R ggplot2:如何使用太少的绘图强制增加面数?

R ggplot2:如何使用太少的绘图强制增加面数?,r,ggplot2,facet,R,Ggplot2,Facet,为了绘制每个ggplot图的9个直方图,我使用了以下数据: id variable value 1 Segment III | RIM BlackBerry Pearl | 5.600000 2 Display size | RIM BlackBerry Pearl | 6.500000 3 V

为了绘制每个ggplot图的9个直方图,我使用了以下数据:

                               id               variable      value
1                     Segment III | RIM BlackBerry Pearl | 5.600000
2                    Display size | RIM BlackBerry Pearl | 6.500000
3              Voice/call quality | RIM BlackBerry Pearl | 5.600000
4  Instant messaging availability | RIM BlackBerry Pearl | 7.200000
5                   Media quality | RIM BlackBerry Pearl | 6.100000
6          Ease of use for typing | RIM BlackBerry Pearl | 5.700000
7        Speed in accessing email | RIM BlackBerry Pearl | 6.400000
8                      Segment II | RIM BlackBerry Pearl | 5.545455
9                 Value for money | RIM BlackBerry Pearl | 6.000000
10                    Segment III |       Palm Treo 700p | 4.320000
11                   Display size |       Palm Treo 700p | 6.500000
12             Voice/call quality |       Palm Treo 700p | 8.000000
13 Instant messaging availability |       Palm Treo 700p | 5.100000
14                  Media quality |       Palm Treo 700p | 7.000000
15         Ease of use for typing |       Palm Treo 700p | 6.200000
16       Speed in accessing email |       Palm Treo 700p | 6.500000
17                     Segment II |       Palm Treo 700p | 4.454545
18                Value for money |       Palm Treo 700p | 5.400000
19                    Segment III |           Motorola Q | 4.680000
20                   Display size |           Motorola Q | 7.400000
21             Voice/call quality |           Motorola Q | 4.800000
22 Instant messaging availability |           Motorola Q | 5.300000
23                  Media quality |           Motorola Q | 6.900000
24         Ease of use for typing |           Motorola Q | 7.400000
25       Speed in accessing email |           Motorola Q | 8.000000
26                     Segment II |           Motorola Q | 3.121212
27                Value for money |           Motorola Q | 4.200000
28                    Segment III |           Nokia 9300 | 4.360000
29                   Display size |           Nokia 9300 | 6.400000
30             Voice/call quality |           Nokia 9300 | 7.800000
31 Instant messaging availability |           Nokia 9300 | 6.700000
32                  Media quality |           Nokia 9300 | 5.900000
33         Ease of use for typing |           Nokia 9300 | 4.500000
34       Speed in accessing email |           Nokia 9300 | 6.300000
35                     Segment II |           Nokia 9300 | 7.181818
36                Value for money |           Nokia 9300 | 4.600000
37                    Segment III |  Sony Ericsson M600i | 4.360000
38                   Display size |  Sony Ericsson M600i | 7.300000
39             Voice/call quality |  Sony Ericsson M600i | 8.000000
40 Instant messaging availability |  Sony Ericsson M600i | 1.500000
41                  Media quality |  Sony Ericsson M600i | 7.800000
42         Ease of use for typing |  Sony Ericsson M600i | 5.000000
43       Speed in accessing email |  Sony Ericsson M600i | 8.100000
44                     Segment II |  Sony Ericsson M600i | 3.606061
45                Value for money |  Sony Ericsson M600i | 4.000000
46                    Segment III |            Sidekick3 | 7.040000
47                   Display size |            Sidekick3 | 7.200000
48             Voice/call quality |            Sidekick3 | 6.300000
49 Instant messaging availability |            Sidekick3 | 7.200000
50                  Media quality |            Sidekick3 | 6.400000
51         Ease of use for typing |            Sidekick3 | 6.800000
52       Speed in accessing email |            Sidekick3 | 6.200000
53                     Segment II |            Sidekick3 | 3.424242
54                Value for money |            Sidekick3 | 5.300000
然后我使用了以下代码:

ggplot(data = data_sub, aes(x = variable, y = value)) +
  geom_bar(stat = "identity") +
  facet_wrap(~id, ncol = 3) +
  coord_flip() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.grid   = element_blank(),
        legend.position = "none")
得到:

我的问题:

当我有较少的图形时,例如只有一个图形时,我希望保持这种格式。然而,我只得到一个像下面这样的大图(不介意图例)。

