"geom_bar(position = 'dodge')"中的条形图宽度相同。

64

我希望使用相同的宽度绘制条形图。这是我的最小示例代码:

data <- data.frame(A = letters[1:17],
                   B = sample(1:500, 17),
                   C = c(rep(1, 5), rep(2, 6), rep(c(3,4,5), each = 2)))

ggplot(data,
       aes(x = C,  y = B, label = A,
           fill = A)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(position = position_dodge(width = 0.9), angle = 90)

结果如上图所示: enter image description here

条形图的宽度取决于变量C中给定组的观察次数。我希望每个条形图的宽度相同。

facet_grid(~C)可以实现这一点(条形图具有相同的宽度),但这不是我的意思:

ggplot(data,
       aes(x = C,  y = B, label = A,
           fill = A)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(position = position_dodge(width = 0.9), angle = 90) +
  facet_grid(~C)

enter image description here

我希望的是像第一张图片一样的绘图,但是每个级别中观察数量独立于列C中的观察数量。我该怎么做?
[编辑] geom_bar(width) 可以改变条形图组的宽度,但第五组的条形比第一组的条形更宽,所以这不是我的问题的答案。

我不知道你如何在不更改 aes(x = ) 的情况下完成这个任务。如果您在 geom_bar() 中观察到的数量不均匀,该函数将限制单个观察宽度为组的宽度,以便所有观察都可见。 - Nate
尝试这个:https://dev59.com/42gu5IYBdhLWcg3w3ara。所以对于你的数据,你必须像这样转换它:`dat.all <- rbind(data[,c(1,3,2)], cbind(expand.grid(A=levels(data$A),C=levels(data$C)), B=NA))`但我认为 facet grid 是更好的选择。 - Roman
5
给未来的自己:如果问题是“如何在使用position_dodge时让geom_bar具有固定宽度?”,可以直接在手册中尝试这个“geom_bar(position = position_dodge(preserve = "single"))”方法。[未经过OP的问题测试] - PatrickT
1个回答

108

更新

自从ggplot2_3.0.0版本以来,您现在可以使用preserve = c("total", "single")position_dodge2一起使用。

ggplot(data,aes(x = C,  y = B, label = A, fill = A)) +
  geom_col(position = position_dodge2(width = 0.9, preserve = "single")) +
  geom_text(position = position_dodge2(width = 0.9, preserve = "single"), angle = 90, vjust=0.25)

enter image description here

原始回答

如已经评论所述,您可以像在这个answer中那样做: 使用tidyrcompleteAC转换为因子,并添加未见过的变量。自最近的ggplot2版本以来,建议在stat =“identity”的情况下使用geom_col而不是geom_bar

data %>% 
  as.tibble() %>% 
  mutate_at(c("A", "C"), as.factor) %>% 
  complete(A,C) %>% 
  ggplot(aes(x = C,  y = B, fill = A)) +
  geom_col(position = "dodge")

enter image description here

或者使用交互项:

data %>% 
  ggplot(aes(x = interaction(C, A),  y = B, fill = A)) +
  geom_col(position = "dodge")

enter image description here

通过最终将交互转换为数字,您可以根据所需的输出设置x轴。通过分组(group_by),您可以计算匹配的断点。在ggplot参数周围使用{}的花式技巧是必要的,以便直接在管道中使用变量BreaksC
data %>% 
  mutate(gr=as.numeric(interaction(C, A))) %>% 
  group_by(C) %>% 
  mutate(Breaks=mean(gr)) %>% 
  {ggplot(data=.,aes(x = gr,  y = B, fill = A, label = A)) +
   geom_col(position = "dodge") +
   geom_text(position = position_dodge(width = 0.9), angle = 90 ) +
   scale_x_continuous(breaks = unique(.$Breaks),
                     labels = unique(.$C))}

enter image description here

编辑:

另一种方法是使用 facets。使用 space = "free_x" 可以设置宽度与 x 轴比例相关。

library(tidyverse)
data %>% 
  ggplot(aes(x = A,  y = B, fill = A))  +  
   geom_col(position = "dodge") +
   facet_grid(~C, scales = "free_x", space = "free_x")

enter image description here

你也可以使用switch将分面标签绘制在底部,并删除x轴标签。

data %>% 
  ggplot(aes(x = A,  y = B, fill = A))  +  
  geom_col(position = "dodge") +
  facet_grid(~C, scales = "free_x", space = "free_x", switch = "x") + 
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        strip.background = element_blank())

enter image description here


但我还有一个问题 - as.numeric(interaction(C,A)) 中的数字是什么意思,R如何将交互向量转换为数字? 我在其他数据上使用代码,as.numeric(interaction(C,A)) 的结果是无序数字向量,并且绘图看起来不像应该的样子(图中的条形图顺序不正确)。 - jjankowiak
1
我认为这是一个层级排序问题。为了清楚起见,请查看此示例,并将 as.numeric(factor(c("a","b","c"))) 的输出与 as.numeric(factor(c("a","b","c"),levels = c("b","c","a"))) 的输出进行比较。因此,您必须重新排序 interaction() 产生的因子水平。 - Roman

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