如何按clarity分组命名ggplot2组合直方图?
按clarity分组生成对应标题的组合直方图问题解决
问题说明
我正在学习R语言可视化,想要按clarity分组生成组合直方图,但遇到两个问题:
- 当前生成的所有直方图标题均为“carat”,无法用
clarity的取值作为对应直方图的标题 - 尝试修改
set_names写法时触发错误:Error in set_names(): ! The size of nm (8) must be compatible with the size of x (2)
原代码如下:
library(ggplot2) library(dplyr) library(rlang) library(purrr) library(gridExtra) carat_histogram <- function(df) { label= names({{df}}) ggplot(df, aes(x = carat)) + geom_histogram(binwidth = 0.1)+ labs(title = label) } by_clarity <- diamonds |> group_nest(clarity) by_clarity_named <- set_names(by_clarity$data, nm = by_clarity$clarity) names(by_clarity_named) by_clarity_named<-map(by_clarity_named, carat_histogram) do.call(grid.arrange,by_clarity_named)
尝试过的错误代码:
by_clarity_named <- set_names(by_clarity, nm = by_clarity$clarity) #Error in `set_names()`: ! The size of `nm` (8) must be compatible with the size of `x` (2).
问题原因
- 标题错误原因:
carat_histogram函数中用names({{df}})获取标题,但group_nest生成的每个子数据框包含原数据的多列(carat、cut、color等),names({{df}})返回的是所有列名的向量,ggplot会自动取第一个元素(即carat)作为标题,所以所有图的标题都相同。 - set_names报错原因:
by_clarity是一个包含2列(clarity和data)的数据框,对象长度为2,但by_clarity$clarity有8个取值,用set_names(by_clarity, by_clarity$clarity)时,名字数量和对象长度不匹配,因此触发错误。
解决方案
方法一:用pmap同时传递分组值和数据
直接修改函数,增加参数接收clarity值作为标题,用pmap按行遍历分组后的数据,同时传递分组值和子数据框:
library(ggplot2) library(dplyr) library(purrr) library(gridExtra) # 修改函数,新增clarity_val参数用于设置标题 carat_histogram <- function(df, clarity_val) { ggplot(df, aes(x = carat)) + geom_histogram(binwidth = 0.1) + labs(title = clarity_val) } # 按clarity分组嵌套数据 by_clarity <- diamonds |> group_nest(clarity) # 按行传递clarity值和子数据框,生成直方图列表 hist_list <- pmap(by_clarity, carat_histogram) # (可选)给直方图列表设置名字,方便后续操作 names(hist_list) <- by_clarity$clarity # 组合显示所有直方图 do.call(grid.arrange, hist_list)
方法二:用set_names+map2绑定名字和数据
如果坚持使用set_names给数据列表命名,可以用map2同时遍历数据列表和它的名字,将名字作为标题传递给函数:
library(ggplot2) library(dplyr) library(purrr) library(gridExtra) # 修改函数,新增title参数接收标题 carat_histogram <- function(df, title) { ggplot(df, aes(x = carat)) + geom_histogram(binwidth = 0.1) + labs(title = title) } # 按clarity分组嵌套数据 by_clarity <- diamonds |> group_nest(clarity) # 给data列的子数据框列表命名为对应的clarity值 named_data <- set_names(by_clarity$data, by_clarity$clarity) # 同时遍历数据列表和它的名字,生成直方图 hist_list <- map2(named_data, names(named_data), carat_histogram) # 组合显示所有直方图 do.call(grid.arrange, hist_list)
关键说明
- 原代码中
set_names(by_clarity$data, by_clarity$clarity)是正确的写法,因为by_clarity$data是包含8个子数据框的列表,和by_clarity$clarity的长度(8)匹配,之前的错误是误将整个数据框by_clarity作为命名对象,而非data列的列表。 - 不要通过子数据框的列名获取标题,因为子数据框保留了原数据的所有列,无法直接拿到分组的
clarity值,最好直接传递分组值作为标题参数。
内容的提问来源于stack exchange,提问作者franklin ross
相关产品推荐
相关产品推荐