我怎样才能得到像下面这样的东西? 试试这个

d <- subset(mtcars, cyl==4)
d$cyl <- factor(d$cyl, levels=unique(mtcars$cyl))
ggplot(d, aes(x=am, y=wt) ) +
  geom_point() +
  facet_grid(.~cyl, drop = FALSE)

d一种方法是为每个非空因子水平创建一个绘图,并为每个空因子水平创建一个空白占位符:

首先,使用内置的
mtcars
数据框,我们将刻面变量设置为9个级别的因子,但任何数据仅5个级别:

library(ggplot2)
library(grid)
library(gridExtra)

d = mtcars
set.seed(4193)
d$cyl = sample(1:9, nrow(d), replace=TRUE)
d$cyl <- factor(d$cyl, levels=sort(unique(d$cyl)))
d <- subset(d, cyl %in% c(1,5,7:9))

# Identify factor levels without any data
blanks = which(table(d$cyl)==0)

# Initialize a list
pl = list()
现在,布置绘图并在其周围添加边框:

do.call(grid.arrange, c(pl, ncol=3))
grid.rect(.5, .5, gp=gpar(lwd=2, fill=NA, col="black"))

更新:我想添加到我的答案中的一个功能是删除不在最左边列或最下面一行的绘图的轴标签(更像OP中的格式)。下面是我不太成功的尝试

从某些绘图中删除轴记号和/或标签时出现的问题是,在不同的绘图中,绘图区域的大小不同。原因是所有打印占用相同的物理区域,但带有轴标签的打印使用部分该区域作为轴标签,使其打印区域相对于没有轴标签的打印更小

我曾希望可以使用
cowplot
包(由@ClausWilke编写)中的
plot\u-grid
解决这个问题,但是
plot\u-grid
不适用于
nullGrob
s。然后@baptiste为这个问题添加了另一个答案,他已经删除了这个答案,但对于至少拥有10000名声誉的SO用户来说,这个答案仍然可见。这个答案让我意识到了他的
egg
软件包和
set_panel_size
功能,用于在不同的绘图中设置一个通用的面板大小

下面是我尝试使用
set\u panel\u size
解决绘图区域问题的方法。这并不是很成功,在展示代码和情节之后,我将更详细地讨论这一点

# devtools::install_github("baptiste/egg")
library(egg)

# Fake data for making a barplot. Once again we have 9 facet levels, 
# but with data for only 5 of the levels.
set.seed(4193)
d = data.frame(facet=rep(LETTERS[1:9],each=100), 
               group=sample(paste("Group",1:5),900,replace=TRUE))
d <- subset(d, facet %in% LETTERS[c(1,5,7:9)])

# Identify factor levels without any data
blanks = which(table(d$facet)==0)

# Initialize a list
pl = list()

for (i in 1:length(levels(d$facet))) {

  if(i %in% blanks) {

    pl[[i]] = nullGrob()

  } else {

    # Create the plot, including a common y-range across all plots
    # (though this becomes the x-range due to coord_flip)
    pl[[i]] = ggplot(d[d$facet %in% levels(d$facet)[i], ], aes(x=group) ) +
      geom_bar() +
      facet_grid(. ~ facet) +
      coord_flip() +
      labs(x="", y="") +
      scale_y_continuous(limits=c(0, max(table(d$group, d$facet)))) 

    # If the panel isn't on the left edge, remove y-axis labels
    if(!(i %in% seq(1,9,3))) {
      pl[[i]] = pl[[i]] + theme(axis.text.y=element_blank(),
                                axis.ticks.y=element_blank())
    }

    # If the panel isn't on the bottom, remove x-axis labels
    if(i %in% 1:6) {
      pl[[i]] = pl[[i]] + theme(axis.text.x=element_blank(),
                                axis.ticks.x=element_blank())
    }
  }

  # If the panel is a plot (rather than a nullGrob), 
  # remove margins and set to common panel size
  if(any(class(pl[[i]]) %in% c("ggplot","gtable"))) {
    pl[[i]] = pl[[i]] + theme(plot.margin=unit(rep(-1,4), "lines"))
    pl[[i]] = set_panel_size(pl[[i]], width=unit(4,"cm"), height=unit(3,"cm"))
  }

}
正如您在下面的图中所看到的,即使这些图都具有相同的面板大小,它们之间的边距也不是恒定的,这可能是由于
网格的方式。排列
处理空GROB的间距,这取决于哪些位置具有实际图。另外,由于
set\u panel\u size
设置了绝对大小,因此我必须手动调整最终绘图的大小,以使面板尽可能靠近在一起,同时避免重叠。我希望SO的一位常驻
grid
专家来拜访,并提出一种更有效的方法

