Using R: a function that adds multiple ggplot2 layers
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Another interesting thing that an R course participant identified: Sometimes one wants to make a function that returns multiple layers to be added to a ggplot2 plot. One could think that just adding them and returning would work, but it doesn’t. I think it has to do with how + is evaluated. There are a few workarounds that achieve similar results and may save typing.
First, some data to play with: this is a built-in dataset of chickens growing:
library(ggplot2) data(ChickWeight) diet1 <- subset(ChickWeight, Diet == 1) diet2 <- subset(ChickWeight, Diet == 2)
This is just an example that shows the phenomenon. The first two functions will work, but combining them won’t.
add_line <- function(df) { geom_line(aes(x = Time, y = weight, group = Chick), data = df) } add_points <- function(df) { geom_point(aes(x = Time, y = weight), data = df) } add_line_points <- function(df) { add_line(df) + add_points(df) } ## works (plot1 <- ggplot() + add_line(diet1) + add_points(diet1)) ## won't work: non-numeric argument to binary operator try((plot2 <- ggplot() + add_line_points(diet1)))
First, you can get the same result by putting mappings and data in the ggplot function. This will work if all layers are going to plot the same data, but that does it for some cases:
## bypasses the issue by putting mappings in ggplot() (plot3 <- ggplot(aes(x = Time, y = weight, group = Chick), data = diet1) + geom_line() + geom_point())
One way is to write a function that takes the plot object as input, and returns a modified version of it. If we use the pipe operator %>%, found in the magrittr package, it even gets a ggplot2 like feel:
## bypasses the issue and gives a similar feel with pipes library(magrittr) add_line_points2 <- function(plot, df, ...) { plot + geom_line(aes(x = Time, y = weight, group = Chick), ..., data = df) + geom_point(aes(x = Time, y = weight), ..., data = df) } (plot4 <- ggplot() %>% add_line_points2(diet1) %>% add_line_points2(diet2, colour = "red"))
Finally, in many cases, one can stick all the data in a combined data frame, and avoid building up the plot from different data frames altogether.
## plot the whole dataset at once (plot5 <- ggplot(aes(x = Time, y = weight, group = Chick, colour = Diet), data = ChickWeight) + geom_line() + geom_point())
Okay, maybe that plot is a bit too busy to be good. But note how the difference between plotting a single diet and all diets at the same time one more mapping in aes(). No looping or custom functions required.
I hope that was of some use.
Postat i:computer stuff, data analysis Tagged: ggplot2, R
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.