You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:38:19