(还请注意,使用这种方法,您可能会在给定的行或列中没有带标签的绘图。在下面的示例中,绘图“E”没有y轴标签,而绘图“D”丢失,因此您必须查看其他行中的标签。如果仅绘图“B”、“C”、“E”和“F”如果存在,布局中将不会有任何带标签的绘图。我不知道OP希望如何处理这种情况(一种选择是添加逻辑,如果给定行或列中没有“外部”绘图,则在“内部”绘图上保留标签),但我认为值得指出。)


一种可能的解决方案是生成GGPlot列表,并用虚拟占位符替换其中一些

d <- data.frame(x=rnorm(90), y=rnorm(90), 
                f1 = gl(3, 30) , f2 = rep(gl(3, 10), 3) )

p <- ggplot(d, aes(x, y)) + 
  geom_point()

# if you want to keep the facet labels
# p <- p + facet_grid(f1~f2)

library(plyr)
pl <- dlply(d, .(f1, f2), "%+%", e1=p, .drop = FALSE)

.dummy_plot <- ggplot() + theme_void()
pl[c(3,4,7)] <- rep(list(.dummy_plot), 3, simplify=FALSE)


# devtools::install_github("baptiste/egg)
library(grid)
grid.newpage()
grid.draw(egg::ggarrange(plots=pl))

# alternatively
# library(cowplot)
# plot_grid(plotlist = pl)

d我会在
facet\u wrap
中使用
drop=FALSE
来防止删除未使用的因子级别,或者使用
gridExtra::grid.arrange
cowplot
包手动创建一个网格。也许对于我刚才遇到的一个类似问题,会给你一些想法。
drop=FALSE
仍然会导致“空”正在绘制面,但其中没有任何点。如果有任何值可以绘制的话,OP似乎希望在刻面所在的位置留有空白。可能是一个
网格。安排
布局时,空的GROB代表空的刻面级别?人们可能会从GTTable中删除GROB,但不清楚轴会发生什么。在使用两种解决方案后,我感觉您的解决方案可能是正确的。原因是它将作为
plot对象
而不是
tableGrob
保存,后者更难操作,例如保存整个元素。此外,它需要更少的编码。我现在不能接受它的唯一原因是我不知道如何用空的level隐藏空的图。如果我弄明白了,我会让你不断更新。理想的解决方案是能够为每个方面指定一个特定的主题。这背后的原因是我喜欢操纵它作为GGPGOT对象。你的问题并不表明在中间的面板轴应该发生什么。这真是棒极了,它像一个魅力!然而,我一直在思考如何将输出转换为一个图像,理想的情况是能够使用
ggsave
。有什么想法吗?在这种情况下,我不知道如何使用
ggsave
,但是你可以这样做,例如
pdf(“test.pdf”,6,6)
do.call
行之前,然后在
grid.rect
行之后使用
dev.off()
ggsave
在最近的ggplot2中没有问题,你可以使用它(不是grid.rect,但这可能不是必需的)。
set\u panel\u size
本身并不能确保面板对齐(轴可以跨行/列移动,至少在一般情况下——这里不清楚它们应该在哪里)。另外,请注意,您不需要
do.call
使用最近的
grid.arrange(grobs=list())
do.call(grid.arrange, c(pl, ncol=3))
grid.rect(.5, .5, gp=gpar(lwd=2, fill=NA, col="black"))
d <- data.frame(x=rnorm(90), y=rnorm(90), 
                f1 = gl(3, 30) , f2 = rep(gl(3, 10), 3) )

p <- ggplot(d, aes(x, y)) + 
  geom_point()

# if you want to keep the facet labels
# p <- p + facet_grid(f1~f2)

library(plyr)
pl <- dlply(d, .(f1, f2), "%+%", e1=p, .drop = FALSE)

.dummy_plot <- ggplot() + theme_void()
pl[c(3,4,7)] <- rep(list(.dummy_plot), 3, simplify=FALSE)


# devtools::install_github("baptiste/egg)
library(grid)
grid.newpage()
grid.draw(egg::ggarrange(plots=pl))

# alternatively
# library(cowplot)
# plot_grid(plotlist = pl)