你如何在ggplot2的geom_bar中排序填充颜色?

58
我正在调用ggplot函数。
ggplot(data,aes(x,y,fill=category)+geom_bar(stat="identity")

结果是一张柱状图,柱子的颜色对应着各自的类别。然而,颜色的顺序在不同的柱子中并不一致。比如有粉色、绿色和蓝色。有些柱子从下往上是粉色、绿色、蓝色,有些则是绿色、粉色、蓝色。我没有看到任何明显的模式。

这些顺序是怎么选出来的呢?我该如何改变它?至少我该如何让ggplot选择一个一致的顺序呢?

(x、y 和 category)的类别分别是 (整数、数值和因子)。如果我将 category 设为有序因子,也无法改变这种行为。

有人知道如何解决这个问题吗?

可重现的例子:

data <- data.frame(
  mon = c(
    9L, 10L, 11L, 10L, 8L, 7L, 7L, 11L, 9L, 10L, 12L, 11L, 7L,
    12L, 8L, 12L, 9L, 7L, 9L, 10L, 10L, 8L, 12L, 7L, 11L, 10L, 8L,
    7L, 11L, 12L, 12L, 9L, 9L, 7L, 7L, 12L, 12L, 9L, 9L, 8L
  ),
  gclass = ordered(c(
    "Up-Up", "Down-Down", "Up-Stable", "Stable-Up", "Stable-Down",
    "Stable-Down", "Down-Up", "Stable-Up", "Down-Stable", "Stable-Down",
    "Down-Down", "Down-Down", "Stable-Stable", "Up-Down", "Down-Down",
    "Stable-Up", "Up-Stable", "Stable-Up", "Stable-Down", "Up-Down",
    "Up-Stable", "Up-Down", "Up-Up", "Up-Stable", "Down-Up", "Stable-Stable",
    "Up-Up", "Down-Stable", "Up-Down", "Down-Up", "Stable-Stable",
    "Stable-Stable", "Up-Down", "Up-Down", "Up-Up", "Down-Stable",
    "Stable-Down", "Down-Down", "Down-Up", "Up-Stable"
  )),
  NG = c(
    222614.67, 9998.17, 351162.2, 37357.95, 4140.48, 1878.57, 553.86, 40012.25,
    766.52, 15733.36, 90676.2, 45000.29, 0, 375699.84, 2424.21, 93094.21,
    120547.69, 291.33, 1536.38, 167352.21, 160347.01, 26851.47, 725689.06,
    4500.55, 10644.54, 75132.98, 42676.41, 267.65, 392277.64, 33854.26, 384754.67,
    7195.93, 88974.2, 20665.79, 7185.69, 45059.64, 60576.96, 3564.53, 1262.39,
    9394.15
  )
)

ggplot(data, aes(mon, NG, fill = gclass)) + geom_bar(stat = "identity")

2
请提供可重现的示例。 - Ben Bolker
顺便说一句:Brian 确认了这实际上是一个(有点长期存在的)错误。 - joran
3
读者请注意 - 在ggplot2最近的历史中,这种行为不幸地发生了几次改变,一些回答中的示例已经无法使用。 - Ken Williams
6个回答

78

从ggplot2_2.0.0开始,order美学不再可用。 为了得到一个将堆栈按填充颜色排序的图形,您可以简单地按要排序的分组变量对数据集进行排序。

我经常使用dplyr中的arrange来实现这个功能。 在这里,我通过ggplot调用内的fill因子对数据集进行排序,而不是创建一个有序的数据集,但两种方法都可以正常工作。

library(dplyr)

ggplot(arrange(data, gclass), aes(mon, NG, fill = gclass)) +
    geom_bar(stat = "identity")

当然,在base R中可以轻松完成这个任务,使用经典的order函数和提取括号即可:

ggplot(data[order(data$gclass), ], aes(mon, NG, fill = gclass)) +
    geom_bar(stat = "identity")

经过这些步骤,现在两种情况下的图表都按照所需的顺序排列:

enter image description here

ggplot2_2.2.0更新

在ggplot_2.2.0中,填充的顺序基于因子水平的顺序。默认顺序会将第一个水平放在堆栈的顶部而不是底部。

如果您想要将第一个水平放在堆栈的底部,您可以在position_stack中使用reverse = TRUE。请注意,您还可以使用geom_col作为geom_bar(stat = "identity")的快捷方式。

ggplot(data, aes(mon, NG, fill = gclass)) +
    geom_col(position = position_stack(reverse = TRUE))

这似乎在stat="identity"的情况下运行良好,但在geom_bar(stat="summary", fun.y=median)的情况下失败。在这种情况下,我不得不对数据进行总结并使用stat="identity"来获得适当的排序。我相信这是自2.0以来的新功能。 - Etienne Low-Décarie
@EtienneLow-Décarie 可能 stat_summary_bin 是这个问题的适当工具。你尝试过使用 stat = "summary_bin" 而不是 stat = "summary" 吗? - aosmith
这真的很烦人。有人可以评论一下为什么order美学被移除了吗?参考链接:https://github.com/hadley/ggplot2/issues/1593 - fanli
太棒了!非常感谢您的留言和解决方案! - Shadow
4
如果想要调整图例的顺序以匹配堆叠的顺序,可以添加guides(fill = guide_legend(reverse = T))来实现。 - Eric

27
你需要同时指定 order 这个美学属性。
ggplot(data,aes(mon,NG,fill=gclass,order=gclass))+
    geom_bar(stat="identity")

enter image description here

这可能是一个bug


4
从ggplot >= 2.0版本开始,“Ignoring unknown aesthetics: order”!(见下文) - Yan Foto

7

要下订单,您必须使用levels参数并通知订单。就像这样:

data$gclass
(data$gclass2 <- factor(data$gclass,levels=sample(levels(data$gclass)))) # Look the difference in the factors order
ggplot(data,aes(mon,NG,fill=gclass2))+geom_bar(stat="identity")

4
您可以使用 scale_fill_ 函数来更改颜色。例如:
ggplot(dd,aes(mon,NG,fill=gclass)) + 
  geom_bar(stat="identity") + 
  scale_fill_brewer(palette="blues")

要在 bars 中获得一致的排序,则需要对数据框进行排序:
dd = dd[with(dd, order(gclass, -NG)), ]

为了改变图例的顺序,请修改gclass因子。示例如下:
dd$gclass= factor(dd$gclass,levels=sort(levels(dd$gclass), TRUE))

enter image description here


1
这看起来对你来说像是一致的排序吗?我和原帖作者遇到了相同的问题,数据出了点问题。这里似乎有些不对劲。 - joran
1
@joran 啊,我现在明白问题了! - csgillespie
@Dave31415 我想我已经回答了这个问题,但是我对为什么这样工作的理解有点模糊。 - csgillespie
好的,我同意,对df进行排序似乎是有效的。但是这仍然让我感到非常可疑。 - joran
@csgillespie。谢谢。这似乎有效,但仍然有点奇怪。我想知道stat="identity"是否是问题所在。 - Dave31415

4

由于这个交换显示在“因子填充顺序”中排名第一,我将再添加一种解决方案,我认为这更直接,并且不需要修改您的基础数据。

ggplot(data,aes(x,y,fill=factor(category, levels = c("Down-Down", "Down-Stable", "Down-Up", "Stable-Down", "Stable-Stable", "Stable-Down", "Up-Down", "Up-Stable", "Up-Up"))) + 
geom_col(position = position_stack(reverse = FALSE))

或者,我更喜欢先创建一个变量向量,以后编码更简单,易于编辑:
v_factor_levels <- c("Down-Down", "Down-Stable", "Down-Up", "Stable-Down", "Stable-Stable", "Stable-Down", "Up-Down", "Up-Stable", "Up-Up")

ggplot(data,aes(x,y,fill=factor(category, levels = v_factor_levels)) + 
geom_col(position = position_stack(reverse = FALSE))

您不需要在geom_col()中使用reverse position元素,我将其保留作为提醒,以防想要反转,但是您可以通过消除它来进一步简化。


1
对于那些希望更清晰地看到相邻类别的人,可以添加 scale_fill_brewer(palette = "Set1")。 - undefined

1

在@aosmith的回答基础上,我发现另一种更直观的排序条形图的方法是:

ggplot(data, aes(x=mon, y=reorder(NG,gclass), fill = gclass)) +
    geom_bar(stat = "identity")

基本统计包中重新排序函数的优点在于您可以在reorder(based_on_dimension, y, function)中使用它,其中y是基于维度based_on_dimension使用sum、mean等函数进行排序。

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