Бок о бок участки с ggplot2

Я хотел бы разместить два графика бок о бок, используя пакет ggplot2 , т. Е. Сделать эквивалент par(mfrow=c(1,2)) .

Например, я хотел бы, чтобы следующие два графика отображались бок о бок с одинаковым масштабом.

 x <- rnorm(100) eps <- rnorm(100,0,.2) qplot(x,3*x+eps) qplot(x,2*x+eps) 

Нужно ли помещать их в один и тот же файл данных?

 qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth() 

Любые ggplots бок о бок (или n графиков на сетке)

Функция grid.arrange() в пакете gridExtra объединяет несколько графиков; так вы ставите две бок о бок.

 require(gridExtra) plot1 <- qplot(1) plot2 <- qplot(1) grid.arrange(plot1, plot2, ncol=2) 

Это полезно, когда два графика не основаны на одних и тех же данных, например, если вы хотите построить разные переменные без использования функции reshape ().

Это будет отображать результат как побочный эффект. Чтобы напечатать побочный эффект в файле, укажите драйвер устройства (например, pdf , png и т. Д.), Например

 pdf("foo.pdf") grid.arrange(plot1, plot2) dev.off() 

или, используйте arrangeGrob() в сочетании с ggsave() ,

 ggsave("foo.pdf", arrangeGrob(plot1, plot2)) 

Это эквивалентно созданию двух разных графиков с использованием par(mfrow = c(1,2)) . Это не только экономит время на сбор данных, это необходимо, если вам нужны два разных графика.


Приложение: Использование граней

Границы полезны для создания похожих сюжетов для разных групп. Это указано ниже во многих ответах ниже, но я хочу подчеркнуть этот подход примерами, эквивалентными приведенным выше графикам.

 mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1)) qplot(data = mydata, x = myX, facets = ~myGroup) ggplot(data = mydata) + geom_bar(aes(myX)) + facet_wrap(~myGroup) 

Обновить

функция plot_grid в cowplot стоит проверить как альтернативу grid.arrange . См. Ответ by @ claus-wilke ниже и эту виньетку для эквивалентного подхода; но функция позволяет более тонкие средства управления расположением и размером участка на основе этой виньетки .

Один недостаток решений, основанных на grid.arrange заключается в том, что они затрудняют маркировку графиков буквами (A, B и т. Д.), Как того требует большинство журналов.

Я написал пакет cowplot для решения этой (и нескольких других) проблем, в частности функции plot_grid() :

 library(cowplot) iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) + geom_boxplot() + theme_bw() iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) + geom_density(alpha = 0.7) + theme_bw() + theme(legend.position = c(0.8, 0.8)) plot_grid(iris1, iris2, labels = "AUTO") 

введите описание изображения здесь

Объект, plot_grid() возвращает plot_grid() является другим объектом ggplot2, и вы можете сохранить его с помощью ggsave() как обычно:

 p <- plot_grid(iris1, iris2, labels = "AUTO") ggsave("plot.pdf", p) 

Кроме того, вы можете использовать функцию save_plot() , которая представляет собой тонкую оболочку вокруг ggsave() которая позволяет легко получить правильные размеры для комбинированных графиков, например:

 p <- plot_grid(iris1, iris2, labels = "AUTO") save_plot("plot.pdf", p, ncol = 2) 

( ncol = 2 сообщает save_plot() что два участка бок о бок, а save_plot() делает сохраненное изображение вдвое большим.)

Для более подробного описания того, как расположить графики в сетке, см. Эту виньетку. Существует также виньетка, объясняющая, как делать сюжеты с общей легендой.

Одна из частых путаниц заключается в том, что пакет cowplot изменяет тему ggplot2 по умолчанию. Пакет ведет себя так, потому что он был первоначально написан для внутренних лабораторных целей, и мы никогда не используем тему по умолчанию. Если это вызывает проблемы, вы можете использовать один из следующих трех подходов для их работы:

1. Задайте тему вручную для каждого сюжета. Я думаю, что правильная практика всегда указывать конкретную тему для каждого сюжета, так же, как я сделал с + theme_bw() в приведенном выше примере. Если вы укажете конкретную тему, тема по умолчанию не имеет значения.

2. Верните тему по умолчанию обратно в значение ggplot2 по умолчанию. Вы можете сделать это с помощью одной строки кода:

 theme_set(theme_gray()) 

