# Consistent levelplot size in R

I'm using the R package 'rastervis' to create a number of multi-plot figures. I'm continually running into alignment issues which I believe are the result of rounding in the plot legends. For example, a plot in which values are rounded to 3 decimal places will be shifted compared to those rounded to just two decimal places. Similarly, if two plots are rounded to 2 d.p. but one has minus values, this will also change the alignment of the plot (presumably because the '-' sign is taking up space within the plot).

I have attached an image of this misalignment and ask whether there is a simple argument which I haven't invoked which will fix the problem. After many search attempts I've been unable to find a solution. I've included some very low-tech red lines on this diagram to show how the plots are misaligned given legends with varying numbers of characters:

I would (ideally) like all plots to be left justified and to be the same width. This would hopefully align the legends too. All of the misalignment I'm experiencing really needs to be pushed to the whitespace on the right of the plot.

Here is a very quickly photo-shopped mock up of the intended result. Note how all plots and legends are aligned with any differences in whitespace given to the right of the plot window. I've done nothing to this image except shift the plots manually either left or right by a few pixels such that they align(i.e. I haven't resized the individual plots, I've just moved them slightly).

Here is a minimum reproducible example. The misalignment isn't quite as severe as my real-world example shown in the images but it is still apparent.

library(raster)
library(rasterVis)

r1 <- raster(nrow=18, ncol=36)
r1[] <- runif(ncell(r1)) * 10
r2 <- raster(nrow=18, ncol=36)
r2[] <- runif(ncell(r1)) * 2.345
r3 <- raster(nrow=18, ncol=36)
r3[] <- runif(ncell(r1)) * -4

p1 <- levelplot(r1, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE))
p2 <- levelplot(r2, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE))
p3 <- levelplot(r3, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE))

print(p,  split=c(1, 1, 1, 3), more=TRUE)
print(p2, split=c(1, 2, 1, 3), more=TRUE)
print(p3, split=c(1, 3, 1, 3))

• its rasterVis with an upper-case V isn't it? – Spacedman Apr 16 '18 at 17:31
• Are you hitched to levelplot? Doing par(mfrow=c(3,1));plot(r1);plot(r2);plot(r3) gives you three aligned plots with individual colour schemes and legends. – Spacedman Apr 17 '18 at 7:14
• Thanks for the reply. I'm not hitched to rasterVis, no. I'm currently using it because it's easy to implement colourblind-safe palettes with this package. I've always found base raster graphics to be a bit of a faff! – Simon Apr 17 '18 at 8:16
• For plotting rasters with base plot, add col=somevectorofcolours, eg col=pals::plasma(10) (and install pals package, its ace). – Spacedman Apr 17 '18 at 9:41

Steer the levelplot parameters at and colorkey. This solution is something of a workaround.

Fetch the minimum and maximum value across all your data, and perform floor / ceiling on these.

scaleMin <- floor(min(c(r1@data@values,r2@data@values,r3@data@values)))
scaleMax <- ceiling(max(c(r1@data@values,r2@data@values,r3@data@values)))


Set a number of desired breaks, and generate a sequence of universal breaks where effectively all values will be contained in your different levelplots.

numberOfBreaks <- 6
brksUniv <- seq(scaleMin,scaleMax, length.out=numberOfBreaks)


At this point a central step borrowed from the approach in this answer (Christopher Stephan 2017), is performed. Define at and colorkey. Finally, generate and print the plots with these information included.

myColorkey <- list(at=brksUniv, labels=list(at=brksUniv, labels=round(brksUniv,1)))
p1Univ <- levelplot(r1, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE), at=brksUniv, colorkey=myColorkey)
p2Univ <- levelplot(r2, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE), at=brksUniv, colorkey=myColorkey)
p3Univ <- levelplot(r3, margin=FALSE, xlab=NULL, ylab=NULL,scales=list(draw=FALSE), at=brksUniv, colorkey=myColorkey)

print(p1Univ, split=c(1, 1, 1, 3), more=TRUE)
print(p2Univ, split=c(1, 2, 1, 3), more=TRUE)
print(p3Univ, split=c(1, 3, 1, 3))


• If you are going to do that you may as well do levelplot(stack(r1,r2,r3)). And if the data covers several orders of magnitude this won't work at all well. – Spacedman Apr 17 '18 at 7:12
• Thanks for the detailed reply. However the scale in my 'real' example spans two orders of magnitude; I do need different legends for each plot otherwise the top and middle plots will be unreadable compared to the middle plot. – Simon Apr 17 '18 at 8:18