Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
In a previous post, I showed how to keep text and symbols at the same size across figures that have different numbers of panels. The figures in that post were ugly because they used the default panel spacing associated with the mfrow argument of the par( ) function. Below I will walk through how to adjust the spacing of the panels when using mfrow.
For this example, we will use Edgar Anderson’s iris data, which is distributed with R. The data set includes flower measurements for 3 iris species. In this case, the data would be more effectively plotted in a single panel with different colors or symbols for each species, but with larger data sets the different colors/symbols can create a jumbled mess and multi-panel figures illustrate patterns in the data more clearly.
To plot all the data on the same scale, we need to extract the max and min values of the variables that we are plotting.
min.width = min(iris$Sepal.Width) min.length = min(iris$Sepal.Length) max.width = max(iris$Sepal.Width) max.length = max(iris$Sepal.Length)
The next block of code plots 3 panels in a 2×2 arrangement with mostly default options. [Note: The optimal way to plot this data in a multi-panel figure is a 3×1 arrangement, but using the 2×2 arrangement provides a better illustration of how mfrow works.] An empty panel is created by calling plot.new( ). The empty panel can be placed in any of the 4 positions, but it is redundant to use plot.new( ) for the bottom right panel because mfrow fills the graphics device by row, moving left to right along the row. I am writing to the PNG graphics device to post the figures online; using a different graphics device (e.g., TIFF) might require adjustments to the arguments that control the panel spacing.
png(filename="PanelFigure1.png",width=4,height=4,units="in",res=150) par(mfrow=c(2,2), tcl=-0.5, family="serif") # Top left panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="virginica"), xlab="Sepal Width", ylab="Sepal Length", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) # Top right panel plot.new() # Bottom left panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="versicolor"), xlab="Sepal Width", ylab="Sepal Length", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) # Bottom right panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="setosa"), xlab="Sepal Width", ylab="Sepal Length", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) dev.off()
png(filename="PanelFigure2.png",width=4,height=4,units="in",res=150) par(mfrow=c(2,2), tcl=-0.5, family="serif", mai=c(0.3,0.3,0.3,0.3)) # Top left panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="virginica"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) # Top right panel plot.new() # Bottom left panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="versicolor"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) # Bottom right panel plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="setosa"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) dev.off()
png(filename="PanelFigure3.png",width=4,height=4,units="in",res=150) par(mfrow=c(2,2), tcl=-0.5, family="serif") # Top left panel par(mai=c(0.2,0.4,0.2,0)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="virginica"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length), xaxt="n") axis(1, labels=F) # Top right panel plot.new() # Bottom left panel par(mai=c(0.4,0.4,0,0)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="versicolor"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length)) # Bottom right panel par(mai=c(0.4,0.2,0,0.2)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="setosa"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length), yaxt="n") axis(2, labels=F) dev.off()
png(filename="PanelFigure4.png",width=4,height=4,units="in",res=150) par(mfrow=c(2,2), tcl=-0.5, family="serif", omi=c(0.2,0.2,0,0)) # Top left panel par(mai=c(0.2,0.4,0.2,0)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="virginica"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length<strong>+0.15</strong>), xaxt="n", <strong>bty="n"</strong>) axis(1, labels=F) text((max.width-min.width)/2 + min.width, max.length+0.15, expression(italic("Iris virginica"))) # Top right panel plot.new() # Bottom left panel par(mai=c(0.4,0.4,0,0)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="versicolor"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length<strong>+0.15</strong>),<strong> bty="n"</strong>) text((max.width-min.width)/2 + min.width, max.length+0.15, expression(italic("Iris versicolor"))) # Bottom right panel par(mai=c(0.4,0.2,0,0.2)) plot(Sepal.Length~Sepal.Width, data=iris, subset=(Species=="setosa"), xlab=" ", ylab=" ", xlim=c(min.width,max.width), ylim=c(min.length,max.length<strong>+0.15</strong>), yaxt="n", <strong>bty="n"</strong>) axis(2, labels=F) text((max.width-min.width)/2 + min.width, max.length+0.15, expression(italic("Iris setosa"))) mtext("Sepal Width", side=1, outer=T, at=0.5) mtext("Sepal Length", side=2, outer=T, at=0.5) dev.off()
Lastly, I want to point out how useful the lattice package is for quickly generating multi-panel figures with grouped data. As in the R base package, the default is not publication quality, but it requires a lot less code to generate a multi-panel figure that is at least easily readable.
library(lattice) xyplot(Sepal.Length~Sepal.Width|Species,data=iris)
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.