如何为包装 ggplot() 的自定义函数编写可选参数?
How to code optional arguments for a custom function that wraps ggplot()?
我有一个一般性问题,但找不到满意的答案。我正在构建一组可视化功能,我想让用户在使用它们时具有灵活性。例如,我想让它保持可选状态,即误差线是否应包含在条形图中,或者 geom_text()
中的标签是百分比还是小数。
如果我们考虑 ggplot()
中的典型代码构造,我们的元素由 +
分隔。因此,如果我想允许可选构造,我可能需要“打开”或“关闭”整个 geom
s(例如,如果用户不想要错误栏,则完全忽略 geom_errorbar()
plot),或者以其他方式调整 within geom
s(例如,更改 geom_text()
中唯一的 label
参数以将标签转换为百分比或保留小数).
我希望我的问题不会引起过于基于意见的答案,而是让人们在用自定义函数包装 ggplot()
时列出 standard/typical 编码可选参数的方法。
例子
我想出了一个我不喜欢的解决方案。我认为这会使代码变长且难以阅读。我也不能说它在计算方面是否有效。
假设我想为条形图构建一个自定义函数。有几件事我希望它们是“可调整的”:
- 是否应该订购柱状图(参见
reorder_cols
参数)
- 是否提供用户自己的一组 x 轴标签(参见
x_axis_labels
参数)
- 是否添加误差线(
add_errorbar
)
- 是否以百分比显示条形标签(
show_in_percents
)
然后我把每个可选的代码赋值到一个变量中,根据bar_chart()
的相关参数,用条件判断应该包含哪一段代码。
library(tidyverse)
library(broom)
#> Warning: package 'broom' was built under R version 4.0.3
bar_chart <- function(data, x_var, y_value, reorder_cols = TRUE, x_axis_labels = NULL, add_errorbar = NULL) {
reordered <- geom_bar(stat = "identity", width = 0.8, aes(x = reorder({{ x_var }}, -{{ y_value }} ), y = {{ y_value }}, fill = as_factor({{ x_var }})))
not_reordered <- geom_bar(stat = "identity", width = 0.8, aes(x = {{ x_var }}, y = {{ y_value }}, fill = as_factor({{ x_var }})))
with_x_axis_labels <- scale_x_discrete(labels = setNames(str_wrap(x_axis_labels, 10), names(x_axis_labels)), expand = c(0, 0))
without_x_axis_labels <- scale_x_discrete(expand = c(0, 0))
if (reorder_cols == TRUE) {
my_geom_bar <- reordered
} else {
my_geom_bar <- not_reordered
}
if (is.null(x_axis_labels)) {
my_scale_x_discrete <- without_x_axis_labels
} else {
my_scale_x_discrete <- with_x_axis_labels
}
if (add_errorbar == TRUE) {
my_errorbar <- geom_errorbar(aes(x = {{ x_var }}, y = {{ y_value }}, ymin = errorbar_lwr, ymax = errorbar_upr), width = 0.1, size = 0.75)
} else {
my_errorbar <- NULL
}
ggplot(data) +
my_geom_bar +
my_errorbar +
my_scale_x_discrete
}
labels_for_barplot <-
c("bar_1", "bar_2", "bar_3")
mtcars %>%
lm(mpg ~ factor(carb), data = .) %>%
broom::tidy() %>%
mutate(errorbar_lwr = estimate - std.error,
errorbar_upr = estimate + std.error) %>%
bar_chart(data = ., x_var = term, y_value = estimate, reorder_cols = TRUE, add_errorbar = TRUE, x_axis_labels = labels_for_barplot)
由 reprex package (v0.3.0)
于 2021 年 1 月 17 日创建
总而言之,我给出这个例子是为了询问是否有替代的、更简洁的方法来在 ggplot
的包装器中实现可选参数。
编辑
正如@Tjebo 指出的那样,我的代码有问题,根本不会 运行。我更新了它,还删除了关于 geom_text()
的部分,因为它太混乱了。
这不会试图回答所有问题(因为有几个),而只是为了演示您可以利用的原理。查看 the ggplot book on programming with ggplot2
我们的想法是创建一个包含所有 ggplot 对象(例如 aes、geom、scale)的列表。返回的对象 NULL
将被简单地丢弃。这就是全部的美。
我删除了比例尺,因为它有点难以理解您想要达到的目标。这个想法会非常相似。并且实际上通常将整个问题简化为我认为是问题的要点。
library(tidyverse)
bar_chart <- function(data, xvar, yvar,
se = TRUE, show_percents = TRUE,
myscale = TRUE) {
newy <- deparse(substitute(yvar))
if (show_percents) {
my_label <- paste0(100 * round(data[[newy]], 2), "%")
} else {
my_label <- round(data[[newy]], 2)
}
ggplot({{data}}, aes({{xvar}}, {{yvar}})) +
list(
geom_col(width = 0.8),
geom_text(vjust = 1.4, color = "white", size = 6, fontface = "bold", label = my_label),
if (se) geom_errorbar(aes(ymin = {{yvar}} - .1, ymax = {{yvar}} + .1), width = 0.1, size = 0.75)
)
}
iris2 <- iris %>%
group_by(Species) %>%
slice_max(Sepal.Length)
bar_chart(iris2, Species, Sepal.Length)
bar_chart(iris2, Species, Sepal.Length, se = FALSE)
由 reprex package (v0.3.0)
于 2021 年 1 月 17 日创建
我有一个一般性问题,但找不到满意的答案。我正在构建一组可视化功能,我想让用户在使用它们时具有灵活性。例如,我想让它保持可选状态,即误差线是否应包含在条形图中,或者 geom_text()
中的标签是百分比还是小数。
如果我们考虑 ggplot()
中的典型代码构造,我们的元素由 +
分隔。因此,如果我想允许可选构造,我可能需要“打开”或“关闭”整个 geom
s(例如,如果用户不想要错误栏,则完全忽略 geom_errorbar()
plot),或者以其他方式调整 within geom
s(例如,更改 geom_text()
中唯一的 label
参数以将标签转换为百分比或保留小数).
我希望我的问题不会引起过于基于意见的答案,而是让人们在用自定义函数包装 ggplot()
时列出 standard/typical 编码可选参数的方法。
例子
我想出了一个我不喜欢的解决方案。我认为这会使代码变长且难以阅读。我也不能说它在计算方面是否有效。
假设我想为条形图构建一个自定义函数。有几件事我希望它们是“可调整的”:
- 是否应该订购柱状图(参见
reorder_cols
参数) - 是否提供用户自己的一组 x 轴标签(参见
x_axis_labels
参数) - 是否添加误差线(
add_errorbar
) - 是否以百分比显示条形标签(
show_in_percents
)
然后我把每个可选的代码赋值到一个变量中,根据bar_chart()
的相关参数,用条件判断应该包含哪一段代码。
library(tidyverse)
library(broom)
#> Warning: package 'broom' was built under R version 4.0.3
bar_chart <- function(data, x_var, y_value, reorder_cols = TRUE, x_axis_labels = NULL, add_errorbar = NULL) {
reordered <- geom_bar(stat = "identity", width = 0.8, aes(x = reorder({{ x_var }}, -{{ y_value }} ), y = {{ y_value }}, fill = as_factor({{ x_var }})))
not_reordered <- geom_bar(stat = "identity", width = 0.8, aes(x = {{ x_var }}, y = {{ y_value }}, fill = as_factor({{ x_var }})))
with_x_axis_labels <- scale_x_discrete(labels = setNames(str_wrap(x_axis_labels, 10), names(x_axis_labels)), expand = c(0, 0))
without_x_axis_labels <- scale_x_discrete(expand = c(0, 0))
if (reorder_cols == TRUE) {
my_geom_bar <- reordered
} else {
my_geom_bar <- not_reordered
}
if (is.null(x_axis_labels)) {
my_scale_x_discrete <- without_x_axis_labels
} else {
my_scale_x_discrete <- with_x_axis_labels
}
if (add_errorbar == TRUE) {
my_errorbar <- geom_errorbar(aes(x = {{ x_var }}, y = {{ y_value }}, ymin = errorbar_lwr, ymax = errorbar_upr), width = 0.1, size = 0.75)
} else {
my_errorbar <- NULL
}
ggplot(data) +
my_geom_bar +
my_errorbar +
my_scale_x_discrete
}
labels_for_barplot <-
c("bar_1", "bar_2", "bar_3")
mtcars %>%
lm(mpg ~ factor(carb), data = .) %>%
broom::tidy() %>%
mutate(errorbar_lwr = estimate - std.error,
errorbar_upr = estimate + std.error) %>%
bar_chart(data = ., x_var = term, y_value = estimate, reorder_cols = TRUE, add_errorbar = TRUE, x_axis_labels = labels_for_barplot)
由 reprex package (v0.3.0)
于 2021 年 1 月 17 日创建总而言之,我给出这个例子是为了询问是否有替代的、更简洁的方法来在 ggplot
的包装器中实现可选参数。
编辑
正如@Tjebo 指出的那样,我的代码有问题,根本不会 运行。我更新了它,还删除了关于 geom_text()
的部分,因为它太混乱了。
这不会试图回答所有问题(因为有几个),而只是为了演示您可以利用的原理。查看 the ggplot book on programming with ggplot2
我们的想法是创建一个包含所有 ggplot 对象(例如 aes、geom、scale)的列表。返回的对象 NULL
将被简单地丢弃。这就是全部的美。
我删除了比例尺,因为它有点难以理解您想要达到的目标。这个想法会非常相似。并且实际上通常将整个问题简化为我认为是问题的要点。
library(tidyverse)
bar_chart <- function(data, xvar, yvar,
se = TRUE, show_percents = TRUE,
myscale = TRUE) {
newy <- deparse(substitute(yvar))
if (show_percents) {
my_label <- paste0(100 * round(data[[newy]], 2), "%")
} else {
my_label <- round(data[[newy]], 2)
}
ggplot({{data}}, aes({{xvar}}, {{yvar}})) +
list(
geom_col(width = 0.8),
geom_text(vjust = 1.4, color = "white", size = 6, fontface = "bold", label = my_label),
if (se) geom_errorbar(aes(ymin = {{yvar}} - .1, ymax = {{yvar}} + .1), width = 0.1, size = 0.75)
)
}
iris2 <- iris %>%
group_by(Species) %>%
slice_max(Sepal.Length)
bar_chart(iris2, Species, Sepal.Length)
bar_chart(iris2, Species, Sepal.Length, se = FALSE)
由 reprex package (v0.3.0)
于 2021 年 1 月 17 日创建