Вопрос

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

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

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

Нужно ли мне помещать их в один и тот же data.frame?

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.См. отвечать автор @claus-wilke ниже и эта виньетка для эквивалентного подхода;но функция позволяет более точно контролировать расположение и размер графика в зависимости от эта виньетка.

Другие советы

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

Я написал коровник пакет для решения этой (и некоторых других) проблем, в частности, функции 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")

enter image description here

Объект, который plot_grid() return — это еще один объект 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")

enter image description here

Обновления:

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

Вы можете использовать следующее multiplot функция от Поваренная книга Уинстона Чанга 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 ))
    }

}

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

# 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

patchwork

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

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 есть трюки получше - я все еще не совсем в курсе всех этих мощных пакетов от Hadley.

Используя пакет 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)

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


Стивен Тернер разместил arrange() функция включена Как сделать генетику блог (инструкции по применению см. в посте)

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...) команда не имеет прямого эквивалента, так как объекты сетки (называемые гробс) не обязательно рисуются сразу, но могут храниться и обрабатываться как обычные R-объекты перед преобразованием в графический вывод.Это обеспечивает большую гибкость, чем нарисуй это сейчас модель базовой графики, но стратегия обязательно немного отличается.

Я написал 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)

enter image description here

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

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

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

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

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

А также есть многопанельный пакет фигур это стоит упомянуть.См. также это отвечать.

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

Создано 6 июля 2018 г. репрекс-пакет (v0.2.0.9000).

С использованием 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

enter image description here

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

Код ниже показывает, как это сделать, используя упомянутый выше «multiplot()», источник которого находится здесь: 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)
}

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

dt = ggplot2::diamonds
plotAllCounts(dt)

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

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

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

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")

enter image description here

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top