How to create plots dynamically in grid.arrange in R? - r

I have a function get.single.plot, which takes one character argument and returns a ggplot2 plot object. I would like to build a grid.arrange object with n plots on it, where the n is the size of vector of (mentioned) character arguments.
E.g., I woould like something like this to work:
character.argument.vector <- c("12", "1", "2")
grid.arrange(unlist(lapply(character.argument.vector, function(n) get.single.plot(n))),
ncol = 1)
Such thing does not work - I receive the following information:
Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main, :
input must be grobs!
How should I do it?

With gridExtra v>=2.0 you can simply pass a list of grobs (or plots) to grid.arrange,
grid.arrange(grobs = lapply(...), ncol=1)

Related

How can automate this section of grid.arrange function in R

I have a code chunk that looks like this:
p1 <- plotQC(sce_1, type = "highest-expression")
p2 <- plotQC(sce_2, type = "highest-expression")
p3 <- plotQC(sce_3, type = "highest-expression")
p4 <- plotQC(sce_4, type = "highest-expression")
grid.arrange(p1,p2,p3,p4,ncol=2)
This works very well and has no errors or warnings.
I want to put a loop around. What I have done is
for (i in 1:length(paths))
assign(paste0("p",i), plotQC(get(paste0("sce_",i)), type = "highest-expression"))
grid.arrange(p1,p2,p3,p4,ncol=2)
The second chunk also works very well.However, I would like to make grid.arrange work without manually telling it about p1,p2,p3,p4 but it should detect it the number of p objects.
How can I do this? I am working in R markdown.
If you want to keep with your loop, you could also try this:
p.list <- list()
for (i in 1:length(paths)){
p <- plotQC(get(paste0("sce_",i)), type = "highest-expression")
p.list[[i]] <- p
}
cowplot::plot_grid(plotlist = p.list)
Here, instead of assigning the plot, we save it in a list called p.list, then we build your grid from the list. I used plot_grid from cowplot because it accepts a list of plots as an argument, and I find it easier to work with the plot grid overall.
While all this works, I think you'll agree that the following is better as it in no place requires you to repeat any of the lines or manually specify some numbers:
sce <- list(sce_1, sce_2, sce_3, sce_4)
p <- lapply(sce, plotQC, type = "highest-expression")
do.call(grid.arrange, c(p, ncol = 2))
In particular, working with lists is much better in such cases. For this purpose you probably should produce sce_1, ..., sce_4 also differently, as list elements.

plotmath in gridarrange title

I have ggplot plots in a list, say
plts <- list(plt1=qplot(1:10),plt2=qplot(2:3))
which I would like to plot using grid.arrange and a title:
do.call(grid.arrange,c(plts,top='a title'))
The difficulty is I would like some plotmath expressions in that grid.arrange title. If I do
do.call(grid.arrange,c(plts,top=expression('a title[2]') ))
R coerces the second argument to do.call to an expression type rather than list, and do.call throws an error. I tried setting the class manually to "list" but to no avail. What is the proper way to go about this?
according to manual of grid.arrange:
top optional string, or grob
so in oder to use expression, you should provide a grob.
for example, If you want to plot 2 as subscript:
library(grid)
grid.arrange(grobs = plts,top= grid.text(expression('a' ~ title[2])))
# or
do.call(grid.arrange, list(grobs = plts,top = grid.text(expression('a' ~ title[2])) ))

R: gridExtra - How to plot a Summary as table?

I'm having trouble plotting a simple summary.
library(gridExtra)
SummaryTable <- summary(s.tvs$precio.nuevo)
grid.table(SummaryTable)
Gives me this:
I want to achieve something like this:
Upgrade comment:
grid.table calls tableGrob.
grid.table
#function (...)
#grid.draw(tableGrob(...))
#<environment: namespace:gridExtra>
From ?tableGrob its first argument is a matrix or data.frame. t coerces the named vector returned by summary to a matrix with dimension one row. Alternatively, you could of used as.matrix to produce a matrix with one column.
grid.newpage()
grid.table(t(summary(mtcars$mpg)))
grid.newpage()
grid.table(as.matrix(summary(mtcars$mpg)))
From comment:
Question:
I'm trying to plot a barplot and the table generated in this answer. I get: Error in gList(list(grobs = list(list(x = 0.5, y = 0.5, width = 1, height = 1, : only 'grobs' allowed in "gList" when using this code: grid.arrange(a, tbl, ncol = 1)
To combine different tables / plots using grid.arrange they need to be grobs (grid GRaphcal OBjects). So you cannot pass the results from grid.table to grid.arrange as it is not a grob (it actually plots the tableGrob directly). For this you need to pass the tableGrob.
So for example:
mybar <- qplot(mtcars$mpg, geom="bar")
tbl <- tableGrob(t(summary(mtcars$mpg)))
grid.newpage()
grid.arrange(mybar, tbl)

