【问题标题】:using grid and ggplot2 to create join plots using R使用 grid 和 ggplot2 使用 R 创建连接图
【发布时间】:2010-07-22 03:35:14
【问题描述】:

我想知道我可以做些什么来修复一个图网格。这些图以数组的形式排列,这样一行中的所有图都具有相同的 Y 轴变量,而一列中的所有图都具有相同的 X 轴变量。

当在一个网格中连接在一起时,这会创建一个多图。我禁用了大多数图上的标签,除了外部的,因为内部的具有相同的变量和比例。但是,由于外部图具有标签和轴值,因此它们的大小与其他图不同。

我正在考虑在网格中再添加 2 列和行,用于变量名称和轴范围值...然后仅在相应的网格空间上绘制变量名称,在另一个网格空间上绘制轴值,因此仅绘制剩余空间中的点并获得相等的大小。

编辑 1: 感谢 rcs 将我指向align.plot

编辑 align.plot 以接受空值(当不需要轴中的标题/文本时)

现在我离目标更近了,但由于标签的原因,第一个柱状图的宽度仍然小于其他柱状图。

示例代码:

grid_test <- function ()
{
    dsmall <- diamonds[sample(nrow(diamonds), 100), ] 

    #-----/align function-----
    align.plots <- function(gl, ...){
       # Obtained from http://groups.google.com/group/ggplot2/browse_thread/thread/1b859d6b4b441c90
       # Adopted from http://ggextra.googlecode.com/svn/trunk/R/align.r

       # BUGBUG: Does not align horizontally when one has a title.
       #    There seems to be a spacer used when a title is present.  Include the
       #    size of the spacer.  Not sure how to do this yet.

       stats.row <- vector( "list", gl$nrow )
       stats.col <- vector( "list", gl$ncol )

       lstAll <- list(...)

       dots <- lapply(lstAll, function(.g) ggplotGrob(.g[[1]]))
       #ytitles <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.title.y.text",grep=TRUE), vp=NULL))
       #ylabels <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.text.y.text",grep=TRUE), vp=NULL))
       #xtitles <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.title.x.text",grep=TRUE), vp=NULL))
       #xlabels <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.text.x.text",grep=TRUE), vp=NULL))
       plottitles <- lapply(dots, function(.g) editGrob(getGrob(.g,"plot.title.text",grep=TRUE), vp=NULL))

       xtitles <- lapply(dots, function(.g) if(!is.null(getGrob(.g,"axis.title.x.text",grep=TRUE)))
                         editGrob(getGrob(.g,"axis.title.x.text",grep=TRUE), vp=NULL) else ggplot2:::.zeroGrob)   

       xlabels <- lapply(dots, function(.g) if(!is.null(getGrob(.g,"axis.text.x.text",grep=TRUE)))
                         editGrob(getGrob(.g,"axis.text.x.text",grep=TRUE), vp=NULL) else ggplot2:::.zeroGrob)  

       ytitles <- lapply(dots, function(.g) if(!is.null(getGrob(.g,"axis.title.y.text",grep=TRUE)))
                         editGrob(getGrob(.g,"axis.title.y.text",grep=TRUE), vp=NULL) else ggplot2:::.zeroGrob)   

       ylabels <- lapply(dots, function(.g) if(!is.null(getGrob(.g,"axis.text.y.text",grep=TRUE)))
                         editGrob(getGrob(.g,"axis.text.y.text",grep=TRUE), vp=NULL) else ggplot2:::.zeroGrob)  

       legends <- lapply(dots, function(.g) if(!is.null(.g$children$legends))
                         editGrob(.g$children$legends, vp=NULL) else ggplot2:::.zeroGrob)

       widths.left <- mapply(`+`, e1=lapply(ytitles, grobWidth),
                            e2= lapply(ylabels, grobWidth), SIMPLIFY=FALSE)
       widths.right <- lapply(legends, grobWidth)
       #  heights.top <- lapply(plottitles, grobHeight)
       heights.top <- lapply( plottitles, function(x) unit(0,"cm") )
       heights.bottom <- mapply(`+`, e1=lapply(xtitles, grobHeight), e2= lapply(xlabels, grobHeight), SIMPLIFY=FALSE)

       for ( i in seq_along( lstAll ) ) {
          lstCur <- lstAll[[i]]

          # Left
          valNew <- widths.left[[ i ]]
          valOld <- stats.col[[ min(lstCur[[3]]) ]]$widths.left.max
          if ( is.null( valOld ) ) valOld <- unit( 0, "cm" )
          stats.col[[ min(lstCur[[3]]) ]]$widths.left.max <- max( do.call( unit.c, list(valOld, valNew) ) )

          # Right
          valNew <- widths.right[[ i ]]
          valOld <- stats.col[[ max(lstCur[[3]]) ]]$widths.right.max
          if ( is.null( valOld ) ) valOld <- unit( 0, "cm" )
          stats.col[[ max(lstCur[[3]]) ]]$widths.right.max <- max( do.call( unit.c, list(valOld, valNew) ) )

          # Top
          valNew <- heights.top[[ i ]]
          valOld <- stats.row[[ min(lstCur[[2]]) ]]$heights.top.max
          if ( is.null( valOld ) ) valOld <- unit( 0, "cm" )
          stats.row[[ min(lstCur[[2]]) ]]$heights.top.max <- max( do.call( unit.c, list(valOld, valNew) ) )

          # Bottom
          valNew <- heights.bottom[[ i ]]
          valOld <- stats.row[[ max(lstCur[[2]]) ]]$heights.bottom.max
          if ( is.null( valOld ) ) valOld <- unit( 0, "cm" )
          stats.row[[ max(lstCur[[2]]) ]]$heights.bottom.max <- max( do.call( unit.c, list(valOld, valNew) ) )
       }

       for(i in seq_along(dots)){
          lstCur <- lstAll[[i]]
          nWidthLeftMax <- stats.col[[ min( lstCur[[ 3 ]] ) ]]$widths.left.max
          nWidthRightMax <- stats.col[[ max( lstCur[[ 3 ]] ) ]]$widths.right.max
          nHeightTopMax <- stats.row[[ min( lstCur[[ 2 ]] ) ]]$heights.top.max
          nHeightBottomMax <- stats.row[[ max( lstCur[[ 2 ]] ) ]]$heights.bottom.max
          pushViewport( viewport( layout.pos.row=lstCur[[2]],
                         layout.pos.col=lstCur[[3]], just=c("left","top") ) )
          pushViewport(viewport(
                         x=unit(0, "npc") + nWidthLeftMax - widths.left[[i]],
                         y=unit(0, "npc") + nHeightBottomMax - heights.bottom[[i]],
                         width=unit(1, "npc") - nWidthLeftMax + widths.left[[i]] -
                                               nWidthRightMax + widths.right[[i]],
                         height=unit(1, "npc") - nHeightBottomMax + heights.bottom[[i]] -
                                               nHeightTopMax + heights.top[[i]],
                         just=c("left","bottom")))
          grid.draw(dots[[i]])
          upViewport(2)
       }

    }
    #-----\align function-----

    # edge margins
    margin1 = 0.1
    margin2 = -0.9
    margin3 = 0.5

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = x, y = depth, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank())
    plot1 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin3,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = y, y = depth, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot2 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin2,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = z, y = depth, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot3 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin2,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = x, y = price, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank())
    plot4 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin3,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = y, y = price, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot5 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin2,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = z, y = price, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.text.x = theme_blank(), axis.ticks = theme_blank(), axis.title.x = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot6 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin2,"lines"), unit(margin2,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = x, y = carat, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.ticks = theme_blank())
    plot7 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin3,"lines"), unit(margin3,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = y, y = carat, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.ticks = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot8 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin3,"lines"), unit(margin2,"lines")))

    plot <- ggplot(data = dsmall) + geom_point(mapping = aes(x = z, y = carat, colour = cut)) + opts(legend.position="none")
    plot <- plot + opts(axis.ticks = theme_blank(), axis.text.y = theme_blank(), axis.title.y = theme_blank())
    plot9 <- plot + opts(plot.margin=unit.c(unit(margin1, "lines"), unit(margin1,"lines"), unit(margin3,"lines"), unit(margin2,"lines")))

    grid_layout <- grid.layout( nrow=3, ncol=3, widths=c(2,2,2), heights=c(2,2,2) )
    grid.newpage()
    pushViewport( viewport( layout=grid_layout ) )
    align.plots( grid_layout,
             list( plot1, 1, 1 ),
             list( plot2, 1, 2 ),
             list( plot3, 1, 3 ),
             list( plot4, 2, 1 ),
             list( plot5, 2, 2 ),
             list( plot6, 2, 3 ),
             list( plot7, 3, 1 ),
             list( plot8, 3, 2 ),
             list( plot9, 3, 3 ) )
}

