在堆积柱形图中为总计和 class 特定值添加数据标签

Adding data labels for totals as well as class-specific values in a stacked column chart

主要问题

使用 R 的 ggplot2 库创建堆积柱形图时,如何为列总计添加数据标签以及为每个个体添加数据标签class/value?

上下文

我正在尝试使用 R 的 ggplot2 库复制以下图表(最初在 Excel 中创建):

图 1 - 在 Excel

中生成的图表

可重现的示例和数据

这是我的数据和我正在使用的代码的可重现示例:

# Loading libraries
library(ggplot2)
library(extrafont)

# Creating the data.frame object
data = data.frame(year=c(2017,2017,2017,2017,
                         2018,2018,2018,2018,
                         2019,2019,2019,2019,
                         2020,2020,2020,2020,
                         2021,2021,2021,2021),
                  hsys=factor(c('Interstate Highways', 'US Highways', 'State Highways', 'FM Roads',
                                'Interstate Highways', 'US Highways', 'State Highways', 'FM Roads',
                                'Interstate Highways', 'US Highways', 'State Highways', 'FM Roads',
                                'Interstate Highways', 'US Highways', 'State Highways', 'FM Roads',
                                'Interstate Highways', 'US Highways', 'State Highways', 'FM Roads'),
                              levels = c('Interstate Highways',
                                         'US Highways',
                                         'State Highways',
                                         'FM Roads')),
                  num_crashes=c(3845,3562,3436,5749,
                                3978,3502,3565,5836,
                                4510,3692,3618,6133,
                                3517,2945,2957,4978,
                                4698,3765,3645,6158))


p = ggplot(data, 
           aes(fill=hsys, 
               y=num_crashes, 
               x=year, 
               label=format(num_crashes, 
                            big.mark = ",", 
                            decimal.mark = ".", 
                            scientific = FALSE),
           )) + 
  geom_bar(position="stack", 
           stat="identity") + 
  geom_text(size=3, 
            position = position_stack(vjust=0.5,), 
            color='white',
            family = "Franklin Gothic Book",
            fontface = 'bold') + 
  theme(plot.title = element_text(family="Franklin Gothic Demi Cond",
                                  hjust = 0.5),
        axis.title = element_text(family = "Franklin Gothic Book",),
        axis.text = element_text(family = "Franklin Gothic Book",),
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        axis.title.x=element_blank(),
        axis.ticks.x=element_blank(),
        legend.position = "bottom",
        legend.text = element_text(family = "Franklin Gothic Book",),
        legend.title = element_blank(),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(), 
        ) +
  scale_fill_manual(values = c("#3869A2",
                               "#0F3859",
                               "#CC7B28",
                               "#F4BC46",
                               "#79A03F"))

ggsave('hsys.jpg', p) 


图 2 - R 中生成的图形

您会注意到,除了图像尺寸和字体大小不匹配外,它们都包含几乎完全相同的内容。真正缺少的是每列顶部的 列总计 的数据标签。

我的尝试

This SO thread 似乎涵盖了一个非常相似的主题,但我无法找到解决方案。

首先,我创建了一个新的 sum_count data.frame 对象,如下所示:

sum_count <- 
  data %>%
  group_by(year) %>%
  summarise(tot_crashes = sum(num_crashes))

然后我在上面原始代码的 geom_texttheme 命令之间向我的 ggplot2 命令添加了一段新代码:

  # before this chunk, we close the first `geom_text` command
  geom_text(data = sum_count, 
            aes(y = tot_crashes, 
                label = format(tot_crashes, 
                               big.mark = ",", 
                               decimal.mark = ".", 
                               scientific = FALSE)), 
            color='black',
            family = "Franklin Gothic Book",
            fontface = 'bold',
            vjust = -0.5) +
  # after this chunk, we start the `theme` command

但是,当我 运行 包含上述新 geom_text 命令的代码时,代码失败并出现以下错误:

Saving 8.06 x 2.89 in image
Error in FUN(X[[i]], ...) : object 'hsys' not found

我该如何解决这个问题?

问题是您将 fill=hsys 指定为 ggplot() 内的全局美学,所有层都将继承它。要解决此问题,您可以使 fill=hsys 成为 geom_bar 的本地 aes 或将 inherit.aes=FALSE 添加到 geom_text 以防止继承全局 aes ,但需要添加 x=yeargeom_text 也是:

p + geom_text(data = sum_count, 
            aes(x = year,
                y = tot_crashes, 
                label = format(tot_crashes, 
                               big.mark = ",", 
                               decimal.mark = ".", 
                               scientific = FALSE)), 
            color='black',
            family = "Franklin Gothic Book",
            fontface = 'bold',
            vjust = -0.5, inherit.aes = FALSE)

第二种实现您想要的结果的方法是使用 stat_summary 即时计算总数,如下所示:

p +
  stat_summary(
    geom = "text", aes(group = 1, label = format(..y..,
      big.mark = ",",
      decimal.mark = ".",
      scientific = FALSE
    ), ), fun = "sum", color = "black",
    family = "Franklin Gothic Book",
    fontface = "bold", vjust = -0.5
  )