gjain
gjain

Reputation: 4518

Plotting multiple graphs in R/ggplot2 and saving the result

I am creating a list of (gg)plot objects and then trying to view all plots in a single graph. From the questions: How can I arrange an arbitrary number of ggplots using grid.arrange?, and How do I arrange a variable list of plots using grid.arrange?, I was hoping that the following code would do the trick (Skip to the last few lines for the code that actually does the multi-plot thing).

#!/usr/bin/Rscript
library(ggplot2)
library(reshape)
library(gridExtra)
args <- commandArgs(TRUE);
# Very first argument is the directory containing modelling results
setwd(args[1])
df = read.table('model_results.txt', header = TRUE)
df_actual = read.table('measured_results.txt', header = TRUE)
dfMerge = merge(df, df_actual, by = c("Clients", "MsgSize", "Connections"))

# All graphs should be stored in the directory pointed by second argument
setwd(args[2])

# Plot the results obtained from model for msgSize = 1, 1999
# and connections = 10, 15, 20, 25, 30, 50

msgSizes = c(1, 1999)
connVals = c(5, 10, 15, 20, 25, 30, 50)

cmp_df = data.frame(dfMerge$Clients, dfMerge$MsgSize, dfMerge$Connections, dfMerge$PThroughput, dfMerge$MThroughput)
colnames(cmp_df) = c("Clients", "MsgSize", "Connections", "ModelThroughput", "MeasuredThroughput")
cmp_df_melt = melt(cmp_df, id = c("Clients", "MsgSize", "Connections"))
colnames(cmp_df_melt) = c("Clients", "MsgSize", "Connections", "Variable", "Value")

plotList = list()
for (i in msgSizes) {
    msg_Subset = subset(cmp_df_melt, MsgSize == i)

    for (j in connVals) {
        plotData = subset(msg_Subset, Connections == j)

        filename = paste("Modelling.",i, ".", j, ".png", sep = '') 
        list_item = ggplot(data = plotData, aes(Clients, y = Value, color = Variable)) +
            geom_point() +
            geom_line() + 
            xlab("Number of Clients") +
            ylab("Throughput (in ops/second)") +
            labs(title = paste("Message Size = ", i, ", Connections = ", j), color = "Legend")

        plotList = c(plotList, list_item)
        # ggsave(file = filename)

    }
}

# Plot all graphs together
pdf("Summary.pdf")
list_len = length(plotList)
nCol = floor(sqrt(list_len))
do.call(grid.arrange, c(plotList, list(ncol = nCol)))
dev.off() 

Instead, I hit the following error:

Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main,  : 
  input must be grobs!
Calls: do.call -> <Anonymous> -> grid.draw -> arrangeGrob
Execution halted

What am I doing wrong, especially since the two linked questions suggest the same thing? Also, what changes should be made to actually save the graph in a file?

Upvotes: 2

Views: 4634

Answers (2)

bdemarest
bdemarest

Reputation: 14667

Here is a minimal, reproducible example of your problem. It reproduces the error message and can be easily run by any interested users by pasting the code into a fresh R session. The error is caused by the unexpected behavior of plot_list = c(plot_list, new_plot).

library(ggplot2)
library(gridExtra)

dat = data.frame(x=1:10, y=1:10)

plot_list = list()
nplot = 3

for (i in seq(nplot)) {
    new_plot = ggplot(dat, aes(x=x, y=y)) +
               geom_point() +
               labs(title=paste("plot", i))
    plot_list = c(plot_list, new_plot)
}

png("plots.png", width=10, height=5, units="in", res=150)
do.call(grid.arrange, c(plot_list, list(ncol=nplot)))
dev.off()
# Error in arrangeGrob(..., as.table = as.table, clip = clip, main = main,  : 
#  input must be grobs!

The error is resolved by wrapping new_plot with list():

plot_list = c(plot_list, list(new_plot))

enter image description here

Upvotes: 5

jlhoward
jlhoward

Reputation: 59355

As others have said, it's impossible to test your code as you do not provide sample data. However, grid.arrange(...) expects a list containing either grobs or ggplot objects. You are providing a list that has some number of ggplot objects, and a numeric. Did you try this?

do.call(grid.arrange, plotlist)    # untested

Upvotes: 4

Related Questions