r-tmap / tmap

R package for thematic maps
https://r-tmap.github.io/tmap
GNU General Public License v3.0
858 stars 119 forks source link

Adding continuous raster legend when raster contains only NA #937

Open johnbaums opened 4 days ago

johnbaums commented 4 days ago

Is it possible to force a continuous raster legend to display when the raster layer contains no non-NA values? Or else to manually add a continuous raster legend?

Consider the following example, where a list of tmap objects describes a temporally varying attribute. Note that in the first time step, the entire raster has value NA - this results in a map with no legend. For animation, and even just for consistency of map layout, having a consistent legend is obviously important.

One workaround is to give one cell a value, e.g. with r0[1] <- 0, but I would prefer not to modify cell values.

library(tmap)
#> 
#> Attaching package: 'tmap'
#> The following object is masked from 'package:datasets':
#> 
#>     rivers
library(terra)
#> terra 1.7.78
r1 <- setNames(rast(land)[[4]], "t1")
r0 <- setNames(init(r1, NA), "t0")
r2 <- setNames(r1 * 1.3, "t2")
r <- list(r0, r1, r2)
zlim <- range(sapply(r, global, "range", na.rm = TRUE), na.rm = TRUE)

L <- lapply(r, function(x) {
  tm_shape(x) + 
    tm_raster(
      col.scale = tm_scale_continuous(values = terrain.colors(9), limits = zlim), 
      col.legend = tm_legend(title = "Elevation")
    ) +
    tm_shape(World) +
    tm_polygons(fill = NA) +
    tm_title(names(x))
})

L
#> [[1]]

#> 
#> [[2]]

#> 
#> [[3]]

Created on 2024-09-24 with reprex v2.1.1

Session info ``` r sessionInfo() #> R version 4.4.1 (2024-06-14) #> Platform: x86_64-apple-darwin20 #> Running under: macOS Sonoma 14.6.1 #> #> Matrix products: default #> BLAS: /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRblas.0.dylib #> LAPACK: /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0 #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] terra_1.7-78 tmap_3.99.9002 #> #> loaded via a namespace (and not attached): #> [1] s2_1.1.7 xml2_1.3.6 class_7.3-22 #> [4] lwgeom_0.2-14 KernSmooth_2.23-24 lattice_0.22-6 #> [7] digest_0.6.37 magrittr_2.0.3 evaluate_1.0.0 #> [10] grid_4.4.1 RColorBrewer_1.1-3 fastmap_1.2.0 #> [13] e1071_1.7-16 leafsync_0.1.0 DBI_1.2.3 #> [16] colorblindcheck_1.0.2 crosstalk_1.2.1 viridisLite_0.4.2 #> [19] cols4all_0.7-1 XML_3.99-0.17 codetools_0.2-20 #> [22] abind_1.4-8 cli_3.6.3 rlang_1.1.4 #> [25] units_0.8-5 tmaptools_3.1-1 reprex_2.1.1 #> [28] base64enc_0.1-3 withr_3.0.1 yaml_2.3.10 #> [31] leaflegend_1.2.1 tools_4.4.1 raster_3.6-26 #> [34] parallel_4.4.1 colorspace_2.1-1 spacesXYZ_1.3-0 #> [37] widgetframe_0.3.1 curl_5.2.2 R6_2.5.1 #> [40] png_0.1-8 proxy_0.4-27 lifecycle_1.0.4 #> [43] classInt_0.4-10 leaflet_2.2.2 leaflet.providers_2.0.0 #> [46] fs_1.6.4 htmlwidgets_1.6.4 data.table_1.16.0 #> [49] glue_1.7.0 Rcpp_1.0.13 sf_1.0-17 #> [52] highr_0.11 xfun_0.47 knitr_1.48 #> [55] dichromat_2.0-0.1 htmltools_0.5.8.1 rmarkdown_2.28 #> [58] leafem_0.2.3 wk_0.9.3 compiler_4.4.1 #> [61] sp_2.1-4 stars_0.6-6 ```
mtennekes commented 3 days ago

Thx @johnbaums

This was a bug that now has been fixed: when the user provides a tm_scale function for a layer with all NA's, it will now show a legend, provided the essential information is there (limits for tm_scale_continuous and breaks for tm_scale_intervals).

However, you can make these series of plots in one go:

rs = c(r0, r1, r2)

tm_shape(rs) + 
  tm_raster(
  col.scale = tm_scale_continuous(values = terrain.colors(9), limits = zlim), 
  col.legend = tm_legend(title = "Elevation")
  ) +
  tm_shape(World) +
  tm_polygons(fill = NA) +
  tm_facets_pagewise()

The only current limitation is that is uses panels rather than outside titles. But that is for another issue;-)