r - 如何在 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 的附加组件。
我的问题是我不知道如何开始解决这个话题。我的第一个想法是朝这个方向发展:
- 使用 geom_segment 生成箭头和框
- 使用 ggplot 的注释功能将文本放置在箭头或框中
- 根据提供给瀑布图的数据自动计算位置。
请问您是否有其他想法/想法可以在 ggplot 中实现此类图表?
最好的问候马库斯
解决方案
这是我将采用的方法的一个示例。
步骤 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)
推荐阅读
- python - 仅将包含某个单词的 Excel sheet_names 读入 pandas 数据框
- angular - 如何在 NativeScript 的安全存储插件中删除数据存储在特定对象中?[NativeScript 角度]
- javascript - 引导选项卡将所有选项卡保持为“活动”并在第一次选择后停止工作
- mongodb - 如何通过 mongoexport 将参数传递给视图?
- java - 如何在单独的行上输出字符串数组,每行允许 N 个字符
- javascript - 在 WORDPRESS 中使用简码重新加载 Div
- python - 在 Keras 中,使用 SGD,为什么 model.fit() 训练顺利,但逐步训练方法给出了爆炸梯度和损失
- javascript - Mapbox GL JS:在 Studio 中更新图层上的多边形填充颜色
- couchbase - Couchbase - 获取所有文档前缀
- php - 使用 orWhere 与 eloquent