I'm trying to get two separate gradients for land and water on a map. I am able to get the water gradient (first figure), but not the land.
How can I set a grey gradient for land in this code (similar to figure 2 below)?
Sample data
library(marmap)
library(ggplot2)
greys <- c(grey(0.6), grey(0.93), grey(0.99))
# Get map data
bat <- getNOAA.bathy(-68, -51, -48, -39, res = 1, keep = TRUE)
Generate Plot with water gradient
autoplot(bat, geom = c("raster", "contour"), colour = "white", size = 0.1) +
scale_fill_gradientn(limits = c(-6600, 0), colors = c("steelblue4", "#C7E0FF")) +
NULL
I have tried setting different limits in scale_fill_gradientn
, but without much luck:
autoplot(bat, geom = c("raster", "contour"), colour = "white", size = 0.1) +
scale_fill_gradientn(limits = c(min(bat), max(bat)),
colors = c("steelblue4", "#C7E0FF", greys)) +
NULL
Desired output (done using base R's plotting functions)
plot(bat, image = TRUE, land = TRUE, lwd = 0.1, bpal = list(c(0, max(bat), greys), c(min(bat), 0, blues)))
plot(bat, lwd = 0.8, deep = 0, shallow = 0, step = 0, add = TRUE) # highlight coastline
cut
and scale_fill_manual
:It's much more involved than @Z.Lin's answer (which I personally would go with), but this method potentially gives you more control, and the geom_raster
plots pretty fast.
I've done it all manually, but you can imagine a function that takes a vector of elevations and a number of desired breaks, then cuts the vector into a set of categorical breaks and makes appropriate labels. This is what sp::spplot()
does by default with continuous fields, and it uses nbreaks = 16
. You'll need to force the zero elevation break to distinguish between land and ocean.
Here's the general idea that can be developed.
# convert to raster, then data frame
library(raster)
d <- as.raster(bat)
d <- as.data.frame(d, xy=TRUE)
# upper and lower elevation bounds
z <- max(d$layer)
a <- min(d$layer)
# breaks and labels for color scale
brks <- c(a, 1000, 500, 0, -500, -1000, -2000, -3000, -4000, -5000, z)
labs <- c("> 1000", "500:1000", "0:500", "-500:0", "-1000:-500", "-2000:-1000",
"-3000:-2000", "-4000:-3000", "-5000:-4000", "< -6514")
d$bin <- cut(d$layer, breaks = brks, labels = labs)
d <- d[!is.na(d$bin), ] # filter sneaky NA values
library(colormap)
gr <- colormap(colormaps$greys, nshades = 10)[4:6]
bl <- colormap(colormaps$velocity_blue, nshades = 13)[3:9]
cols <- c(bl, gr)
# plot
ggplot(d, aes(x, y, fill = bin)) +
geom_raster() +
scale_fill_manual(values = cols, limits = labs, labels = rev(labs)) +
theme_minimal() +
labs(fill = "Elevation (ft)")
Maybe something like this? Range of fill values is obtained from checking summary(fortify.bathy(bat))
for z
's range.
autoplot(bat, geom = c("raster", "contour"), colour = "white", size = 0.1) +
scale_fill_gradientn(values = scales::rescale(c(-6600, 0, 1, 1500)),
colors = c("steelblue4", "#C7E0FF", "grey50", "grey80"))
Note: I used c("grey50", "grey80")
as the range for grey values here, but of course you can change that based on your requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With