使用 ggplot2 在堆积条形图中排序分类数据

Posted

技术标签:

【中文标题】使用 ggplot2 在堆积条形图中排序分类数据【英文标题】:Order categorical data in a stacked bar plot with ggplot2 【发布时间】:2011-11-01 07:15:18 【问题描述】:

我有一个包含以下条目的矩阵:

dput(MilDis[1:200,])
structure(list(hhDomMil = c("HED", "ETB", "HED", "ETB", "PER", 
"BUM", "EXP", "TRA", "TRA", "PMA", "MAT", "MAT", "KON", "ETB", 
"PMA", "PMA", "HED", "BUM", "BUM", "HED", "PMA", "PMA", "HED", 
"TRA", "BUM", "EXP", "BUM", "PMA", "ETB", "MAT", "ETB", "ETB", 
"KON", "MAT", "TRA", "BUM", "BUM", "TRA", "TRA", "PMA", "PMA", 
"PMA", "MAT", "ETB", "TRA", "BUM", "TRA", "MAT", "BUM", "ETB", 
"TRA", "TRA", "BUM", "KON", "ETB", "ETB", "ETB", "BUM", "KON", 
"ETB", "ETB", "PMA", "TRA", "PER", "PER", "MAT", "HED", "KON", 
"TRA", "TRA", "TRA", "EXP", "TRA", "BUM", "MAT", "MAT", "TRA", 
"PMA", "HED", "PER", "TRA", "PER", "EXP", "PER", "BUM", "KON", 
"BUM", "ETB", "ETB", "TRA", "PER", "ETB", "KON", "KON", "BUM", 
"ETB", "BUM", "MAT", "BUM", "KON", "KON", "ETB", "MAT", "KON", 
"PER", "ETB", "ETB", "KON", "PMA", "PER", "HED", "HED", "PMA", 
"MAT", "PMA", "PER", "PMA", "TRA", "TRA", "MAT", "BUM", "BUM", 
"KON", "ETB", "ETB", "ETB", "PMA", "TRA", "TRA", "PMA", "PER", 
"KON", "PER", "BUM", "KON", "ETB", "ETB", "BUM", "TRA", "ETB", 
"PMA", "HED", "MAT", "TRA", "BUM", "PMA", "BUM", "ETB", "TRA", 
"TRA", "TRA", "PER", "EXP", "HED", "BUM", "EXP", "HED", "BUM", 
"MAT", "DDR", "BUM", "MAT", "KON", "HED", "HED", "TRA", "BUM", 
"PMA", "PMA", "PMA", "KON", "KON", "MAT", "ETB", "MAT", "TRA", 
"MAT", "ETB", "ETB", "TRA", "MAT", "ETB", "TRA", "HED", "BUM", 
"MAT", "TRA", "PMA", "BUM", "BUM", "EXP", "ETB", "EXP", "EXP", 
"MAT", "TRA", "KON", "BUM", "BUM", "HED"), kclust = c(1L, 2L, 
15L, 4L, 5L, 6L, 5L, 7L, 8L, 5L, 6L, 5L, 11L, 6L, 5L, 1L, 9L, 
10L, 2L, 1L, 9L, 8L, 4L, 11L, 14L, 5L, 8L, 11L, 12L, 5L, 5L, 
14L, 15L, 2L, 10L, 6L, 8L, 4L, 6L, 8L, 14L, 14L, 16L, 10L, 5L, 
1L, 12L, 17L, 12L, 16L, 16L, 5L, 10L, 14L, 8L, 19L, 5L, 4L, 4L, 
14L, 2L, 14L, 9L, 7L, 1L, 14L, 4L, 15L, 18L, 16L, 9L, 14L, 6L, 
14L, 12L, 11L, 4L, 7L, 8L, 12L, 9L, 16L, 2L, 6L, 15L, 1L, 1L, 
3L, 14L, 5L, 5L, 9L, 14L, 6L, 5L, 14L, 15L, 2L, 14L, 2L, 1L, 
8L, 5L, 10L, 1L, 1L, 16L, 5L, 2L, 9L, 9L, 1L, 12L, 10L, 1L, 4L, 
1L, 9L, 8L, 8L, 5L, 10L, 1L, 10L, 2L, 6L, 15L, 2L, 2L, 10L, 5L, 
6L, 10L, 19L, 19L, 6L, 5L, 6L, 7L, 7L, 8L, 5L, 16L, 5L, 6L, 6L, 
1L, 10L, 12L, 4L, 7L, 19L, 7L, 8L, 16L, 10L, 5L, 16L, 12L, 7L, 
7L, 19L, 4L, 6L, 1L, 15L, 7L, 8L, 16L, 4L, 10L, 15L, 11L, 10L, 
1L, 10L, 17L, 1L, 2L, 1L, 14L, 8L, 8L, 14L, 10L, 8L, 6L, 6L, 
8L, 5L, 7L, 5L, 1L, 5L, 7L, 9L, 2L, 1L, 9L, 14L), order = c(9, 
1, 9, 1, 3, 7, 10, 5, 5, 2, 8, 8, 4, 1, 2, 2, 9, 7, 7, 9, 2, 
2, 9, 5, 7, 10, 7, 2, 1, 8, 1, 1, 4, 8, 5, 7, 7, 5, 5, 2, 2, 
2, 8, 1, 5, 7, 5, 8, 7, 1, 5, 5, 7, 4, 1, 1, 1, 7, 4, 1, 1, 2, 
5, 3, 3, 8, 9, 4, 5, 5, 5, 10, 5, 7, 8, 8, 5, 2, 9, 3, 5, 3, 
10, 3, 7, 4, 7, 1, 1, 5, 3, 1, 4, 4, 7, 1, 7, 8, 7, 4, 4, 1, 
8, 4, 3, 1, 1, 4, 2, 3, 9, 9, 2, 8, 2, 3, 2, 5, 5, 8, 7, 7, 4, 
1, 1, 1, 2, 5, 5, 2, 3, 4, 3, 7, 4, 1, 1, 7, 5, 1, 2, 9, 8, 5, 
7, 2, 7, 1, 5, 5, 5, 3, 10, 9, 7, 10, 9, 7, 8, 6, 7, 8, 4, 9, 
9, 5, 7, 2, 2, 2, 4, 4, 8, 1, 8, 5, 8, 1, 1, 5, 8, 1, 5, 9, 7, 
8, 5, 2, 7, 7, 10, 1, 10, 10, 8, 5, 4, 7, 7, 9)), .Names = c("hhDomMil", 
"kclust", "order"), row.names = c(NA, 200L), class = "data.frame")