3. Позвоните в функции cowplot без установки пакета. Вы также не можете вызывать library(cowplot) или require(cowplot) и вместо этого вызывать функции cowplot:: . Например, приведенный выше пример с использованием темы ggplot2 по умолчанию станет следующим:

 ## Commented out, we don't call this # library(cowplot) iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) + geom_boxplot() iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) + geom_density(alpha = 0.7) + theme(legend.position = c(0.8, 0.8)) cowplot::plot_grid(iris1, iris2, labels = "AUTO") 

введите описание изображения здесь

Обновление: Начиная с ggplot2 3.0.0, графики могут быть помечены напрямую, см. Здесь.

Вы можете использовать следующую функцию multiplot из поваренной книги Winston Chang’s R

 multiplot(plot1, plot2, cols=2) 

 multiplot <- function(..., plotlist=NULL, cols) { require(grid) # Make a list from the ... arguments and plotlist plots <- c(list(...), plotlist) numPlots = length(plots) # Make the panel plotCols = cols # Number of columns of plots plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols # Set up the page grid.newpage() pushViewport(viewport(layout = grid.layout(plotRows, plotCols))) vplayout <- function(x, y) viewport(layout.pos.row = x, layout.pos.col = y) # Make each plot, in the correct location for (i in 1:numPlots) { curRow = ceiling(i/plotCols) curCol = (i-1) %% plotCols + 1 print(plots[[i]], vp = vplayout(curRow, curCol )) } } 

Да, важно, чтобы вы правильно упорядочили свои данные. Один из способов:

 X <- data.frame(x=rep(x,2), y=c(3*x+eps, 2*x+eps), case=rep(c("first","second"), each=100)) qplot(x, y, data=X, facets = . ~ case) + geom_smooth() 

Я уверен, что есть лучшие трюки в plyr или reshape - я все еще не совсем готов к ускорению во всех этих мощных пакетах Хэдли.

Используя пакет reshape, вы можете сделать что-то вроде этого.

 library(ggplot2) wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2)) wide$first <- with(wide, 3 * x + eps) wide$second <- with(wide, 2 * x + eps) long <- melt(wide, id.vars = c("x", "eps")) ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable) 

Используя пакет исправлений , вы можете просто использовать оператор + :

 # install.packages("devtools") devtools::install_github("thomasp85/patchwork") library(ggplot2) p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp)) p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear)) library(patchwork) p1 + p2 

пэчворк

Обновление: этот ответ очень старый. gridExtra::grid.arrange() теперь рекомендуется. Я оставляю это здесь, если это может быть полезно.


Стивен Тернер опубликовал функцию arr () в разделе « Получение Genetics Done» (см. Сообщение для инструкций по применению)

 vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y) arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) { dots <- list(...) n <- length(dots) if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)} if(is.null(nrow)) { nrow = ceiling(n/ncol)} if(is.null(ncol)) { ncol = ceiling(n/nrow)} ## NOTE see n2mfrow in grDevices for possible alternative grid.newpage() pushViewport(viewport(layout=grid.layout(nrow,ncol) ) ) ii.p <- 1 for(ii.row in seq(1, nrow)){ ii.table.row <- ii.row if(as.table) {ii.table.row <- nrow - ii.table.row + 1} for(ii.col in seq(1, ncol)){ ii.table <- ii.p if(ii.p > n) break print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col)) ii.p <- ii.p + 1 } } } 

ggplot2 основан на сетке графики, которые предоставляют различные системы для размещения графиков на странице. Команда par(mfrow...) не имеет прямого эквивалента, поскольку объекты сетки (называемые grobs ) не обязательно выводятся немедленно, но могут быть сохранены и обработаны как обычные объекты R перед преобразованием в графический вывод. Это обеспечивает большую гибкость, чем рисование этой модели базовой графики, но страtagsя обязательно немного отличается.

Я написал grid.arrange() чтобы обеспечить простой интерфейс как можно ближе к par(mfrow) . В простейшей форме код будет выглядеть так:

 library(ggplot2) x <- rnorm(100) eps <- rnorm(100,0,.2) p1 <- qplot(x,3*x+eps) p2 <- qplot(x,2*x+eps) library(gridExtra) grid.arrange(p1, p2, ncol = 2) 