Input must be grobs Error when using do.call()

I am trying to create four parallel coordinate plots into a big figure. Below is just toy data to make it reproducible so it has no particular meaning other than mimicking my real data of meaning.
library(GGally)
library(gridExtra)
library(ggplot2)
cNum=4
x = data.frame(a=2*runif(100)-1,b=2*runif(100)-1,c=2*runif(100)-1,d=2*runif(100)-1,e=2*runif(100)-1)
plot_i = vector("list", length=cNum)
for (i in 1:4){
x = x + i
plot_i[[i]] = ggparcoord(x, columns=1:5, alphaLines=0.5)
do.call("grid.arrange", c(plot_i, ncol=1))
}
Here, it seems that the error occurs on the first iteration of the do.call part. I get an error:
Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main, :
input must be grobs!
I see this is a well-searched Error, although the solution seems to be dependent on the context. For instance, here, the user misused ncol (Error with grid.arrange:input must be grobs) but that does not seem to be my situation.

ggplot2 : printing multiple plots in one page with a loop

I have several subjects for which I need to generate a plot, as I have many subjects I'd like to have several plots in one page rather than one figure for subject.
Here it is what I have done so far:
Read txt file with subjects name
subjs <- scan ("ListSubjs.txt", what = "")
Create a list to hold plot objects
pltList <- list()
for(s in 1:length(subjs))
{
setwd(file.path("C:/Users/", subjs[[s]])) #load subj directory
ifile=paste("Co","data.txt",sep="",collapse=NULL) #Read subj file
dat = read.table(ifile)
dat <- unlist(dat, use.names = FALSE) #make dat usable for ggplot2
df <- data.frame(dat)
pltList[[s]]<- print(ggplot( df, aes(x=dat)) + #save each plot with unique name
geom_histogram(binwidth=.01, colour="cyan", fill="cyan") +
geom_vline(aes(xintercept=0), # Ignore NA values for mean
color="red", linetype="dashed", size=1)+
xlab(paste("Co_data", subjs[[s]] , sep=" ",collapse=NULL)))
}
At this point I can display the single plots for example by
print (pltList[1]) #will print first plot
print(pltList[2]) # will print second plot
I d like to have a solution by which several plots are displayed in the same page, I 've tried something along the lines of previous posts but I don't manage to make it work
for example:
for (p in seq(length(pltList))) {
do.call("grid.arrange", pltList[[p]])
}
gives me the following error
Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main, :
input must be grobs!
I can use more basic graphing features, but I d like to achieve this by using ggplot. Many thanks for consideration
Matilde
Your error comes from indexing a list with [[:
consider
pl = list(qplot(1,1), qplot(2,2))
pl[[1]] returns the first plot, but do.call expects a list of arguments. You could do it with, do.call(grid.arrange, pl[1]) (no error), but that's probably not what you want (it arranges one plot on the page, there's little point in doing that). Presumably you wanted all plots,
grid.arrange(grobs = pl)
or, equivalently,
do.call(grid.arrange, pl)
If you want a selection of this list, use [,
grid.arrange(grobs = pl[1:2])
do.call(grid.arrange, pl[1:2])
Further parameters can be passed trivially with the first syntax; with do.call care must be taken to make sure the list is in the correct form,
grid.arrange(grobs = pl[1:2], ncol=3, top=textGrob("title"))
do.call(grid.arrange, c(pl[1:2], list(ncol=3, top=textGrob("title"))))
library(gridExtra) # for grid.arrange
library(grid)
grid.arrange(pltList[[1]], pltList[[2]], pltList[[3]], pltList[[4]], ncol = 2, main = "Whatever") # say you have 4 plots
OR,
do.call(grid.arrange,pltList)
I wish I had enough reputation to comment instead of answer, but anyway you can use the following solution to get it work.
I would do exactly what you did to get the pltList, then use the multiplot function from this recipe. Note that you will need to specify the number of columns. For example, if you want to plot all plots in the list into two columns, you can do this:
print(multiplot(plotlist=pltList, cols=2))

Resources