使用arrangeGrob批量排列grob报错:仅允许grob在gList中
问题描述
我需要基于调研数据批量生成图表,要求每个条形图旁显示完整问题文本,采用grid排列grob的方案最优。但使用arrangeGrob传入grob列表时,执行grid.draw会报错:Error in gList(...) : only 'grobs' allowed in "gList"。手动逐个传入grob可正常运行,但无法满足批量自动化需求。
原代码如下:
# Dummy data set question <- c("Q1. A very long text like this one is hard to use as a label.", "Q2. A very long text like this one is hard to use as a label.", "Q3. A very long text like this one is hard to use as a label.", "Q4. A very long text like this one is hard to use as a label.", "Q5. A very long text like this one is hard to use as a label.") variable <- c("V1","V2") set.seed(42) response <- round(runif(n = length(question) * length(variable), min = 1, max = 10), 0) # Create a data frame df_example <- expand.grid(Question = question, Variable = variable) df_example$Response <- rep(response, length.out = nrow(df_example)) grob_list <- list() for (question in unique(df_example$Question)) { # Text grob # used textbox_grob() over alternatives for ease of wrapping text. text_grob <- textbox_grob(question, x = 0.05, y = 0.5, hjust = 0, vjust = 0.5, gp = gpar(col = "black"), maxwidth = 1, padding = unit(c(0, 20, 0, 0), "pt")) # Bar chart bar_chart <- ggplot(df_example, aes(x = Variable, y = Response, fill = Variable)) + geom_bar(stat = "identity", position = "dodge") + coord_flip() + theme_minimal() + theme(legend.position = "none") + theme(axis.title.x = element_blank()) + theme(axis.title.y = element_blank()) # Convert ggplot to grob bar_grob <- ggplotGrob(bar_chart) # Add text and bar chart grobs to the list of grobs grob_list[[length(grob_list) + 1]] <- list(text_grob, bar_grob) } ### a. Required step for automation- # Arrange grobs from list into a grid combined_grobs <- arrangeGrob(grob = grob_list, ncol = 2) # returns an error at grid.draw(): # > Error in gList(...) : only 'grobs' allowed in "gList" ### b. Manual step that works but not practical at scale- # Arrange grobs manually using arrangeGrob from grid combined_grobs <- arrangeGrob(grob_list[[1]][[1]], grob_list[[1]][[2]], grob_list[[2]][[1]], grob_list[[2]][[2]], grob_list[[3]][[1]], grob_list[[3]][[2]], grob_list[[4]][[1]], grob_list[[4]][[2]], grob_list[[5]][[1]], grob_list[[5]][[2]], ncol = 2 ) # Display after step a or b above. grid.newpage() grid.draw(combined_grobs)
问题原因
当前生成的grob_list是嵌套列表,每个元素又是包含文本grob和条形图grob的子列表,而arrangeGrob要求传入的是扁平化的grob对象列表,不能有嵌套结构。此外原代码还存在一个bug:所有条形图都使用了全量数据,导致每个问题对应的图表完全一致。
解决方案
方法1:扁平化grob列表(推荐)
直接在循环中将每个grob添加到顶级列表,避免嵌套,同时修复数据过滤问题:
# Dummy data set question <- c("Q1. A very long text like this one is hard to use as a label.", "Q2. A very long text like this one is hard to use as a label.", "Q3. A very long text like this one is hard to use as a label.", "Q4. A very long text like this one is hard to use as a label.", "Q5. A very long text like this one is hard to use as a label.") variable <- c("V1","V2") set.seed(42) response <- round(runif(n = length(question) * length(variable), min = 1, max = 10), 0) # Create a data frame df_example <- expand.grid(Question = question, Variable = variable) df_example$Response <- rep(response, length.out = nrow(df_example)) grob_list <- list() for (q in unique(df_example$Question)) { # Text grob text_grob <- textbox_grob(q, x = 0.05, y = 0.5, hjust = 0, vjust = 0.5, gp = gpar(col = "black"), maxwidth = 1, padding = unit(c(0, 20, 0, 0), "pt")) # Bar chart:过滤当前问题的数据,修复原bug bar_chart <- ggplot(subset(df_example, Question == q), aes(x = Variable, y = Response, fill = Variable)) + geom_bar(stat = "identity", position = "dodge") + coord_flip() + theme_minimal() + theme(legend.position = "none") + theme(axis.title.x = element_blank()) + theme(axis.title.y = element_blank()) # Convert ggplot to grob bar_grob <- ggplotGrob(bar_chart) # 直接将两个grob添加到顶级列表,避免嵌套 grob_list <- c(grob_list, list(text_grob, bar_grob)) } # 传入扁平化的grob列表,注意参数名是grobs(原代码用grob是错误的) combined_grobs <- arrangeGrob(grobs = grob_list, ncol = 2) # 显示图表 grid.newpage() grid.draw(combined_grobs)
方法2:展开现有嵌套列表
如果要保留原循环的嵌套结构,可以用do.call将嵌套列表展平后再传入:
# 保留原代码生成的嵌套grob_list不变,执行以下步骤: flat_grobs <- do.call(c, grob_list) combined_grobs <- arrangeGrob(grobs = flat_grobs, ncol = 2) grid.newpage() grid.draw(combined_grobs)
内容的提问来源于stack exchange,提问作者Bart Yarborough
相关产品推荐
相关产品推荐

