1

I'd like to use ggplot to plot a series of graphs and then stack them using grid.arrange. The problem is that ggplot doesn't "use" the data supplied until grid.arrange is called, which forces me to store the data in .GlobalEnv, and I can't figure out how to avoid conflicting names. To illustrate with an MWE:

library(ggplot2)
library(gridExtra)

plot.one.graph <- function(data)
{
    p <- ggplot(data, aes(x = category, y = value))
    p <- p + geom_bar(alpha = 0.5, stat = "identity")

    se.minus <- data$value - 1  # fake error bar
    se.plus <- data$value + 1
    assign("se.minus", se.minus, globalenv())
    assign("se.plus", se.plus, globalenv())
    p <- p + geom_errorbar(aes(ymin = se.minus, ymax = se.plus))

    return(p)
}

data.list <- list(  data.frame(category = 1:10, value = rnorm(10, 5)),
                    data.frame(category = 1:10, value = rpois(10, 5)))

ps <- list()
for (i in 1:len(data.list)) {
    ps[[i]] <- plot.one.graph(data.list[[i]])
}
grid.arrange(ps[[1]], ps[[2]])

Here I have two data.frame's and I want to plot them one on top of another. The output looks like this output. Because the latter loop overwrites the (fake) error bar data for the first loop, the error bars were correct for the second graph but wrong for the first. I have tried various ways of storing the variable in .GlobalEnv but nothing seems to work. Any suggestions?

1
  • Side notes: 1:len(data.list) should probably be 1:length(data.list) or even seq_along(data.list) and ps <- list() would be better as ps <- vector("list", length(data.list)). Commented Jan 4, 2015 at 9:01

1 Answer 1

2

You can return a built grob from the plot function, thus avoiding the need for .GlobalEnv:

library(ggplot2)
library(gridExtra)

plot.one.graph <- function(data) {

    p <- ggplot(data, aes(x = category, y = value))
    p <- p + geom_bar(alpha = 0.5, stat = "identity")

    data$ymin <- data$value - 1
    data$ymax <- data$value + 1

    p <- p + geom_errorbar(data=data, 
                           aes(ymin = ymin, ymax = ymax))

    p <- p + ylim(0,11)

    return(ggplotGrob(p))

}

set.seed(1492)
data.list <- list(data.frame(category = 1:10, value = rnorm(10, 5)),
                  data.frame(category = 1:10, value = rpois(10, 5)))

ps <- lapply(data.list, plot.one.graph)

do.call(grid.arrange, c(ps, ncol=2))

enter image description here

I added a set.seed so you'll get the same results on your system. Also, I changed the loop for how the plots are generated and used do.call to do the final render. I only did a horizontal layout and added a ylim so it was easier to see that the error bars were, in fact, different.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.