ggplot: 如何为一个图表网格添加公共的x和y标签

6

使用diamonds数据,我想绘制cut的4个等级(FairGoodVery GoodPremium)中caratprice之间的关系。

为了控制轴上的间隔而不是使用facet_wrap()函数,我创建了四个图来控制轴上的间隔。

library(ggplot2)
library(egg)
library(grid)
f1 <- 
ggplot(diamonds[diamonds$cut=="Fair",], aes(carat, price))+
  geom_point()+
  facet_wrap(~cut, ncol =2)+
  scale_x_continuous(limits = c(0,4), breaks=c(0,  1, 2, 3, 4))+
  scale_y_continuous(limits = c(0,10000), breaks=c(0,  2500, 5000, 7500, 10000))+
  labs(x=expression(" "),
       y=expression(" "))


f2 <- 
ggplot(diamonds[diamonds$cut=="Good",], aes(carat, price))+
  geom_point()+
  facet_wrap(~cut, ncol =2)+
  scale_y_continuous(limits = c(0,5000), breaks=c(0,  1000, 2000, 3000, 4000, 5000))+
  labs(x=expression(" "),
       y=expression(" "))


f3 <- 
  ggplot(diamonds[diamonds$cut=="Very Good",], aes(carat, price))+
  geom_point()+
  facet_wrap(~cut, ncol =2)+
  scale_x_continuous(limits = c(0,1), breaks=c(0, 0.2,  0.4, 0.6, 0.8, 1))+
  scale_y_continuous(limits = c(0,1000), breaks=c(0,  200, 400, 600, 800, 1000))+
  labs(x=expression(" "),
       y=expression(" "))

f4 <- 
  ggplot(diamonds[diamonds$cut=="Premium",], aes(carat, price))+
  geom_point()+
  facet_wrap(~cut, ncol =2)+
  scale_x_continuous(limits = c(0,1.5), breaks=c(0, 0.2,  0.4, 0.6, 0.8, 1, 1.2, 1.4))+
  scale_y_continuous(limits = c(0, 3000), breaks=c(0,  500, 1000, 1500, 2000, 2500, 3000))+
  labs(x=expression(" "),
       y=expression(" "))

fin_fig <- ggarrange(f1, f2, f3, f4, ncol =2)
fin_fig   

结果

每个图都有一系列不同的y值。

enter image description here

问题

在所有方面,x和y轴都是相同的。唯一的区别是最小值、最大值和间断点。我想在这个图形中添加x和y标签。我可以在任何Word文档或图像编辑器中手动完成此操作。是否有任何直接在R中完成此操作的方法?


1
请查看 grid::textGrobggplot2::annotation_custom - shayaa
4
你可以使用 gridExtra 包,其中包含 leftbottom 参数。: p <- ggplot() ; g <- gridExtra::arrangeGrob(p,p,p,p,ncol=2, bottom=grid::textGrob("底部标签"), left=grid::textGrob("左侧标签", rot=90)) ; grid::grid.newpage() ; grid::grid.draw(g) - user20650
1个回答

7
除了使用@user20650建议的gridExtra包中的函数外,您还可以通过按照cut级别拆分diamonds数据框,并使用mapply来减少代码量创建图形。
下面的答案还包括评论中后续问题的解决方案。我们展示如何布置四个图形,添加单个x和y标签(包括使它们加粗并控制它们的颜色和大小),这些标签适用于所有图形,并获取单个图例而不是每个图形一个图例。
library(ggplot2)
library(gridExtra)
library(grid)
library(scales)

删除 cut 列等于"Ideal" 的行:

dat = diamonds[diamonds$cut != "Ideal",]
dat$cut = droplevels(dat$cut)

创建四个图表,每个图表对应剩余的cut级别,并将其存储在一个列表中。我们使用mapply(而不是lapply),以便为每个cut级别提供单独的数据帧和自定义ymax值向量,以分别设置y轴上的最高值。我们还添加color=clarity以创建颜色图例:

pl = mapply(FUN = function(df, ymax) {
  ggplot(df, aes(carat, price, color=clarity))+
    geom_point()+
    facet_wrap(~cut, ncol=2)+
    scale_x_continuous(limits = c(0,4), breaks=0:4)+
    scale_y_continuous(limits = c(0, ymax), labels=dollar_format()) +
    labs(x=expression(" "),
         y=expression(" "))
}, df=split(dat, dat$cut), ymax=c(1e4,5e3,1e3,3e3), SIMPLIFY=FALSE)

好的,我们已经有了四个图表,但每个图表都有自己的图例。因此现在我们希望安排只有一个总体图例。我们通过提取一个图例作为单独的grob(图形对象),然后从四个图表中删除图例来实现这一点。

使用一个小助手函数将图例提取为单独的grob:

# Function to extract legend
# https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend) }

# Extract legend as a grob
leg = g_legend(pl[[1]])

现在我们需要将四个图形排列成2x2的网格,然后将图例放置在此网格的右侧。我们使用arrangeGrob来布局这些图形(请注意,在呈现每个图形之前,我们使用lapply删除了每个图形中的图例)。这基本上与我们在先前版本的答案中使用grid.arrange所做的相同,只是arrangeGrob创建2x2 plot网格对象而不绘制它。然后,我们通过将整个东西包装在grid.arrange内,在2x2 plot网格旁边布置图例。widths=c(9,1)将水平空间的90%分配给2x2图形网格,10%分配给图例。哇!
grid.arrange(
  arrangeGrob(grobs=lapply(pl, function(p) p + guides(colour=FALSE)), ncol=2, 
              bottom=textGrob("Carat", gp=gpar(fontface="bold", col="red", fontsize=15)), 
              left=textGrob("Price", gp=gpar(fontface="bold", col="blue", fontsize=15), rot=90)),
  leg, 
  widths=c(9,1)
)

enter image description here


感谢您的时间和帮助。请查看更新以了解我无法使用“更少的代码”的原因。我不得不制作四个不同的图,因为它们都具有不同范围的y和x值,但仍然具有相同的单位。 - shiny
1
请参见更新。我已经改用mapply,这样我们就可以包含一个参数来单独设置每个图的y轴顶部。 - eipi10
1
请查看更新后的代码。我还加入了颜色和字体大小,如果有兴趣的话。 - eipi10
1
请查看更新的代码。我添加了颜色美学以获取图例,并展示如何使用单个图例布置图表。 - eipi10
我希望有一种方法可以让我给你的答案投多次赞。非常感谢你的时间和帮助。 - shiny
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接