Reputation: 7435
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
Upvotes: 4
Views: 1094
Reputation: 8392
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)")
Upvotes: 5
Reputation: 29085
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.
Upvotes: 2