ggplot面板网格条形图的y轴限制不同?

15

我的数据:

    day variable      value
1  Fri     avg1 446.521127
2  Mon     avg1 461.676056
3  Sat     avg1 393.366197
4  Sun     avg1 435.985714
5  Thu     avg1 445.571429
6  Tue     avg1 441.549296
7  Wed     avg1 462.042254
8  Fri     avg2   7.442113
9  Mon     avg2   7.694648
10 Sat     avg2   6.556056
11 Sun     avg2   7.266571
12 Thu     avg2   7.426286
13 Tue     avg2   7.359577
14 Wed     avg2   7.700282

我的问题是,我想使用facet_grid创建一个条形图来显示每天的平均数据集,但是观测值非常相似,因此我发现通过使用scale_y_continuous指定y轴限制非常有帮助。

所以,如果我将我的ggplot分配给g <- ggplot(df, aes(x=day, y=value)),则可以使用以下方法之一获得我想要的一半:

g + geom_bar(stat="identity") + facet_grid(variable~., scales="free")

g + geom_bar(stat="identity") + scale_y_continuous(limits=c(300,500), oob=rescale_none)

然而,我不知道如何使用facet grid,并指定一个scale_y_cont来限制单独y轴的大小。有解决方案吗?


你是在说你不希望每个面的下限为零吗? - eipi10
好的,我希望下限值可以是范围“平均值”之类的东西。 - knl
所以您希望facet“avg1”的下限大致为0.5 * max(avg1),并且facet“avg2”的下限大致为0.5 * max(avg2)?如果不希望y轴刻度尺度降至零,我建议不要使用条形图,因为条形高度之间的相对差异将会误导。 - eipi10
是的,但我不知道如何在 scale_y_continuous 中引用变量或值。 - knl
2个回答

14
使用geom_point时,您可以为不同的数据分面创建单独的y轴范围,但是我不知道如何使用geom_bar来实现。对于使用facet_wrapgeom_bar设置特定y轴范围,我所知道的唯一方法是创建单独的图,并使用gridExtra包中的grid.arrange将它们并排放置。(使用垂直刻度尺不到零会夸大点/条之间的差异,这可能会产生误导,但您必须决定它是否适用于您的特定情况。)
首先,这里是使用geom_point的版本:创建一个“虚拟”数据框,其中包含您想要的ylim的下限和上限值,然后使用geom_blank“绘制”它们。 geom_blank不会绘制任何内容,但添加此几何图形将确保每个数据分面的轴范围符合您的要求。
ddummy = data.frame(day=NA, variable=rep(c("avg1", "avg2"), each=2), 
               value=c(0.5*max(df$value[df$variable=="avg1"]), 
                       1.1*max(df$value[df$variable=="avg1"]),
                       0.5*max(df$value[df$variable=="avg2"]), 
                       1.1*max(df$value[df$variable=="avg2"])))

g <- ggplot(df, aes(x=day, y=value))

g + geom_point() + 
  geom_blank(data=dummy, aes(day, value)) +
  facet_grid(variable ~ ., scales="free")

在此输入图片描述

这里有多个单独的图表,使用grid.arrange组合在一起:

avg1 = ggplot(df[df$variable=="avg1",], aes(x=day, y=value)) +
  geom_bar(stat="identity") +
  facet_wrap(~variable) +
  coord_cartesian(ylim=c(300,500))

avg2 = ggplot(df[df$variable=="avg2",], aes(x=day, y=value)) +
  geom_bar(stat="identity") +
  facet_wrap(~variable) +
  coord_cartesian(ylim=c(3.5,8))

gridExtra::grid.arrange(avg1, avg2, ncol=2)

在此输入图片描述

根据你的评论,使用geom_segment可以这样做:

library(dplyr)

ggplot(df %>% group_by(variable) %>%
         mutate(ymin=0.5*max(value))) +
  geom_segment(aes(x=day, xend=day, y=ymin, yend=value), 
               size=5, colour=hcl(195,100,65)) + 
  facet_grid(variable ~ ., scales="free")

很好。为什么在条形图上没有像geom_point一样强制执行y轴范围? - knl
我相信这是因为geom_bar“假定”条形图应该下降到零,因此“数据” geom_bar 的有效范围隐含地使用的是从零到max(ydata)。添加一个y范围高于零的虚拟数据框不会改变它,因此它不会改变绘图。但是,如果您将我的虚拟数据框中的0.5更改为-0.5,则会看到geom_bar扩展了低于零的y范围,因为您现在已经有效地扩展了绘图的y范围。 - eipi10
哦,当然。如果你不使用虚拟变量绘制geom_point,你会得到类似的结果。我想知道是否可以使用geom_segment从max(avg1/2)/2绘制到该值。 - knl
这是一个老问题,我没有时间写一个完整的答案,但是可以使用来自facetscales包的facet_grid_sc()函数使用条形图来完成此操作。 - kenny

1

实际上,scales = 'free' 选项在使用 geom_bar 函数时对我很有效。我的代码块如下:

    merged_no_country_year %>% 
      ggplot(aes(x=age, y=outcome_values/1000000)) + 
      geom_bar(stat="identity", fill="skyblue", alpha=1.0) + 
      theme_minimal() +
      facet_grid(outcome~source, scales = 'free') + 
      labs(y='people (in millions)')

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