ggplot2: multiple plots in a single row with a single legend

前端 未结 2 2014
盖世英雄少女心
盖世英雄少女心 2021-01-04 20:46

I want a combined plot of two plots + their legend like this:

library(ggplot2) 
library(grid)
library(gridExtra)
dsamp <- diamonds[sample(nrow(diamonds),          


        
相关标签:
2条回答
  • 2021-01-04 20:50

    Why don't you use facetting?

    library(reshape2)
    dmelt <- melt(dsamp, id.vars = c("price", "clarity"), measure.vars = c("carat", "depth"))
    ggplot(dmelt, aes(x = price, y = value, color = clarity)) +
      geom_point() +
      facet_wrap(~ variable, scales = "free")
    

    0 讨论(0)
  • 2021-01-04 21:12

    I usually use facet_wrap or facet_grid as @Roland suggested.

    A while ago I had to use the grid.arrange (I wanted the labels on the y-axis to be colored in an specific order) and this is the function I came up with:

    ggplot_shared_info <- function(...) {
      plots <- list(...)
      g <- ggplotGrob(plots[[1]])$grobs
      legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
      title <- g[[grep("plot.title", sapply(g, function(x) x$name))]]
      xaxis <- g[[grep("axis.title.x", sapply(g, function(x) x$name))]]
      yaxis <- g[[grep("axis.title.y", sapply(g, function(x) x$name))]]
    
      lwidth <- sum(legend$width)
      theight <- sum(title$height)
      xheight <- sum(xaxis$height)
      ywidth <- sum(yaxis$width)
    
      grid.arrange(
         title,
         arrangeGrob(
           yaxis,
           do.call(arrangeGrob, c(lapply(plots, function(x)
             x + theme(legend.position="none", 
                       plot.title = element_blank(),
                       axis.title = element_blank())), 
             nrow = 1)),
           legend,
           nrow = 1,
           widths = grid::unit.c(ywidth, unit(1, "npc") - ywidth - lwidth, lwidth)
         ),
         xaxis, 
         heights = grid::unit.c(theight, unit(1, "npc") - theight - xheight, xheight),
         ncol = 1
      )
    }
    

    Edit: now user can determine which of the listed plot elements should be 'joined'.

    ggplot_shared_info <- function(..., elements = c('legend', 'title', 'yaxis', 'xaxis')) {
      plots <- list(...)
      g <- ggplotGrob(plots[[1]])$grobs
    
      legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
      lwidth <- sum(legend$width)
      title <- g[[grep("plot.title", sapply(g, function(x) x$name))]]
      theight <- sum(title$height)  
      xaxis <- g[[grep("axis.title.x", sapply(g, function(x) x$name))]]
      xheight <- sum(xaxis$height)
      yaxis <- g[[grep("axis.title.y", sapply(g, function(x) x$name))]]
      ywidth <- sum(yaxis$width)
    
      plots <- lapply(plots, function(x, elements = elements){
        if('legend' %in% elements) x <- x + theme(legend.position="none")
        if('title' %in% elements) x <- x + theme(plot.title = element_blank())
        if('xaxis' %in% elements) x <- x + theme(axis.title.x = element_blank())
        if('yaxis' %in% elements) x <- x + theme(axis.title.y = element_blank())
        x
      }, elements = elements)
      plots <- do.call(arrangeGrob, c(plots, nrow = 1))
    
      if('legend' %in% elements) 
        plots <- arrangeGrob(plots, legend, nrow = 1, widths = grid::unit.c(unit(1, "npc") - lwidth, lwidth))
      if('yaxis' %in% elements)
        plots <- arrangeGrob(yaxis, plots, nrow = 1, widths = grid::unit.c(ywidth, unit(1, "npc") - ywidth))
      if('title' %in% elements) 
        plots <- arrangeGrob(title, plots, ncol = 1, heights = grid::unit.c(theight, unit(1, "npc") - theight))
      if('xaxis' %in% elements)     
        plots <- arrangeGrob(plots, xaxis, ncol = 1, heights = grid::unit.c(unit(1, "npc") - xheight, xheight))
      grid.arrange(plots)
    }
    
    0 讨论(0)
提交回复
热议问题