[R-sig-Geo] contour plots with lattice

Martin Ivanov martin.ivanov at ifg.uni-tuebingen.de
Sat Jul 28 13:48:04 CEST 2012


Dear R users,

I need to overlay the plot of one spatial variable with the contours of 
another spatial variable. And I want to do this with lattice.
Here is an example with the meuse.grid data set that comes with the R 
package sp.
First of all, in the classical function "contour" labels are drawn so 
that each contour line is broken at the place of the label,
so that the label does not overlap the line; besides care is taken that 
the labels look good as labels are plotted only for
those closed contours that are large enough for the label - if the 
closed contour is too small, no label is drawn:

library(sp);
library(lattice);
library(latticeExtra);
library(gridBase);
data(meuse.grid);
coordinates(meuse.grid) <- c("x", "y");
pixDF <- as(meuse.grid, "SpatialPixelsDataFrame")["dist"];
zlevs.conts <- zlevs.fill <- seq(0, 1, 0.1);
Z <- matrix(NA, nrow = pixDF at grid@cells.dim[1], ncol = 
pixDF at grid@cells.dim[2]); # convert the SpatialPixelsDataFrame to a matrix
Z[pixDF at grid.index] <- pixDF at data$dist;
Z <- Z[, ncol(Z):1];
contour(Z, levels=zlevs.conts);

In the trellis contourplot the labels are placed beside or over the 
line, controlled by the label.style parameter:
levelplot(Z, contour=TRUE, labels=TRUE, at=zlevs.conts, region=FALSE);
Labels are drawn at every single contour, even at the closed ones that 
are too small and the map looks nasty.

I do not like this and I could not find an option that would place the 
labels just as in the classical contour: breaking the contour line to 
make place for
the label, and with a smart consideration where to place a label and 
where not. I made several posting in the R and r-sig-geo forum on this 
issue,
and I was lucky to receive generous help from Dr. Tim Appelhans from the 
r-sig-geo forum. He wrote a function for me that combines the 
traditional R contour with grid graphics. With his permission am posting 
his function here:

panel.filledcontour <- function(x, y, z, subscripts, at, fill.cont = T,
                                 col.regions,
                                 contours = T,
                                 col = col.regions(length(zlevs.fill)),
                                 ...)
{
   stopifnot(require("gridBase"))
   z <- matrix(z[subscripts],
               nrow = length(unique(x[subscripts])),
               ncol = length(unique(y[subscripts])))
   if (!is.double(z)) storage.mode(z) <- "double"
   opar <- par(no.readonly = TRUE)
   on.exit(par(opar))
   if (panel.number() > 1) par(new = TRUE)
   par(fig = gridFIG(), omi = c(0, 0, 0, 0), mai = c(0, 0, 0, 0))
   cpl <- current.panel.limits()
   plot.window(xlim = cpl$xlim, ylim = cpl$ylim,
               log = "", xaxs = "i", yaxs = "i")
   # paint the color contour regions
   if (isTRUE(fill.cont))
     .Internal(filledcontour(as.double(do.breaks(cpl$xlim,
                                                 nrow(z) - 1)),
                             as.double(do.breaks(cpl$ylim,
                                                 ncol(z) - 1)),
                             z, levels = as.double(zlevs.fill),
                             col = col))
   else NULL

   #add contour lines
   if (isTRUE(contours))
     contour(as.double(do.breaks(cpl$xlim, nrow(z) - 1)),
             as.double(do.breaks(cpl$ylim, ncol(z) - 1)),
             z, levels = as.double(zlevs.conts),
             add=T, col = "grey10", # color of the lines
             drawlabels = T, ...
              # add labels or not
     )
   else NULL

}

Practically this function solves my problem:

plot1 <- spplot(pixDF, at=zlevs.conts);
plot2 <- levelplot(Z, panel = function(fill.cont, contours, ...) {
           panel.filledcontour(fill.cont = F, contours = T, ...) }, 
col.regions = colorRampPalette(c("snow", "lightblue")),
           plot.args = list(newpage = FALSE))

plot.new();print( plot1 + as.layer(plot2));

My data are all spatial, so they are available as spatial objects. 
However, spplot does not seem to be able to overlay
a plot with a contourplot of another spatial variable, it can only 
overlay spatial points, spatial lines, spatial polygons and text (at least
according to the spplot documentation: see the sp.layout argument). That 
is why one has to use levelplot for the second field. But levelplot
does not recognise spatial objects, so one has to convert the spatial 
object to a matrix. So far so good. But if spplot is given xlim and ylim
arguments:

bbx <- bbox(pixDF);
xlim <- c(.999*bbx[1, 1], 1.001*bbx[1, 2]);
ylim <- c(.999*bbx[2, 1], 1.001*bbx[2, 2]);
plot11 <- spplot(pixDF, at=zlevs.conts, xlim=xlim, ylim=ylim);

plot2 <- levelplot(Z, panel = function(fill.cont, contours, ...) {
           panel.filledcontour(fill.cont = F, contours = T, ...) }, 
col.regions = colorRampPalette(c("snow", "lightblue")),
           plot.args = list(newpage = FALSE))

plot.new();print(plot11 + as.layer(plot2))


things go wrong: the second field is plotted in the old scales of 
course, while spplot plots the first field according to the
newly given scales. This can only be solved by converting the matrix of 
the second field appropriately so that it matches the
new scales of the first field. So my problem is in principle over, but 
nevertheless I have 3 questions:

1. Is there a simpler way to achieve the final result I need with 
trellis/grid graphics? Or possibly some not necessarily simpler way, but 
a way
not relying on traditional R graphics, as so long as I know combinig 
traditional and grid graphics does have drawbacks.
2. Is it possible to get the final result with one or two calls to 
spplot, that is, working
only with spatial objects, without having to transform one of the 
objects to a matrix?
3. How can I see the code of spplot? I tried spplot, sp::spplot, 
sp:::spplot, but neither of the commands returned the code.

I am looking forward to Your comments. Any suggestions will be appreciated.
I would again like to thank Dr. Appelhans for his generous help.


Best regards,

-- 
Dr. Martin Ivanov
Eberhard-Karls-Universität Tübingen
Mathematisch-Naturwissenschaftliche Fakultät
Fachbereich Geowissenschaften
Water & Earth System Science (WESS)
Keplerstraße 17, 72074 Tübingen, Deutschland
Tel. +4970712975023



More information about the R-sig-Geo mailing list