我想创建一个像 这样的堆积条形图。

唯一的问题是,我希望堆栈的顺序适合这个 (ETB,PMA,PER,KON,TRA,DDR,BUM,MAT,HED,EXP) - 矩阵中的订单号我也有一些审美问题。我在这里搜索了一个解决方案,但没有一个订购建议对我有用... :-\

    如何绘制这样一个有序的图? 如何设置 x 以使每个条都“打开”一个数字? 如何分隔条 - 在这里我尝试使用白色边框...? 如何打印 x 中的所有 kclust 编号?

非常感谢您的帮助! 多米尼克


更新

这是我用来绘制情节的代码:

mycols <- c('#FFFD00', '#97CB00', '#3168FF', '#FF0200', '#FB02FE', \
'#CCFCCC', '#FE9900', '#98CBF8', '#00CCFF', '#00FD03') # Set milieu colors


ggplot(MilDis) +
 geom_bar(aes(kclust, fill=factor(hhDomMil), \
 colour=mycols), position='fill', binwidth=1, colour='white') +
 scale_fill_manual(values = mycols)

更新 2:

我现在就是这样做的:

    mycols <- c('#3168FF', '#00CCFF', '#98CBF8', '#CCFCCC', '#00FD03',\
   '#97CB00', '#FFFD00', '#FE9900', '#FB02FE', '#FF0200') # Set milieu colors

    ggplot(MilDis) +
      geom_bar(aes(factor(kclust), fill=reorder(hhDomMil,order)),\
      position='fill') +
      scale_fill_manual(values = mycols)

有了这个结果:

感谢大家的帮助!

【问题讨论】:

