paleolimbot / ggspatial

Enhancing spatial visualization in ggplot2
https://paleolimbot.github.io/ggspatial
372 stars 35 forks source link

How to create a discrete scale legend from a RasterLayer object #99

Open dpabon opened 2 years ago

dpabon commented 2 years ago

I would like to create a discrete scale legend from a RasterLayer object that contains numbers from 1 to 4 (1,2,3,4) where each number represents a different category. Is there an easy way to do it? I could not find an example of maps with discrete classes on ggspatial documentation. The closest that I got was using scale_fill_stepsn ... but still I cannot assign a specific color for each number, here is an example:

ggplot()+
  layer_spatial(map.4categories.raster.moll) +
  scale_fill_stepsn(colours = c("#CABCCE", "#B33D50","#3D84BD", "#432D4A"), na.value = NA, 
                              trans = "identity", limits = c(0,4), breaks = c(1.5, 2.5, 3.5)) +
  layer_spatial(coast.moll) +
  cowplot::theme_minimal_grid()
paleolimbot commented 2 years ago

I think you can do it! It's hard to repeat your example without the rest of the code, but perhaps this example will help:

library(ggplot2)
library(ggspatial)
load_longlake_data()
#> Warning: multiple methods tables found for 'direction'
#> Warning: multiple methods tables found for 'gridDistance'

raster_cat <- round(longlake_depth_raster)

ggplot() +
  layer_spatial(
    raster_cat, 
    aes(fill = as.factor(stat(band1)))
  ) +
  scale_fill_manual(
    breaks = c(0, 1, 2),
    values = c("red", "green", "blue")
  )

Created on 2022-02-01 by the reprex package (v2.0.1)

dpabon commented 2 years ago

Thanks for the help!

Sorry if I didn't provide a clear example, I found out that the problem is related with the projection used in the raster object. Here is an example of this problem with the rasters used: raster_longlat_and_mollweide.zip

library(ggplot2)
library(ggspatial)
library(raster)

map_long_lat <- raster("4_categories_map_long_lat.tif")

map_moll <- raster("4_categories_map_mollweide.tif")

# plotting lon lat projection

ggmap <- ggplot() +
  layer_spatial(map_long_lat,
                aes(fill = as.factor(stat(band1)))) +
  scale_fill_manual(values = c("#CABCCE", "#B33D50","#3D84BD", "#432D4A"), 
                    na.value = NA, 
                    breaks = c("1", "2", "3", "4"))
ggmap

image

# plotting mollweide projection

ggmap <- ggplot() +
  layer_spatial(map_moll, 
                aes(fill = as.factor(stat(band1))))

# WARNING: trying to visualize the plot on Rstudio produce a crash
#ggmap

# Saving the plot takes a couple of minutes
ggsave("~/Downloads/test.png", ggmap, width = 80, height = 40, units = "cm")

test

Applying the manual scale to the plot:

ggmap <- ggplot() +
  layer_spatial(map_moll, 
                aes(fill = as.factor(stat(band1)))) +
  scale_fill_manual(values = c("#CABCCE", "#B33D50","#3D84BD", "#432D4A"), 
                    na.value = NA, 
                    breaks = c("1", "2", "3", "4"))

ggmap

#Error: Insufficient values in manual scale. 8927 needed but only 4 provided.

I hope this can be useful to understand what's going on.