首页 > 解决方案 > 如何在 ggplot2 中生成的瀑布图中包含类似“think-cell”的百分比变化

问题描述

我尝试在我的公司中建立 R 作为数据可视化工具。我部门使用的典型图表类型是瀑布图(https://en.wikipedia.org/wiki/Waterfall_chart)。

在 R 中,ggplot 有一些包和提示可以生成瀑布图(https://learnr.wordpress.com/2010/05/10/ggplot2-waterfall-charts/),我已经使用了。

不幸的是,使用的瀑布图的一个共同特征是带有箭头的注释,以指示步骤内的百分比变化。

请参阅下面的示例:

条形图/瀑布图的百分比变化注释

或在此视频中 ( https://www.youtube.com/watch?v=WMHf7uFR6Rk )

用于生成此类绘图的软件是 think cell ( https://www.think-cell.com/ ),它是 Excel 和 Powerpoint 的附加组件。

我的问题是我不知道如何开始解决这个话题。我的第一个想法是朝这个方向发展:

请问您是否有其他想法/想法可以在 ggplot 中实现此类图表?

最好的问候马库斯

标签: rggplot2waterfall

解决方案


这是我将采用的方法的一个示例。

步骤 1. 选择应该添加的元素,一次添加一个。

假设我们从这个简单的图表开始:

df <- data.frame(x = c(2007, 2008, 2009),
                 y = c(100, 120, 140))
ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5)

在此处输入图像描述

首先,我们需要一些额外的垂直空间:

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(10, 50))) # Add 50 y padding

在此处输入图像描述

现在,我逐渐添加图层,直到看起来像我想要的那样:

# Semi-manual proof of concept
ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(10, 50))) + # Add 50 y padding

  # Line with arrow
  geom_segment(aes(x    = df$x[3], y    = df$y[3] + 50,
                   xend = df$x[3], yend = df$y[3] + 50), 
               arrow = arrow(length = unit(0.02, "npc"), type = "closed")) +

  # Background box
  geom_tile(aes(x = mean(c(df$x[3], df$x[3])),
                y = mean(c(df$y[3], df$y[3])) + 50, width = 1, height = 40), 
            fill = "white", color = "black", size = 0.5) +

  # Text
  geom_text(aes(x = mean(c(df$x[3], df$x[3])),
                y = mean(c(df$y[3], df$y[3])) + 50,
                label = paste0("CAGR\n", 
                               df$x[3], "-", df$x[3], "\n", 
                               scales::percent((df$y[3] / df$y[3]) ^ (1/(df$x[3]-df$x[3])) - 1))))

在此处输入图像描述

步骤 2. 使其成为一个函数

现在我将与 CAGR 相关的层移动到一个函数中,用函数参数替换大部分常量。

add_CAGR <- function(df, first_val_pos, second_val_pos, 
                     y_offset, box_width = 1, box_height) {
  list(
    # Line with arrow
    geom_segment(aes(x    = df$x[first_val_pos], 
                     xend = df$x[second_val_pos], 
                     y    = df$y[first_val_pos]  + y_offset,
                     yend = df$y[second_val_pos] + y_offset), 
                 arrow = arrow(length = unit(0.02, "npc"), type = "closed")), 

      # Background box
      geom_tile(aes(x = mean(c(df$x[first_val_pos], df$x[second_val_pos])),
                    y = mean(c(df$y[first_val_pos], df$y[second_val_pos])) + y_offset, 
                    width = box_width, height = box_height), 
                fill = "white", color = "black", size = 0.5),

      # Text
      geom_text(aes(x = mean(c(df$x[first_val_pos], df$x[second_val_pos])),
                    y = mean(c(df$y[first_val_pos], df$y[second_val_pos])) + y_offset,
                    label = paste0("CAGR\n", 
                                   df$x[first_val_pos], "-", df$x[second_val_pos], "\n", 
                                   scales::percent((df$y[second_val_pos] / df$y[1]) ^ 
                                                     (1/(df$x[second_val_pos]-df$x[first_val_pos])) - 1))),
                lineheight = 0.8)
  )
}

第 3 步:在情节中使用

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(0, 50))) + # Add 50 y padding
  add_CAGR(df, first_val_pos = 1, second_val_pos = 3, 
           y_offset = 50,
           box_width = 0.7, box_height = 40)

在此处输入图像描述

或者前两个小节之间的相同内容:

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(0, 50))) + # Add 50 y padding
  add_CAGR(df, first_val_pos = 1, second_val_pos = 2, 
           y_offset = 50,
           box_width = 0.7, box_height = 40)

在此处输入图像描述


推荐阅读