我想对一些在y轴上具有相同数量的组,但在每个x轴类别上具有不同数量的"闪避"组的geom_bar图进行刻面_包装.虽然我可以调整图形上的条的宽度,使它们在小平面之间相同,但有没有办法压缩小平面的宽度,以避免组较少的面板中的空白空间?

这就是我的意思.

data(mtcars)
mtcars$car <- rownames(mtcars)

g1 <- gather(mtcars, parameter, reading, c(1,3:7))
g1$gear = factor(g1$gear)
g1$am = factor(g1$am)
g1$cyl = factor(g1$cyl)

g2 <- ggplot(g1, aes(x=am,y=reading, fill=gear)) +
  geom_bar(position = position_dodge2(preserve="single"), stat = "summary")+
  geom_point(position=position_jitterdodge(jitter.width = 0.1, dodge.width = 0.7)) +
  facet_grid(. ~ cyl, scales = "free", space = "free_x")
g2

这就产生了...

enter image description here

基本上,我希望调整右侧第三个面板的宽度,以避免空白空间,并比左侧的两个面板窄.有什么主意吗?

提前谢谢!

推荐答案

首先,简短的回答是...BLUF或更时髦的TL;DR(继续阅读,看看我是如何做到的).

这不是一场完美的比赛.但是,您可以根据需要或需要进行调整,以实现所需的输出.

library(grid)
g3 <- ggplotGrob(g2)
bW <- list() # to collect the "before" width
bX <- list() # to collect the "before" x position start of column
invisible(lapply(1:length(g3), 
                 function(j) {
                   if(length(g3$grobs[[j]]$children) > 5) {
                     i <- g3$grobs[[j]]$children
                     k <- i[grepl("rect", names(i))] %>% 
                       gsub("^.*\\[(.*)\\].", "\\1", .)
                     bW[length(bW) + 1] <<- list(setNames(i[[k]]$width[[1]], k))
                     bX[length(bX) + 1] <<- list(setNames(list(c(i[[k]]$x)), k))
                   }
                 }))
bW <- unlist(bW)  # before widths
bw <- min(bW) * 2 # new width of third facet's columns
g3$grobs[[4]]$children[[names(bW)[3]]]$width[[1]] <- unit(bw, "native")
g3$grobs[[4]]$children[[names(bW)[3]]]$width[[2]] <- unit(bw, "native")    
                  # new x start position to accommodate wider columns
g3$grobs[[4]]$children[[names(bW)[3]]]$x[[1]] <- unit(flatten(bX)[[1]][[1]], "native")
g3$grobs[[4]]$children[[names(bW)[3]]]$x[[2]] <- unit(flatten(bX)[[1]][[3]], "native")
                  # close up unused space
g3$widths[[9]] <- unit(1.1, "null")
grid.draw(g3)

enter image description here

你可以使用grid号图书馆.

首先,为网格库创建一个Grob对象.

library(grid)
library(tidyverse)

g3 <- ggplotGrob(g2)

你将有三个gTree格罗布,因为在这个格罗布中有三个地块.

因为您有列和点,所以我查找了名称包含geom_rectgeom_point的子项的Grobs.一旦我找到了一个,我就计算了子元素的数量,并用这个数字来寻找其他的子元素.面板(背景)和gTree将至少有另一个子项.在本例中,每个GROB地块实际上有6个子代.

所以你知道,这lapply是迭代构建的,在我找到我要找的东西后,我必须与Grob合作来找出如何访问不同的元素.(如果您try 将其应用于不同的数据或不同的图表,了解它是如何构建的可能会很有用.)

此代码创建一列列宽度和列在x轴上的位置,该列需要以指定的单位开始.

bW <- list() # to collect the "before" width
bX <- list() # to collect the "before" x position start of column
invisible(lapply(1:length(g4), 
                 function(j) {
                   if(length(g4[[j]]$children) > 5) { # grobs with more than 5 kids
                     i <- g4[[j]]$children             # extract children
                     k <- i[grepl("rect", names(i))] %>%  # get name
                       gsub("^.*\\[(.*)\\].", "\\1", .)
                     message("results of k ", k, " for ", j)
                     message("width is ")                 
                     message(print(i[[k]]$width))
                     message("x is ")
                     message(print(i[[k]]$x))
                                              # capture before widths and x positions
                     bW[length(bW) + 1] <<- list(setNames(i[[k]]$width[[1]], k))
                     bX[length(bX) + 1] <<- list(setNames(list(c(i[[k]]$x)), k))
                   }
                 }))

