Site icon R-bloggers

Emulating local static variables in R

[This article was first published on R snippets, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Recently I was writing a code allowing to plot multiple ggplot2 plots on one page. I wanted to replicate standard behavior of  plot  function that plots graphs in sequence according to  mfrow/ mfcol option in par. The solution lead me to think of emulating C-like local static variables in R.
There are several solutions to this problem but I think that a nice one is by adding attributes to a function. Here is a simple example:

f <- function(x) {< o:p>
    y <- attr(f, “sum”)< o:p>
    if (is.null(y)) {< o:p>
        y <- 0< o:p>
    }< o:p>
    y <- x + y< o:p>
    attr(f, “sum”) <<- y< o:p>
    return(y)< o:p>
}< o:p>

It can be applied as follows:

> for (in 1:5) cat(i, “: “, f(i)“\n”, sep=“”)
1: 1< o:p>
2: 3< o:p>
3: 6< o:p>
4: 10< o:p>
5: 15< o:p>

As it can be seen attribute “sum” is static but it can be thought of as local because it is not stored directly as a variable in global environment.

And here is the application of the concept to the problem of plotting several qplots in a sequence:

library(ggplot2)< o:p>
library(grid)< o:p>

# setup the ploting grid and plotting sequence< o:p>
mplot.setup <- function(nrow, ncol, by.row = TRUE) {< o:p>
    attributes(mplot.seq) <<- list(nrow = nrow, ncol = ncol,< o:p>
      pos = 0, by.row = by.row)< o:p>
    grid.newpage()< o:p>
    pushViewport(viewport(layout = grid.layout(nrow, ncol)))< o:p>
}   < o:p>

# plot at given grid location< o:p>
mplot <- function(graph, row, col) {< o:p>
     print(graph, vp = viewport(layout.pos.row = row,< o:p>
                                layout.pos.col = col))< o:p>
}< o:p>

# plot the at the next position in the sequence< o:p>
mplot.seq <- function(graph) {< o:p>
    pos <- attr(mplot.seq, “pos”)< o:p>
    nrow <- attr(mplot.seq, “nrow”)< o:p>
    ncol <- attr(mplot.seq, “ncol”)< o:p>

    if (attr(mplot.seq, “by.row”)) {< o:p>
        col <- 1 + (pos %% ncol)< o:p>
        row <- 1 + ((pos %/% ncol) %% nrow)< o:p>
    } else {< o:p>
        row <- 1 + (pos %% nrow)< o:p>
        col <- 1 + ((pos %/% nrow) %% ncol)< o:p>
    }< o:p>
    attr(mplot.seq, “pos”) <<- pos + 1< o:p>
    mplot(graph, row, col)< o:p>
}< o:p>

# application example< o:p>
mplot.setup(2,4, FALSE)< o:p>
for (i in 1:4) {< o:p>
  mplot.seq(qplot(iris[,i], xlab = names(iris)[i]))< o:p>
  mplot.seq(qplot(iris[,5], iris[,i], geom = “boxplot”,< o:p>
    xlab = “Species”, ylab = names(iris)[i]) + coord_flip())< o:p>
}

The following plot is produced by the above code:


To leave a comment for the author, please follow the link and comment on their blog: R snippets.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.