Side-by-side plots with ggplot2

后端 未结 13 2470
轮回少年
轮回少年 2020-11-22 02:06

I would like to place two plots side by side using the ggplot2 package, i.e. do the equivalent of par(mfrow=c(1,2)).

For example, I would like to have t

相关标签:
13条回答
  • 2020-11-22 02:20

    The cowplot package gives you a nice way to do this, in a manner that suits publication.

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

    0 讨论(0)
  • 2020-11-22 02:25

    ggplot2 is based on grid graphics, which provide a different system for arranging plots on a page. The par(mfrow...) command doesn't have a direct equivalent, as grid objects (called grobs) aren't necessarily drawn immediately, but can be stored and manipulated as regular R objects before being converted to a graphical output. This enables greater flexibility than the draw this now model of base graphics, but the strategy is necessarily a little different.

    I wrote grid.arrange() to provide a simple interface as close as possible to par(mfrow). In its simplest form, the code would look like:

    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)
    

    More options are detailed in this vignette.

    One common complaint is that plots aren't necessarily aligned e.g. when they have axis labels of different size, but this is by design: grid.arrange makes no attempt to special-case ggplot2 objects, and treats them equally to other grobs (lattice plots, for instance). It merely places grobs in a rectangular layout.

    For the special case of ggplot2 objects, I wrote another function, ggarrange, with a similar interface, which attempts to align plot panels (including facetted plots) and tries to respect the aspect ratios when defined by the user.

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

    Both functions are compatible with ggsave(). For a general overview of the different options, and some historical context, this vignette offers additional information.

    0 讨论(0)
  • 2020-11-22 02:27

    Yes, methinks you need to arrange your data appropriately. One way would be this:

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

    I am sure there are better tricks in plyr or reshape -- I am still not really up to speed on all these powerful packages by Hadley.

    0 讨论(0)
  • 2020-11-22 02:28

    Using the patchwork package, you can simply use + operator:

    library(ggplot2)
    library(patchwork)
    
    p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
    p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
    
    
    p1 + p2
    

    0 讨论(0)
  • 2020-11-22 02:30

    One downside of the solutions based on grid.arrange is that they make it difficult to label the plots with letters (A, B, etc.), as most journals require.

    I wrote the cowplot package to solve this (and a few other) issues, specifically the function 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")
    

    The object that plot_grid() returns is another ggplot2 object, and you can save it with ggsave() as usual:

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

    Alternatively, you can use the cowplot function save_plot(), which is a thin wrapper around ggsave() that makes it easy to get the correct dimensions for combined plots, e.g.:

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

    (The ncol = 2 argument tells save_plot() that there are two plots side-by-side, and save_plot() makes the saved image twice as wide.)

    For a more in-depth description of how to arrange plots in a grid see this vignette. There is also a vignette explaining how to make plots with a shared legend.

    One frequent point of confusion is that the cowplot package changes the default ggplot2 theme. The package behaves that way because it was originally written for internal lab uses, and we never use the default theme. If this causes problems, you can use one of the following three approaches to work around them:

    1. Set the theme manually for every plot. I think it's good practice to always specify a particular theme for each plot, just like I did with + theme_bw() in the example above. If you specify a particular theme, the default theme doesn't matter.

    2. Revert the default theme back to the ggplot2 default. You can do this with one line of code:

    theme_set(theme_gray())
    

    3. Call cowplot functions without attaching the package. You can also not call library(cowplot) or require(cowplot) and instead call cowplot functions by prepending cowplot::. E.g., the above example using the ggplot2 default theme would become:

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

    Updates:

    • As of cowplot 1.0, the default ggplot2 theme is not changed anymore.
    • As of ggplot2 3.0.0, plots can be labeled directly, see e.g. here.
    0 讨论(0)
  • 2020-11-22 02:31

    Using the reshape package you can do something like this.

    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)
    
    0 讨论(0)
提交回复
热议问题