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.Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
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) {
y <- attr(f, “sum”)
if (is.null(y)) {
y <- 0
}
y <- x + y
attr(f, “sum”) <<- y
return(y)
}
> for (i in 1:5) cat(i, “: “, f(i), “\n”, sep=“”)
1: 1
2: 3
3: 6
4: 10
5: 15
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)
library(grid)
# setup the ploting grid and plotting sequence
mplot.setup <- function(nrow, ncol, by.row = TRUE) {
attributes(mplot.seq) <<- list(nrow = nrow, ncol = ncol,
pos = 0, by.row = by.row)
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow, ncol)))
}
# plot at given grid location
mplot <- function(graph, row, col) {
print(graph, vp = viewport(layout.pos.row = row,
layout.pos.col = col))
}
# plot the at the next position in the sequence
mplot.seq <- function(graph) {
pos <- attr(mplot.seq, “pos”)
nrow <- attr(mplot.seq, “nrow”)
ncol <- attr(mplot.seq, “ncol”)
if (attr(mplot.seq, “by.row”)) {
col <- 1 + (pos %% ncol)
row <- 1 + ((pos %/% ncol) %% nrow)
} else {
row <- 1 + (pos %% nrow)
col <- 1 + ((pos %/% nrow) %% ncol)
}
attr(mplot.seq, “pos”) <<- pos + 1
mplot(graph, row, col)
}
# application example
mplot.setup(2,4, FALSE)
for (i in 1:4) {
mplot.seq(qplot(iris[,i], xlab = names(iris)[i]))
mplot.seq(qplot(iris[,5], iris[,i], geom = “boxplot”,
xlab = “Species”, ylab = names(iris)[i]) + coord_flip())
}
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.