如何在 ggplot2 中使用 position_dodge() 为 geom_col() 中的每个条获得相同的宽度?

How to get the same width for every bar in this geom_col() with position_dodge() in ggplot2?

我正在尝试重现以下情节:

到目前为止,我已经在 R 中生成了以下代码:

library(tidyverse)

tribble(~attribute, ~level, ~importance_score,
        "Price", " per month", -0.18,
        "Price", " per month", 0,
        "Price", " per month", 0.18,
        "Data included", "500MB", -0.25,
        "Data included", "1GB", -0.10,
        "Data included", "10GB", 0.11,
        "Data included", "Unlimited", 0.23,
        "International minutes included", "0 min", -0.01,
        "International minutes included", "90 min", -0.01,
        "International minutes included", "300 min", 0.02,
        "SMS included", "300 messages", -0.06,
        "SMS included", "Unlimited text", 0.06) %>% 
  mutate(id = 1:nrow(.)) %>% 
  arrange(desc(id)) %>% 
  mutate(attribute = as_factor(attribute),
         level = as_factor(level)) %>%
  ggplot(aes(attribute, importance_score, fill = level)) +
  geom_col(width = 0.5, position = position_dodge(0.75)) +
  coord_flip() +
  scale_y_continuous(breaks = seq(-0.4, 0.4, by = 0.1), limits = c(-0.35, 0.35)) +
  scale_fill_manual(values = c(" per month" = "#721817",
                               " per month" = "#721817",
                               " per month" = "#721817",
                               "500 MB" = "#fa9f42",
                               "1GB" = "#fa9f42",
                               "10GB" = "#fa9f42",
                               "Unlimited" = "#fa9f42",
                               "0 min" = "#2b4162",
                               "90 min" = "#2b4162",
                               "300 min" = "#2b4162",
                               "300 messages" = "#0b6e4f",
                               "Unlimited text" = "#0b6e4f")) +
  labs(y = "Relative value", x = "Levels by attribute") +
  theme(panel.grid.minor = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.major.x = element_line(color = "gray95", linetype = 1, size = 1),
        panel.grid.major = element_blank(),
        panel.background = element_blank(),
        legend.position = "none",
        text = element_text(size = 15))

输出以下图:

我的问题是,您将如何控制 geom_col() 中的 width 参数而不弄乱 position = position_dodge() 参数,它允许情节按“属性”分组多变的? 我想要的是让这个图中的每个条形具有相同的宽度,并且每个分组变量之间的距离也相同。

当我使用 position = position_dodge(0.75, preserve = "single") 时,我得到:

在这种情况下,在这个图中看得不是很清楚,但是:我在图上画的两个绿色括号的长度不一样。 我该如何解决这个问题

实现您想要的结果的一个选择是像这样使用 facet_grid

  1. factor(id) 映射到 y 而不是 atrribute
  2. attribute 的分面。添加 scales="free_y"space=free_y
  3. 通过 theme 选项设置条带文本的样式并删除轴标签和刻度。
  4. 要在条形组之间添加一些 space,您可以调整 y 比例尺的扩展

注意:据我所知,您可以将 attribute 映射到 fill,这将简化您的 scale_fill_manual,因为您只需要设置四种颜色。

library(tidyverse)

dd <- dd %>% 
  mutate(id = 1:nrow(.)) %>% 
  arrange(desc(id)) %>% 
  mutate(attribute = forcats::fct_rev(as_factor(attribute)),
          level = as_factor(level))

ggplot(dd, aes(importance_score, factor(id), fill = attribute)) +
  geom_col() +
  scale_x_continuous(breaks = seq(-0.4, 0.4, by = 0.1), limits = c(-0.35, 0.35), expand = c(0, 0)) +
  scale_y_discrete(expand = expansion(add = c(1, 1))) +
  scale_fill_manual(values = c("Price" = "#721817", 
                               "Data included" = "#fa9f42",
                               "International minutes included" = "#2b4162",
                               "SMS included" = "#0b6e4f")) +
  labs(y = "Relative value", x = "Levels by attribute") +
  facet_grid(attribute ~ ., scales = "free_y", space = "free_y", switch = "y") +
  theme(panel.grid.minor = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.major.x = element_line(color = "gray95", linetype = 1, size = 1),
        panel.grid.major = element_blank(),
        panel.background = element_blank(),
        legend.position = "none",
        text = element_text(size = 15),
        strip.text.y.left = element_text(angle = 360, hjust = 1),
        strip.background.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.ticks.length.y = unit(0, "pt"),
        panel.spacing.y = unit(0, "pt")
        )

数据

dd <- tribble(~attribute, ~level, ~importance_score,
        "Price", " per month", -0.18,
        "Price", " per month", 0,
        "Price", " per month", 0.18,
        "Data included", "500MB", -0.25,
        "Data included", "1GB", -0.10,
        "Data included", "10GB", 0.11,
        "Data included", "Unlimited", 0.23,
        "International minutes included", "0 min", -0.01,
        "International minutes included", "90 min", -0.01,
        "International minutes included", "300 min", 0.02,
        "SMS included", "300 messages", -0.06,
        "SMS included", "Unlimited text", 0.06)