1
votes

I'm having a hard time plotting an sf point object. Basically I want to show the points with a black border and a fill color according to a variable. In base plot I would do this to impose border color with different background colors:

plot(1:3, cex = 3, pch = 21, col = 'red', bg = c('blue', 'green', 'yellow'), lwd = 2)

I use pch = 21 in order to fill the points with bg colors while using col = 'red' as the point border color.

Using a sf object I can use col to impose the border color but the legend disappears (according to the documentation for plot {sf}, if col is passed to the function the legend is suppressed).

library(sf)
# example
df <- data.frame(est = c('A', 'B', 'C'), 
             long = c(-70, -68, -69), 
             lat = c(-12.2, -12.4, -12), 
             RMSE = c(25, 8, 55)) %>% 
    st_as_sf(coords = c('long', 'lat'), crs = 4326)

# reclassifying the RMSE variable:
df$rmse_cut <- cut(df$RMSE, c(0,15,30,45,60))

# plotting the map
plot(df['rmse_cut'], main = 'RMSE', graticule = TRUE, axes = TRUE, 
bgc = 'gray92', 
pch = 21, lwd = 2, cex = 3,
col = 'black', 
bg = c('blue', 'green', 'yellow'))

But plotting without col:

plot(df['rmse_cut'], main = 'RMSE', graticule = TRUE, axes = TRUE, 
bgc = 'gray92', 
pch = 21, lwd = 2, cex = 3,
bg = c('blue', 'green', 'yellow'))

The borders are sorted by the variable rmse_cut but the background color is fixed. How can I use a single color for point borders while using background colors to show the different values from the rmse_cut variable?.

2
There's probably a more direct route, but you can overplot the points, first plotting the fill, then the strokes (or with different plotting characters). Or just use ggplot, which has solid sf support.alistaire
I'll go with the ggplot2 option but I realize I have many scripts in base R. Perhaps finding a solution to this would save me some time (I think it'll take quite a lot of time to recreate my old plots with ggplot2). Anyway, thank you.noriega

2 Answers

3
votes

Remember base plotting! You need to sort out your palettes so that they are consistent, and then call the palette referenced by the value:

plotpal <- sf.colors(nlevels(df[['rmse_cut']]),categorical=TRUE)
plot(df['rmse_cut'], main = 'RMSE', graticule = TRUE, axes = TRUE, bgc = 'gray92',
     type="n", pal=plotpal, key.pos=1, reset=FALSE)
plot(df[['geometry']], pch = 21, lwd = 2, cex = 3, bg=plotpal[df[['rmse_cut']]], add=TRUE)

enter image description here

1
votes

Forget base plotting, geom_sf() is in the latest CRAN release for ggplot2.

library(ggplot2)

ggplot(df, aes(fill = rmse_cut)) +
  geom_sf(size = 5, color = "black", shape = 21, stroke = 2) +
  coord_sf(ylim = c(-11,-13))

enter image description here

Since your lat values are so tight I expanded the scale a bit manually.