原图:

当前进度图片:

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    这里有一个简单的ggplot2和melt方法:

    diamonds_sample <- diamonds[sample(nrow(diamonds), 100), ]
    
    melted_diamonds <- melt(diamonds_sample, measure.vars=c('x','y','z'),
      variable_name='letter')
    # rename the melt results to avoid confusion with next melt
    # (bug in melt means you can't rename the value during melt)
    names(melted_diamonds)[9] <- 'letter.value'
    
    melted_diamonds <- melt(melted_diamonds, 
      measure.vars=c('depth', 'price', 'carat'), variable_name='variables')
    
    ggplot(melted_diamonds, aes(x=letter.value, y=value, colour=cut)) +
      geom_point() + facet_grid(variables~letter, scale='free')
    

    结果:

    您可以使用所有 ggplot2 选项来让选项卡出现在适当的位置,并删除图例。


    注意:对于这样的图,您想成对比较大量变量,请查看the GGally package。这里有一些文档:http://rgm2.lab.nig.ac.jp/RGM2/func.php?rd_id=GGally:ggpairs

    【讨论】:

      【解决方案2】:

      ggExtra 包中有一个函数align.plots。 从 ggplot2 邮件列表中检查此线程: Aligning time series plots

      aligned plots http://img138.imageshack.us/img138/6786/aligngrid.png

      【讨论】:

      • 谢谢!这很好地对齐了图,但是,一旦我设置了删除某些图上的轴文本/刻度/标题的选项,align.plot 函数就会给我错误: UseMethod("validGrob") 中的错误:'validGrob 没有适用的方法' 应用于“NULL”类的对象我一直在使用 align 函数来查看是否可以相应地对其进行编辑,但运气不佳。
      • 编辑了问题以显示当前进度。我编辑了 align.plot 以接受空值,现在它对齐但没有正确分配第一列。有关代码和图像,请参见上面的问题。
      • ggExtra 不再可用。 gridExtra 确实有 grid.arrange 。
      猜你喜欢
      • 2010-12-16
      • 2019-07-11
      • 1970-01-01
      • 2022-11-25
      • 1970-01-01
      • 2021-08-17
      • 2018-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多