你能发布你用来得到这里显示的情节的 ggplot 代码吗?这将节省一点时间来加快速度以进行您要求的修改(除了订购,@Gavin Simpson 已在下面处理)... 您应该对每个问题提出 1 个问题 - 这样可以更轻松地搜索和查找答案。 @Ben:我刚刚更新了我的帖子。 @Gavin 你是对的,但拆分它也会使它变得更复杂...... @Dominik ???为什么?我已经回答了 1,甚至不需要绘图代码。 2,3 和 4 只需要 kclust 强制转换为一个因子 - 目前您使用的是连续变量,因此 x 轴是连续刻度。 【参考方案1】:

通过在将数据传递给ggplot() 之前正确格式化数据,可以轻松解决这个问题。关键是明确设置hhDomMil 因子的水平。假设你的数据在dat:

dat <- transform(dat, hhDomMil = factor(hhDomMil,
                                        levels = c("ETB", "PMA", "PER", "KON",
                                                   "TRA", "DDR", "BUM", "MAT",
                                                   "HED", "EXP")))

这将hhDomMil 固定为dat 内的一个因素就位并且将级别设置为您想要的顺序:

> head(dat$hhDomMil)
[1] HED ETB HED ETB PER BUM
Levels: ETB PMA PER KON TRA DDR BUM MAT HED EXP

注意当 R 将 hhDomMil 强制转换为一个因子时发生了什么:

> head(factor(as.character(dat$hhDomMil)))
[1] HED ETB HED ETB PER BUM
Levels: BUM DDR ETB EXP HED KON MAT PER PMA TRA

默认是按字母顺序对级别进行排序,这就是为什么情节会如您所见。

我能给出的最佳建议是先正确格式化您的数据,然后再尝试绘制它 - 不要依赖自动或即时转换来获得适合您的数据;不可避免地不会是你想要的。

【讨论】:

【参考方案2】:

如果您将 hhDomMil 重新调整为这样的因素:

o<-c("ETB" "PMA" "PER" "KON" "TRA" "DDR" "BUM" "MAT" "HED" "EXP")
d$hh<-factor(d$hhDomMil,levels=o)

那么你的情节将按照你喜欢的顺序:

ggplot(d,(aes(x=kclust, fill=hh))) +geom_bar(position="fill")

【讨论】:

我喜欢这个解决方案,因为 a)它很简洁,b)它也可以推广到非 ggplot 问题。 像 Gavins 一样,解决方案,这是一个很好的通用解决方案【参考方案3】:

我看到您的数据框中有一个order 列,我收集的是您的订单。因此你可以简单地做。

p0 = qplot(factor(kclust), fill = reorder(hhDomMil, order), position = 'fill', 
       data = df1)

以下是处理您的问题的代码元素

    如何绘制这样一个有序的图? reorder 如何设置 x 以使每个条都“打开”一个数字? factor(kclust) 如何分隔条形? 如何打印 x 中的所有 kclust 编号? factor(kclust)

我记得你之前的一个问题,hhDomMil 对应于不同的组,我怀疑你的排序遵循分组。在这种情况下,您可能希望使用该信息来选择一个调色板,以便更轻松地跟踪图表。这是一种方法。

mycols = c(brewer.pal(3, 'Oranges'), brewer.pal(3, 'Greens'), 
           brewer.pal(2, 'Blues'), brewer.pal(2, 'PuRd'))

p0 + scale_fill_manual(values = mycols)

【讨论】:

非常感谢您的解决方案!这正是我一直在寻找的。而且您的假设是绝对正确的,它们以所描述的方式对应。 如果集群编号没有任何意义,那么我会重新排序这个图,以便集群根据它们包含的元素数量进行排列。或者您也可以根据它们包含的组数来排列集群。 集群对应一个邻域设置。但是所有的环境都在所有的集群中。在显示的示例中并非所有数据点,因为在此处发布它们会太大...但是您的想法很好,您对 update2 中的情节有想法吗?

以上是关于使用 ggplot2 在堆积条形图中排序分类数据的主要内容,如果未能解决你的问题,请参考以下文章

在堆积条形图中反转 geom_text() (ggplot2)

带有 facet_grid 的 ggplot2 中具有多个分类变量的堆积条形图

带有facet_grid的ggplot2中带有多个分类变量的堆积条形图

带有ggplot2的发散堆积条形图:图例中的因子排序问题

将百分比标签添加到堆积条形图ggplot2

堆积条形图,按总计(值的总和)重新排序,而不是值 ggplot2 + dplyr