ggplot:如何按照每个分面的顺序对分面条形图中的条形进行排序

17

我有一个R数据框,希望能够用faceted ggplot柱状图来展示它。

我在ggplot中使用以下代码:

ggplot(data_long, aes(x = partei, y = wert, fill = kat, width=0.75)) + 
    labs(y = "Wähleranteil [ % ]", x = NULL, fill = NULL) +
    geom_bar(stat = "identity") +
    facet_wrap(~kat) +
    coord_flip() +
    guides(fill=FALSE) +
    theme_bw() + theme( strip.background  = element_blank(),
                        panel.grid.major = element_line(colour = "grey80"),
                        panel.border = element_blank(),
                        axis.ticks = element_line(size = 0),
                        panel.grid.minor.y = element_blank(),
                        panel.grid.major.y = element_blank() ) +
    theme(legend.position="bottom") +
    scale_fill_brewer(palette="Set2")

这会产生这张图表: enter image description here

您可以看到,只有最后一个区域是按照所需的降序排列的。我希望所有区域都按照降序排列,也就是标签顺序发生变化。因此,我还需要每个区域都有自己的 y 轴标签。

这是我正在使用的数据:

data_long = data.frame(
  partei = c("SP", "Grüne", "AL", "BDP", "glp", 
             "CVP", "EVP", "FDP", "SVP", "EDU", "SP", "Grüne", "AL", "BDP", 
             "glp", "CVP", "EVP", "FDP", "SVP", "EDU", "SP", "Grüne", "AL", 
             "BDP", "glp", "CVP", "EVP", "FDP", "SVP", "EDU", "SP", "Grüne", 
             "AL", "BDP", "glp", "CVP", "EVP", "FDP", "SVP", "EDU", "SP", 
             "Grüne", "AL", "BDP", "glp", "CVP", "EVP", "FDP", "SVP", "EDU", 
             "SP", "Grüne", "AL", "BDP", "glp", "CVP", "EVP", "FDP", "SVP", 
             "EDU", "SP", "Grüne", "AL", "BDP", "glp", "CVP", "EVP", "FDP", 
             "SVP", "EDU"),
  kat = c("kand1", "kand1", "kand1", "kand1", "kand1", 
          "kand1", "kand1", "kand1", "kand1", "kand1", "kand2", "kand2", 
          "kand2", "kand2", "kand2", "kand2", "kand2", "kand2", "kand2", 
          "kand2", "kand3", "kand3", "kand3", "kand3", "kand3", "kand3", 
          "kand3", "kand3", "kand3", "kand3", "kand4", "kand4", "kand4", 
          "kand4", "kand4", "kand4", "kand4", "kand4", "kand4", "kand4", 
          "kand5", "kand5", "kand5", "kand5", "kand5", "kand5", "kand5", 
          "kand5", "kand5", "kand5", "kand6", "kand6", "kand6", "kand6", 
          "kand6", "kand6", "kand6", "kand6", "kand6", "kand6", "kand7", 
          "kand7", "kand7", "kand7", "kand7", "kand7", "kand7", "kand7", 
          "kand7", "kand7"),
  wert = c(95.41, 80.6, 75.77, 54.02, 47.91, 
           39.01, 36.2, 32.01, 5.71, 1.1, 18.05, 7.15, 9.02, 62.3, 39.18, 
           42.41, 23.14, 94.66, 29.93, 34.97, 0.51, 0.27, 3.92, 9.21, 2.53, 
           2.7, 3.52, 23.19, 92.49, 60.64, 52.98, 81.28, 56.42, 7.52, 13.65, 
           4.06, 9.96, 1.46, 0.94, 0, 7.51, 9.19, 9.94, 25.3, 69.58, 10.59, 
           9.23, 17.61, 3.6, 3.43, 4.29, 2.37, 7.73, 13.14, 11.67, 75.43, 
           19.34, 6.52, 2.43, 6.4, 1.87, 2.98, 5.87, 6.7, 1.29, 2.73, 80.91, 
           1.1, 1.58, 45.47)
)

