Skip to content

Commit 58cdd3a

Browse files
committed
Add addRasterLegend, specifically for SpatRaster color table legends
1 parent 3e6fabf commit 58cdd3a

File tree

4 files changed

+136
-9
lines changed

4 files changed

+136
-9
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export(addPolylines)
7676
export(addPopups)
7777
export(addProviderTiles)
7878
export(addRasterImage)
79+
export(addRasterLegend)
7980
export(addRectangles)
8081
export(addScaleBar)
8182
export(addSimpleGraticule)

R/layers.R

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ epsg3857 <- "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y
206206
#' @param x a \code{\link[terra]{SpatRaster}} or a \code{RasterLayer} object--see \code{\link[raster]{raster}}
207207
#' @param colors the color palette (see \code{\link{colorNumeric}}) or function
208208
#' to use to color the raster values (hint: if providing a function, set
209-
#' \code{na.color} to \code{"#00000000"} to make \code{NA} areas transparent).
210-
#' The palette is ignored if \code{x} is a SpatRaster with a color table or if
209+
#' \code{na.color} to \code{"#00000000"} to make \code{NA} areas transparent).
210+
#' The palette is ignored if \code{x} is a SpatRaster with a color table or if
211211
#' it has RGB channels.
212212
#' @param opacity the base opacity of the raster, expressed from 0 to 1
213213
#' @param attribution the HTML string to show as the attribution for this layer
@@ -227,15 +227,20 @@ epsg3857 <- "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y
227227
#' (before base64 encoding); defaults to 4MB.
228228
#' @template data-getMapData
229229
#'
230+
#' @seealso \code{\link{addRasterLegend}} for an easy way to add a legend for a
231+
#' SpatRaster with a color table.
232+
#'
230233
#' @examples
231234
#' \donttest{library(raster)
232235
#'
233236
#' r <- raster(xmn = -2.8, xmx = -2.79, ymn = 54.04, ymx = 54.05, nrows = 30, ncols = 30)
234237
#' values(r) <- matrix(1:900, nrow(r), ncol(r), byrow = TRUE)
235238
#' crs(r) <- CRS("+init=epsg:4326")
236239
#'
240+
#' pal <- colorNumeric("Spectral", domain = c(0, 1000))
237241
#' leaflet() %>% addTiles() %>%
238-
#' addRasterImage(r, colors = "Spectral", opacity = 0.8)
242+
#' addRasterImage(r, colors = pal, opacity = 0.8) %>%
243+
#' addLegend(pal = pal, values = c(0, 1000))
239244
#' }
240245
#' @export
241246
addRasterImage <- function(
@@ -285,6 +290,76 @@ addRasterImage <- function(
285290
}
286291

287292

293+
#' Add a color legend for a SpatRaster to a map
294+
#'
295+
#' A function for adding a [legend][addLegend()] that is specifically designed
296+
#' for [terra::SpatRaster] objects, with categorical values, that carry their
297+
#' own [color table][terra::coltab()].
298+
#'
299+
#' @param map a map widget object
300+
#' @param x a [SpatRaster][terra::SpatRaster] object with a color table
301+
#' @param layer the layer of the raster to target
302+
#' @param ... additional arguments to pass through to [addLegend()]
303+
#' @seealso [addRasterImage()]
304+
#' @examples
305+
#'
306+
#' library(terra)
307+
#'
308+
#' r <- rast("/vsicurl/https://geodata.ucdavis.edu/test/pr_nlcd.tif")
309+
#' leaflet() |>
310+
#' addTiles() |>
311+
#' addRasterImage(r, opacity = 0.75) |>
312+
#' addRasterLegend(r, opacity = 0.75)
313+
#'
314+
#' plot.new() # pause in interactive mode
315+
#'
316+
#' rr <- r
317+
#' levels(rr) <- NULL
318+
#' leaflet() |>
319+
#' addTiles() |>
320+
#' addRasterImage(rr, opacity = 0.75) |>
321+
#' addRasterLegend(rr, opacity = 0.75)
322+
#'
323+
#' @md
324+
#' @export
325+
addRasterLegend <- function(map, x, layer = 1, ...) {
326+
stopifnot(inherits(x, "SpatRaster"))
327+
stopifnot(length(layer) == 1 && layer > 0 && layer <= terra::nlyr(x))
328+
329+
# Retrieve the color table from the layer. If one doesn't exist, that means
330+
# the raster was colored some other way, like using colorFactor or something,
331+
# and the regular addLegend() is designed for those cases.
332+
ct <- terra::coltab(x)[[layer]]
333+
if (is.null(ct)) {
334+
stop("addRasterLegend() can only be used on layers with color tables (see ?terra::coltab). Otherwise, use addLegend().")
335+
}
336+
337+
# Create a data frame that has value and color columns
338+
# Extract the colors in #RRGGBBAA format
339+
color_info <- data.frame(
340+
value = ct[[1]],
341+
color = grDevices::rgb(ct$red/255, ct$green/255, ct$blue/255, ct$alpha/255)
342+
)
343+
344+
lvls <- terra::levels(x)[[layer]]
345+
346+
res <- if (is.data.frame(lvls)) {
347+
# Use the labels from levels(x), and look up the matching colors in the
348+
# color table
349+
colnames(lvls) <- c("value", "label")
350+
base::merge(color_info, lvls, by.x = "value", by.y = 1)
351+
} else {
352+
cbind(color_info, label = color_info$value)
353+
}
354+
355+
# Drop values that aren't part of the layer
356+
res <- res[res[["value"]] %in% terra::values(x),]
357+
358+
addLegend(map, colors = res[["color"]], labels = res[["label"]], ...)
359+
}
360+
361+
362+
288363
addRasterImage_RasterLayer <- function(
289364
map,
290365
x,
@@ -382,11 +457,11 @@ addRasterImage_SpatRaster <- function(
382457
}
383458

384459
raster_is_factor <- terra::is.factor(x)
385-
460+
386461
# there 1.5-50 has terra::has.colors(x)
387462
ctab <- terra::coltab(x)[[1]]
388463
has_colors <- !is.null(ctab)
389-
464+
390465
method <- match.arg(method)
391466
if (method == "ngb") method = "near"
392467
if (method == "auto") {
@@ -426,7 +501,7 @@ addRasterImage_SpatRaster <- function(
426501
if (has_colors) {
427502
colors <- rgb(ctab[,2], ctab[,3], ctab[,4], ctab[,5], maxColorValue=255)
428503
domain <- ctab[,1]
429-
}
504+
}
430505
colors <- colorFactor(colors, domain = domain, na.color = "#00000000", alpha = TRUE)
431506
} else {
432507
# 'numeric'

man/addRasterImage.Rd

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/addRasterLegend.Rd

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)