如何用tidy eval/NSE/元编程通过参数调用scales::label_*函数?
解决方法:用tidy eval/NSE调用scales的label函数
你遇到的问题是用glue拼接的字符串无法直接作为函数调用,且get找不到带命名空间的函数。以下是几种不用if-else的实现方式:
方法1:使用getFromNamespace直接从scales包获取函数
直接构造label_*的函数名,然后从scales命名空间中提取对应的函数:
library(dplyr) library(ggplot2) library(scales) create_pie_chart <- function(data, fill, label = "percent") { data_counts <- data %>% summarize(num = n(), .by = {{ fill }}) %>% mutate(prop = num/sum(num)) # 构造函数名,从scales包获取对应函数 label_func_name <- paste0("label_", label) label_function <- getFromNamespace(label_func_name, ns = "scales") plot <- data_counts %>% ggplot(aes(x="", y = prop, fill = {{ fill }})) + geom_bar(width = 1, stat = "identity") + coord_polar("y", start = 0) + geom_label( aes(label = label_function()(prop)), # label_*是函数生成器,需先执行得到格式化函数 position = position_stack(vjust = 0.5) ) + theme_void() plot } data("starwars") create_pie_chart(starwars, fill = gender, label = "percent")
方法2:使用rlang的符号求值(tidy eval风格)
用rlang::sym创建包含命名空间的函数符号,再通过eval获取函数:
library(dplyr) library(ggplot2) library(scales) library(rlang) create_pie_chart <- function(data, fill, label = "percent") { data_counts <- data %>% summarize(num = n(), .by = {{ fill }}) %>% mutate(prop = num/sum(num)) # 构造带命名空间的函数符号 label_func_sym <- sym(paste0("scales::label_", label)) label_function <- eval(label_func_sym) plot <- data_counts %>% ggplot(aes(x="", y = prop, fill = {{ fill }})) + geom_bar(width = 1, stat = "identity") + coord_polar("y", start = 0) + geom_label( aes(label = label_function()(prop)), position = position_stack(vjust = 0.5) ) + theme_void() plot } create_pie_chart(starwars, fill = gender, label = "percent")
关键说明
scales::label_*系列是函数生成器,不是直接的格式化函数,所以需要先执行label_function()得到实际的格式化函数,再传入数据(比如label_function()(prop))。- 之前用
get报错是因为get默认在当前环境查找,而scales::label_percent是scales包命名空间内的对象,用getFromNamespace或带命名空间的符号求值可以解决这个问题。
内容的提问来源于stack exchange,提问作者mfg3z0
相关产品推荐
相关产品推荐