1
你可以通过 kat 进行子集操作,循环并制作图表,按正确顺序提供列表,然后与 gridExtraarrange.grid 结合。 - Tyler Rinker
请点击此处查看一个很好的答案,解释为什么在这里不应该使用facets(以及解决方案)。 - Axeman
好的,谢谢你的提示。 当我不知道会得到多少图时,我该如何动态地将所有图添加到**grid.arrange(p1,p2等)**中? - Mario
1
@Mario,你可以通过例如lapply(split....创建一个图形列表,然后像这样使用do.call(在这里)[https://dev59.com/n2gv5IYBdhLWcg3wSe-2]来排列变量列表的图形。 - Heroka
再次感谢 - 我该如何将单个绘图添加到列表中?我尝试使用 append(plist, p1);假设循环中的绘图称为p1。 - Mario
2
我发布了这个类似的问题,并收到了@GordonShumway的评论:这实际上是一个问题:github.com/tidyverse/ggplot2/issues/1902,但已经被David Robinson解决了:github.com/dgrtwo/drlib/blob/master/R/reorder_within.R希望能有所帮助! - Tito Sanz
4个回答

19

有时候看到所有的代码运行情况更容易,因此这里为您提供了一个解决方案,可以通过一次调用lapply来生成所有的绘图。还有其他一些问题需要解决(排序,正确获取颜色),我喜欢解谜题。

#create list of plots
myplots <- lapply(split(dat,dat$kat), function(x){
  #relevel factor partei by wert inside this subset
  x$partei <- factor(x$partei, levels=x$partei[order(x$wert,decreasing=F)])

  #make the plot
  p <- ggplot(x, aes(x = partei, y = wert, fill = kat, width=0.75)) +
    geom_bar(stat = "identity") +
    scale_fill_discrete(drop=F)+ #to force all levels to be considered, and thus different colors
    theme_bw()+
    theme(legend.position="none")+
    labs(y="Wähleranteil (%)", x="", title=unique(x$kat))+
    coord_flip()
})

library(gridExtra)

do.call(grid.arrange,(c(myplots, ncol=3)))

输入图像描述


我通过一次修改使其工作:x$partei <- factor(x$partei, levels=unique(x$partei[order(x$wert,decreasing=F)])),以使因子水平唯一。 - Chris

4
最简单的解决方案是使用ggcharts包中的bar_chart()函数。请注意,与@Heroka的答案不同,所有子图都有一个共同的x轴。
chart <- ggcharts::bar_chart(
  data_long,
  partei,
  wert,
  fill = kat,
  facet = kat
)
chart

enter image description here

< p > bar_chart() 的结果是一个类型为 ggplot 的对象,因此您可以对其应用任何 ggplot2 函数。
chart +
  labs(y = "Wähleranteil [ % ]", x = NULL, fill = NULL) +
  theme_bw() +
  theme(
    strip.background  = element_blank(),
    panel.grid.major = element_line(colour = "grey80"),
    panel.border = element_blank(),
    axis.ticks = element_line(size = 0),
    panel.grid.minor.y = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position = "none"
  ) +
  scale_fill_brewer(palette = "Set2")

![enter image description here


4

根据上面的评论,我写出了以下代码:

names <- levels(unique(data_long$kat))

plist <- list()
plist[]

for (i in 1:length(names)) {
    d <- subset(data_long,kat == names[i])
    d$partei <- factor(d$partei, levels=d[order(d$wert),]$partei)

    p1 <- ggplot(d, aes(x = partei, y = wert, fill = kat, width=0.75)) + 
    labs(y = "Wähleranteil [ % ]", x = NULL, fill = NULL) +
    geom_bar(stat = "identity") +
    facet_wrap(~kat) +
    scale_y_continuous(limits=c(0, 100)) +
    coord_flip() +
    guides(fill=FALSE) +
    theme_bw() + theme( strip.background  = element_blank(),
                        panel.grid.major = element_line(colour = "grey80"),
                        panel.border = element_blank(),
                        axis.ticks = element_line(size = 0),
                        panel.grid.minor.y = element_blank(),
                        panel.grid.major.y = element_blank() ) +
    theme(legend.position="bottom") +
    scale_fill_brewer(palette="Set2")


    plist[[names[i]]] = p1
}   



do.call("grid.arrange", c(plist, ncol=4)

虽然不够优雅,但它可以生成以下图表:

generates this plot

全部按降序排列 :-)


2

不需要额外的包,您可以使用普通的ggplot来实现:

  1. 为每一行创建一个额外的变量
  2. 将其转换为因子,并重新排序级别
  3. 将图表标签更改为原始值

完整解决方案:

data_long %>% 
  mutate(kat_partei = paste0(kat, '_', partei),
         kat_partei = forcats::fct_reorder(kat_partei, wert)) %>% 
  ggplot(aes(x = kat_partei, y = wert, fill = kat, width=0.75)) + 
  geom_bar(stat = "identity", show.legend = FALSE) +
  scale_x_discrete(name=NULL, labels=function(x) sub('^.*_(.*)$', '\\1', x)) +
  scale_fill_brewer(palette="Set2") +
  coord_flip() +
  facet_wrap(~kat, scales='free_y') +
  labs(y = "Wähleranteil [ % ]") +
  theme_bw() + theme(strip.background  = element_blank(),
                     panel.grid.major = element_line(colour = "grey80"),
                     panel.border = element_blank(),
                     axis.ticks = element_line(size = 0),
                     panel.grid.minor.y = element_blank(),
                     panel.grid.major.y = element_blank())

更多提示:

  • 使用geom_col()代替geom_bar(stat = "identity")
  • 使用show.legend参数代替guides(fill=FALSE)

你提到“不需要额外的包”,但是在你的代码中使用了forcats包和magrittr管道。也许可以更改一下并将这些要求添加到代码顶部? - andschar

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