Custom placement of spplot legend in the map

2020-03-14 04:34发布

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).

2条回答
对你真心纯属浪费
2楼-- · 2020-03-14 04:51

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
查看更多
够拽才男人
3楼-- · 2020-03-14 05:06

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

查看更多
登录 后发表回答