Custom placement of spplot legend in the map
Asked Answered
I

2

8

Is it possible to place the spplot (spplot polygons) legend within the map, in lower left corner, like this?

enter image description here

The closest I've been able to get is this (I am not posting my data, I just use the example data instead, so in this case, try to place the legend in top left part of the map):

data(meuse.grid)
gridded(meuse.grid)=~x+y
spplot(meuse.grid[,'dist'],
    colorkey = list(space = "left", height = 0.5)
)

But the legend is in the middle of the page and is outside of the map. Unfortunatelly, colorkey argument doesn't support "bottomleft", or x, y, or corner arguments (see ?levelplot). I also tried to use key.space argument, but it seems to only work when plotting SpatialPoints* but it seems ignored for SpatialPolygons* (or SpatialPixelsDataFrame like in the example above).

Illusionary answered 30/3, 2015 at 11:11 Comment(0)
M
10

Since the key is a grob of its own it is perfectly possible to extract it from the plot object and draw it separately where ever you please.

library(grid)

#  Separate plot and key
s <- spplot(meuse.grid[,'dist'],
    colorkey = list(space = "left", height = 0.5)
)
key <- draw.colorkey(s$legend[[1]]$args$key)
s$legend <- NULL # Otherwise we'd get two keys

# Modify key
key$framevp$x <- unit(0.15, "npc")
key$framevp$y <- unit(0.68, "npc")

# Plot
s
grid.draw(key)

enter image description here

Meredeth answered 30/3, 2015 at 12:59 Comment(4)
Not at all, glad you like it! It's a bit of a hack though since it defines the position of the key by its center relative to the plot area size, causing it to drift out of place if the figure is rescaled. A better solution would be to define the position by the top-left corner with an absolute distance to the plot area border, but I don't know how to do that unfortunately.Meredeth
Thanks Backlin!! I wanted to ask you exactly about this - the positioning relative to the topleft corner. Isn't there some possiblity like the corner argument of key.space?Illusionary
I can't see anything like the corner argument in the code of draw.colorkey(), which is why I decided to create and plot the key separately. The location is then decided by key$framevp which is a grid viewport. I am sure there is a proper way to position it but I still find them quite confusing to work with.Meredeth
@Meredeth -- Just posted a solution, inspired by your answer, that fixes the colorkey in position so that it doesn't drift as the figure is rescaled. It also sidesteps the lower level hacking of viewport arguments by passing in the arguments and instruction to call draw.colorkey() via spplot()'s "legend=" argument.Bosley
F
7

The complicating issue here is that, although the colorkey= argument is treated very much like the legend= argument, it doesn't quite support the full suite of positioning options that legend= does. Whereas legends can be directly placed at "left", "right", "top", "bottom", and "inside" the plot, colorkey= only supports the first four of those.

A fairly clean workaround is to extract the colorkey argument list prepared by one call to spplot(), and to pass that in to a second spplot() call via its legend= argument. colorkey= "knows" how to prepare a colorkey object, and legend= knows how to draw arbitrary objects inside of plots, so we can combine the two to get what we want:

library(sp)
library(grid)
library(lattice)
data(meuse.grid)
gridded(meuse.grid)=~x+y

## Call spplot() once as a way to construct a list of arguments
## to draw.color.key
SP <- spplot(meuse.grid[,'dist'],
    colorkey = list(space = "left", height = 0.4)
)
args <- SP$legend$left$args$key

## Prepare list of arguments needed by `legend=` argument (as described in ?xyplot)
legendArgs <- list(fun = draw.colorkey,
                   args = list(key = args),
                   corner = c(0.05,.75))

## Call spplot() again, this time passing in to legend the arguments
## needed to print a color key
spplot(meuse.grid[,'dist'], colorkey = FALSE,
       legend = list(inside = legendArgs))

enter image description here

Note: colorkey='s lack of support for an "inside" option appears to be less a design choice than just a matter of the package authors' not yet having gotten around to implementing the requisite code. As evidence of that, see the documentation for colorkey= in ?lattice::levelplot (to which one is directed by `?sp::spplot):

colorkey: logical specifying whether a color key is to be drawn
          alongside the plot, or a list describing the color key. The
          list may contain the following components:

          ‘space’: location of the colorkey, can be one of ‘"left"’,
              ‘"right"’, ‘"top"’ and ‘"bottom"’.  Defaults to
              ‘"right"’.

          ‘x’, ‘y’: location, currently unused

          ‘corner’: Interacts with x, y; currently unimplemented
Fume answered 3/4, 2015 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.