dieghernan / tidyterra

tidyverse and ggplot2 methods for terra spatial objects
https://dieghernan.github.io/tidyterra/
Other
168 stars 7 forks source link

no fill color for extreme values #101

Closed kongdd closed 1 year ago

kongdd commented 1 year ago

image

library(ggplot2)
library(terar)
library(tidyterra)
library(magrittr)

ra = rast("GRACE2004.nc")
dates = time(ra)

  year = 2004
  #fout = glue("Figures/GRACE_China_2004.pdf")
  dates = names(ra)
  d_labs = data.frame(lyr = dates, label = dates)

  p = ggplot() +
    geom_spatraster(data = ra) +
    facet_wrap(~lyr, ncol = 4) +
    theme(
      panel.border = element_rect(color = "black", fill = "transparent"),
      # panel.background = element_rect(color = "red"),
      axis.text = element_blank(),
      axis.ticks = element_blank(),
      strip.text = element_blank()
      ) +
    # scale_fill_manual(values = cols) +
    scale_fill_whitebox_c(
      palette = "muted",
      breaks = c(20, 40, Inf) %>% c(-rev(.), 0, .),
      limits = c(-40, 40),
      labels = scales::label_number(suffix = "")
    ) +
    coord_sf(xlim = c(70, 140), ylim = c(15, 55), expand = FALSE) +
    labs(fill = "TWS anomaly")
p
dieghernan commented 1 year ago

Could you please share the file GRACE2004.tif?

kongdd commented 1 year ago

Sorry for the later response. It is at here. https://drive.google.com/file/d/1TKsYTlQ3lKf_CUCu19nf9ygRbCkY8Zdi/view?usp=drive_link

dieghernan commented 1 year ago

Hi,

The issue is not in the package, but in the limits you are setting to your scale_fill_whotebox_c((), e.g. limits = c(-40, 40) . Your layers have values beyond 40, so the plot does not produce colors on that since you have set the upper limit to 40. You can use terra::clamp() to limit the values to the scale you want to use in the plot, see:

library(ggplot2)
library(terra)
library(tidyterra)

ra = rast("GRACE2004.nc")
dates = time(ra)

year = 2004
#fout = glue("Figures/GRACE_China_2004.pdf")
dates = names(ra)
d_labs = data.frame(lyr = dates, label = dates)

# Maximum values in your layers
sapply(as_tibble(ra), max)
# > GRACE2004_1  GRACE2004_2  GRACE2004_3  GRACE2004_4  GRACE2004_5  GRACE2004_6  GRACE2004_7  GRACE2004_8  GRACE2004_9 
# > 58.58182     66.45120     60.43810     49.94805     35.16966     67.21159     55.69606     74.56244     53.36175 
# > GRACE2004_10 GRACE2004_11 GRACE2004_12 
# >  48.69635     68.61141     40.84679 

p1 <- ggplot() +
  geom_spatraster(data = ra) +
  facet_wrap(~lyr, ncol = 4) +
  theme(
    panel.border = element_rect(color = "black", fill = "transparent"),
    # panel.background = element_rect(color = "red"),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    strip.text = element_blank()
  ) +
  scale_fill_whitebox_c(
    palette = "muted",
    breaks = c(20, 40, Inf) %>% c(-rev(.), 0, .),
    limits = c(-40, 40),
    labels = scales::label_number(suffix = "")
  ) +
  coord_sf(xlim = c(70, 140), ylim = c(15, 55), expand = FALSE) +
  labs(fill = "TWS anomaly")

p1

plot1

# Clamp values to max and min according to your limits
ra2 <- clamp(ra, lower = -40, upper = 40)
sapply(as_tibble(ra2), max)

# > GRACE2004_1  GRACE2004_2  GRACE2004_3  GRACE2004_4  GRACE2004_5  GRACE2004_6  GRACE2004_7  GRACE2004_8  GRACE2004_9 
# > 40.00000     40.00000     40.00000     40.00000     35.16966     40.00000     40.00000     40.00000     40.00000 
# > GRACE2004_10 GRACE2004_11 GRACE2004_12 
# >  40.00000     40.00000     40.00000 

# Same plot with clamped raster

p2 <- ggplot() +
  geom_spatraster(data = ra2) +
  facet_wrap(~lyr, ncol = 4) +
  theme(
    panel.border = element_rect(color = "black", fill = "transparent"),
    # panel.background = element_rect(color = "red"),
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    strip.text = element_blank()
  ) +
  scale_fill_whitebox_c(
    palette = "muted",
    breaks = c(20, 40, Inf) %>% c(-rev(.), 0, .),
    limits = c(-40, 40),
    labels = scales::label_number(suffix = "")
  ) +
  coord_sf(xlim = c(70, 140), ylim = c(15, 55), expand = FALSE) +
  labs(fill = "TWS anomaly")

p2

plot2

kongdd commented 1 year ago

Got it. Thanks for your solution.

kongdd commented 1 year ago

Finally, I found the solution. A more elegant way.

censor2 <- function (x, range = c(0, 1), only.finite = TRUE) {
  force(range)
  finite <- if (only.finite) is.finite(x) else TRUE
  x[finite & x < range[1]] <- range[1]
  x[finite & x > range[2]] <- range[2]
  x
}

scale_fill_whitebox_c(
    palette = "muted",
    breaks = c(20, 40, Inf) %>% c(-rev(.), 0, .),
    limits = c(-40, 40),
    oob = censor2,
    labels = scales::label_number(suffix = "")
  )

https://github.com/tidyverse/ggplot2/blob/2a7ca74e297cdc23c56ce34fef193d5a6b488292/NEWS#L527-L529