I am making a large volume of plots from survey data that requires the entire text of each question to be displayed next to the resulting bar chart. Arranging a grid of grobs seems the best way to do this. However, I have tried several packages, and have the same issue with the grid arrange step not recognizing the input list of grobs as grobs at the grid.draw() step.
Manually typing in the list references for each grob works fine, but this is not an acceptable solution as the volume of plots mandates an automated process.
# 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)
An easier approach would be to use facetting and
ggtext::element_textbox(_simple)to automatically wrap the question text:UPDATE To make your code work requires two small fixes. First, your
grob_listis a nested list, i.e. it is alistoflists of grobs instead of alistof grobs. To fix that usec()to build yourgrob_listin theforloop. Second, the name of the argument isgrobs=notgrob=.