对于列宽的"之前"列表,我想要最小值&;2.列的大小是相对于绘图宽度的,因此如果我们要减少未使用的绘图空间,您需要首先使列更宽.我用的是4栏图的列宽乘以2.然而,如果你理解相对性质,这就不是很完美了.(这将"接近"你想要的.)

由于有两列,因此需要为每一列指定带单位的宽度.最重要的是...判断你所期待的.

bW <- unlist(bW)
# geom_rect.rect.11892 geom_rect.rect.11894 geom_rect.rect.11896 
#            0.1840909            0.1840909            0.2045455  

bw <- min(bW) * 2 # new column width, before rendering plot more narrow
# [1] 0.3681818 

g3$grobs[[4]]$children[[names(bW)[3]]]$width       # before
# [1] 0.204545454545455native 0.204545454545455native 
g3$grobs[[4]]$children[[names(bW)[3]]]$width[[1]] <- unit(bw, "native")
g3$grobs[[4]]$children[[names(bW)[3]]]$width[[2]] <- unit(bw, "native")
g3$grobs[[4]]$children[[names(bW)[3]]]$width       # after
# [1] 0.368181818181818native 0.368181818181818native 

如果我们让它这样,柱子就不会再居中了.这就是为什么我们还收集了x个.

到目前为止,情况看起来是这样的.

enter image description here

每列都将有一个值为x.所以实际上,我们想从第一列和第三列开始,从前两个方面开始.

flatten(bX)
# $geom_rect.rect.12931
# [1] 0.07840909 0.28295455 0.53295455 0.73750000
# 
# $geom_rect.rect.12933
# [1] 0.07840909 0.28295455 0.53295455 0.73750000
# 
# $geom_rect.rect.12935
# [1] 0.1704545 0.6250000
#  

g3$grobs[[4]]$children[[names(bW)[3]]]$x       # before
# [1] 0.170454545454545native 0.625native      # use the first plot, 1st column position
g3$grobs[[4]]$children[[names(bW)[3]]]$x[[1]] <- unit(flatten(bX)[[1]][[1]], "native")
                                               # use the first plot, 3rd column position
g3$grobs[[4]]$children[[names(bW)[3]]]$x[[2]] <- unit(flatten(bX)[[1]][[3]], "native")
g3$grobs[[4]]$children[[names(bW)[3]]]$x       # after
# [1] 0.0784090909090909native 0.532954545454545native 

现在,柱子居中.

enter image description here

现在它们变宽了,居中了,我们可以改变这个地块的面积了.记住...这都是相对的大小.

您可以看到这样的宽度:

g3$widths

但是输出是没有意义的!我能说的最好的方法是,你可以通过另外两个电话来理解它所告诉你的东西.当您在第一行代码中调用布局时,您将获得一个值的表,它可能没有太大意义,而从第二个调用中获得的是一个表,表明它是如何分解的.例如,您将在第三个面所在的空间中看到8-9个.在每个面的顶部和底部,您将看到2.2null.这是我们需要改变的尺寸.

g3$layout
gtable::gtable_show_layout(g3)

现在我们知道每个图都是2.2null,我们可以返回到宽度输出,并查找第三次调用2.2null.由于您需要大约一半的空间,对于一半的列,我 Select 使用1.1.

g3$widths[[9]] <- unit(1.1, "null")
g3$widths
#  [1] 5.5points           0cm                 1grobwidth         
#  [4] 0.691935845800368cm 2.2null             5.5points          
#  [7] 2.2null             5.5points           1.1null            
# [10] 0cm                 0cm                 11points           
# [13] 1.36216308454538cm  0points             5.5points           
grid.draw(g3)

enter image description here

R相关问答推荐

如何识别组内的行是否在同一列中具有值?

通过R访问MoveApps API

图片中令人惊讶的行为

了解.groups的目的= dØr的摘要功能中的删除

为什么stat_bin在R中的ggplot中显示错误的数字?

在数据表中呈现数学符号

如何在R中正确对齐放射状图中的文本

根据列表中项目的名称多次合并数据框和列表

如何求解arg必须为NULL或deSolve包的ode函数中的字符向量错误

如果行和大于值,则过滤

ggplot的轴标签保存在officer中时被剪切

如何根据R中其他列的值有条件地从列中提取数据?

未识别时区

使用列/行匹配将两个不同维度的矩阵相加

将饼图插入条形图

可以替代与NSE一起使用的‘any_of()’吗?

基于Key->Value数据帧的基因子集相关性提取

基于数据集属性将科分配给物种

我如何go 掉盒子图底部的数字?

将摘要图添加到facet_WRAP gglot的末尾