введите описание изображения здесь

Дополнительные параметры подробно описаны в этой виньетке .

Одна общая жалоба заключается в том, что графики не обязательно выравниваются, например, когда у них есть метки осей разного размера, но это по дизайну: grid.arrange делает попыток объектов специального ggplot2 и рассматривает их одинаково для других грызунов (решетчатые графики , например). Он просто помещает глыбы в прямоугольную компоновку.

Для специального случая объектов ggplot2 я написал еще одну функцию ggarrange с аналогичным интерфейсом, которая пытается выровнять панели сюжетов (включая фасетные графики) и пытается ggarrange пропорции, определенные пользователем.

 library(egg) ggarrange(p1, p2, ncol = 2) 

Обе функции совместимы с ggsave() . Для общего обзора различных вариантов и некоторого исторического контекста эта виньетка предлагает дополнительную информацию .

Использование tidyverse

 x <- rnorm(100) eps <- rnorm(100,0,.2) df <- data.frame(x, eps) %>% mutate(p1 = 3*x+eps, p2 = 2*x+eps) %>% tidyr::gather("plot", "value", 3:4) %>% ggplot(aes(x = x , y = value))+ geom_point()+geom_smooth()+facet_wrap(~plot, ncol =2) df 

введите описание изображения здесь

Вышеупомянутые решения могут быть неэффективными, если вы хотите построить несколько графиков ggplot с использованием цикла (например, как здесь задано: Создание нескольких графиков в ggplot с разными значениями оси Y с использованием цикла ), что является желательным шагом при анализе неизвестного ( или больших) наборов данных (например, когда вы хотите построить график всех переменных в наборе данных).

В приведенном ниже коде показано, как это сделать, используя вышеупомянутый «multipot ()», источник которого находится здесь: http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2) :

 plotAllCounts <- function (dt){ plots <- list(); for(i in 1:ncol(dt)) { strX = names(dt)[i] print(sprintf("%i: strX = %s", i, strX)) plots[[i]] <- ggplot(dt) + xlab(strX) + geom_point(aes_string(strX),stat="count") } columnsToPlot <- floor(sqrt(ncol(dt))) multiplot(plotlist = plots, cols = columnsToPlot) } 

Теперь запустите функцию - чтобы получить Counts для всех переменных, напечатанных с помощью ggplot на одной странице

 dt = ggplot2::diamonds plotAllCounts(dt) 

Следует отметить, что:
используя aes(get(strX)) , который вы обычно используете в циклах при работе с ggplot , в приведенном выше коде вместо aes_string(strX) НЕ будет рисовать нужные графики. Вместо этого он будет строить последний график много раз. Я не понял, почему, возможно, придется делать aes а aes_string в ggplot .

В противном случае, надеюсь, вы найдете эту функцию полезной.

Стоит упомянуть также пакет multipanelfigure . См. Также этот ответ .

 library(ggplot2) theme_set(theme_bw()) q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp)) q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear)) q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec)) q4 <- ggplot(mtcars) + geom_bar(aes(carb)) library(magrittr) library(multipanelfigure) figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none") # show the layout figure1 

 figure1 %<>% fill_panel(q1, column = 1, row = 1) %<>% fill_panel(q2, column = 2, row = 1) %<>% fill_panel(q3, column = 1, row = 2) %<>% fill_panel(q4, column = 2, row = 2) figure1 

 # complex layout figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman") figure2 

 figure2 %<>% fill_panel(q1, column = 1:2, row = 1) %<>% fill_panel(q2, column = 3, row = 1) %<>% fill_panel(q3, column = 1, row = 2) %<>% fill_panel(q4, column = 2:3, row = 2:3) figure2 

Создано в 2018-07-06 пакетом reprex (v0.2.0.9000).

Пакет cowplot дает вам хороший способ сделать это таким образом, который подходит для публикации.

 x <- rnorm(100) eps <- rnorm(100,0,.2) A = qplot(x,3*x+eps, geom = c("point", "smooth"))+theme_gray() B = qplot(x,2*x+eps, geom = c("point", "smooth"))+theme_gray() cowplot::plot_grid(A, B, labels = c("A", "B"), align = "v") 

введите описание изображения здесь

Давайте будем гением компьютера.