ggplot元编程函数报错:如何在ggplot中注入字符型列名?
ggplot函数中字符型列名的注入实现
问题背景
想要编写一个函数,从数据框中选取指定列并生成ggplot图形,示例代码如下:
main_df1 <- starwars %>% dplyr::select(name, height, mass) main_df2 <- starwars %>% dplyr::select(name, sex, gender, homeworld, species) plot_gg <- function(main_df, another_df, column_for_clr = c("sex", "gender", "species", "homeworld")){ #var_clf <- enquo(column_for_clr) new_df <- main_df %>% left_join(another_df, by = "name") p_p <- new_df %>% ggplot( aes(x = height, y = mass, colour = as.symbol(column_for_clr)) ) + xlab("Height") + ylab("Mass") classes_to_colors_10 <- c( "feminine" = "red", # gender "masculine" = "#3cb44b", # "female" = "navy", # sex "hermaphroditic" = "darkgreen", # "male" = "purple4" # ) if (column_for_clr == "sex") { print("colour is sex") p_p <- p_p + scale_colour_manual(values = classes_to_colors_10) + ggtitle("title ") } ggsave(plot = p_p, device = "png", filename = paste0(getwd(), "/test_starwars21.png"), units = "in", width = 6, height = 4, dpi = 300) return(p_p) } plot_gg(main_df1, main_df2, column_for_clr= "sex")
报错信息
运行后出现如下错误:
[1] "colour is sex" Error in `geom_blank()`: ! Problem while computing aesthetics. ℹ Error occurred in the 1st layer. Caused by error in `compute_aesthetics()`: ! Aesthetics are not valid data columns. ✖ The following aesthetics are invalid: ✖ `colour = as.symbol(column_for_clr)` ℹ Did you mistype the name of a data column or forget to add `after_stat()`? Run `rlang::last_trace()` to see where the error occurred. Called from: signal_abort(cnd, .file)
尝试过enquo、rlang::!!()、{{ column_for_clr }}等元编程工具,但始终出现各类错误,希望找到在ggplot中实现字符型列名注入的方法。
解决方案
方法1:使用.data代词(官方推荐)
ggplot支持通过.data[[列名字符串]]的方式直接引用字符型列名,这是最安全且直观的方案,无需复杂元编程:
修改ggplot的aes部分:
p_p <- new_df %>% ggplot( aes(x = height, y = mass, colour = .data[[column_for_clr]]) ) + xlab("Height") + ylab("Mass")
方法2:使用aes_string(兼容旧写法)
如果习惯传统写法,也可以用aes_string直接传入字符型参数(该函数已软弃用,但仍可正常使用):
p_p <- new_df %>% ggplot( aes_string(x = "height", y = "mass", colour = column_for_clr) ) + xlab("Height") + ylab("Mass")
完整修改后的函数
main_df1 <- starwars %>% dplyr::select(name, height, mass) main_df2 <- starwars %>% dplyr::select(name, sex, gender, homeworld, species) plot_gg <- function(main_df, another_df, column_for_clr = c("sex", "gender", "species", "homeworld")){ new_df <- main_df %>% left_join(another_df, by = "name") # 使用.data代词的写法 p_p <- new_df %>% ggplot( aes(x = height, y = mass, colour = .data[[column_for_clr]]) ) + xlab("Height") + ylab("Mass") classes_to_colors_10 <- c( "feminine" = "red", "masculine" = "#3cb44b", "female" = "navy", "hermaphroditic" = "darkgreen", "male" = "purple4" ) if (column_for_clr == "sex") { print("colour is sex") p_p <- p_p + scale_colour_manual(values = classes_to_colors_10) + ggtitle("Star Wars Height vs Mass by Sex") } ggsave(plot = p_p, device = "png", filename = paste0(getwd(), "/test_starwars21.png"), units = "in", width = 6, height = 4, dpi = 300) return(p_p) } # 测试函数 plot_gg(main_df1, main_df2, column_for_clr= "sex")
错误原因说明
你尝试的enquo、!!、{{ }}是针对非字符型裸变量设计的(比如调用函数时传入sex而非"sex")。如果要兼容字符型输入,.data代词是最直接的方案,避免了字符串与裸表达式转换的复杂操作。
内容的提问来源于stack exchange,提问作者K Y
相关产品推荐
相关产品推荐

