dieghernan / tidyterra

tidyverse and ggplot2 methods for terra spatial objects

Home Page:https://dieghernan.github.io/tidyterra/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to plot categorical data(single layer and facet_wrap multiple layers) with geom_spatraster?

tigerwang1998 opened this issue · comments

Hi, I have a problem with categorical data when I want to use this brilliant package.

For single layer, I try to make this codes,but I don't know if there is an easier way?

library(terra)
library(tidyterra)
r=rast(ncol=10,nrow=10,
       vals=sample(x=1:4,size=100,replace = T))
r
plot(r)

image

names(r) <- 'landcover'
rr <- r %>% mutate(fac=factor(landcover))
ggplot()+
  geom_spatraster(data=rr,
                  aes(fill=fac))

image

For multiple layers, I want to use facet_wrap(~lyr), but I failed.

r1=rast(ncol=10,nrow=10,
        vals=sample(x=1:4,size=100,replace = T))
r2=rast(ncol=10,nrow=10,
        vals=sample(x=1:4,size=100,replace = T))
r3=rast(ncol=10,nrow=10,
        vals=sample(x=1:4,size=100,replace = T))
r4=rast(ncol=10,nrow=10,
        vals=sample(x=1:4,size=100,replace = T))

multi <- c(r1,r2,r3,r4)
names(multi) <- c('test1',
                  'test2',
                  'test3',
                  'test4')
n <- names(multi)
n
a=multi[[1]] %>% 
  mutate(fac=factor(get(n[1])))
for (i in 2:nlyr(multi)) {
  b=multi[[i]] %>% 
    mutate(fac=as.factor(get(n[i])))
  a=c(a,b)
}

multi_fac <- a

ggplot()+
  geom_spatraster(data=multi_fac,
                  aes(fill=fac))
# Error: [subset] you cannot select a layer with a name that is not unique

Could you help me? Thanks!

Hi:

For single layer your code is fine, you can also try:

ggplot() + geom_spatraster(data=rr %>% select(fac))

For multi-layers there are two restrictions:

  1. Layer names needs to be unique. Note that terra allows to use the same name on several layers while the tidyverse does not. That's why you receieved and error. Just make the layer names unique.
  2. The other restriction is that when facetting the type of variable to be faceted needs to be the same (i.e. can't facet objects that have mixed layer types as integers/character, etc.). This is the expected behaviour, as in ggplot2, so the approach is to select only layers with the same type.

See an example on multi

library(terra)
#> terra 1.7.18
library(tidyterra)
#> 
#> Attaching package: 'tidyterra'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:terra':
#> 
#>     intersect, union
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union


r1 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r2 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r3 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r4 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)

multi <- c(r1, r2, r3, r4)
names(multi) <- c(
  "test1",
  "test2",
  "test3",
  "test4"
)
n <- names(multi)
n
#> [1] "test1" "test2" "test3" "test4"
a <- multi[[1]] %>%
  mutate(fac = factor(get(n[1])))
for (i in 2:nlyr(multi)) {
  b <- multi[[i]] %>%
    mutate(fac = as.factor(get(n[i])))
  a <- c(a, b)
}

multi_fac <- a

names(multi_fac)
#> [1] "test1" "fac"   "test2" "fac"   "test3" "fac"   "test4" "fac"

# Make names unique
names(multi_fac) <- make.names(names(multi_fac), unique = TRUE)

glimpse(multi_fac)
#> Rows: 100
#> Columns: 8
#> $ test1 <int> 4, 1, 3, 2, 1, 3, 3, 2, 2, 1, 3, 2, 3, 1, 1, 2, 2, 4, 4, 4, 2, 1…
#> $ fac   <fct> 4, 1, 3, 2, 1, 3, 3, 2, 2, 1, 3, 2, 3, 1, 1, 2, 2, 4, 4, 4, 2, 1…
#> $ test2 <int> 1, 3, 1, 3, 3, 3, 2, 3, 3, 4, 4, 2, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1…
#> $ fac.1 <fct> 1, 3, 1, 3, 3, 3, 2, 3, 3, 4, 4, 2, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1…
#> $ test3 <int> 1, 1, 4, 4, 2, 2, 3, 4, 4, 1, 4, 2, 1, 4, 1, 3, 2, 1, 2, 2, 4, 2…
#> $ fac.2 <fct> 1, 1, 4, 4, 2, 2, 3, 4, 4, 1, 4, 2, 1, 4, 1, 3, 2, 1, 2, 2, 4, 2…
#> $ test4 <int> 2, 1, 1, 1, 3, 2, 1, 4, 3, 2, 3, 3, 3, 1, 1, 2, 4, 2, 4, 3, 4, 2…
#> $ fac.3 <fct> 2, 1, 1, 1, 3, 2, 1, 4, 3, 2, 3, 3, 3, 1, 1, 2, 4, 2, 4, 3, 4, 2…


# Select test
ggplot() +
  geom_spatraster(data = multi_fac %>% select(starts_with("test"))) +
  facet_wrap(~lyr)

# Select fac
ggplot() +
  geom_spatraster(data = multi_fac %>% select(starts_with("fac"))) +
  facet_wrap(~lyr)

Created on 2023-03-18 with reprex v2.0.2

Hi:

For single layer your code is fine, you can also try:

ggplot() + geom_spatraster(data=rr %>% select(fac))

For multi-layers there are two restrictions:

  1. Layer names needs to be unique. Note that terra allows to use the same name on several layers while the tidyverse does not. That's why you receieved and error. Just make the layer names unique.
  2. The other restriction is that when facetting the type of variable to be faceted needs to be the same (i.e. can't facet objects that have mixed layer types as integers/character, etc.). This is the expected behaviour, as in ggplot2, so the approach is to select only layers with the same type.

See an example on multi

library(terra)
#> terra 1.7.18
library(tidyterra)
#> 
#> Attaching package: 'tidyterra'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:terra':
#> 
#>     intersect, union
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union


r1 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r2 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r3 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)
r4 <- rast(
  ncol = 10, nrow = 10,
  vals = sample(x = 1:4, size = 100, replace = T)
)

multi <- c(r1, r2, r3, r4)
names(multi) <- c(
  "test1",
  "test2",
  "test3",
  "test4"
)
n <- names(multi)
n
#> [1] "test1" "test2" "test3" "test4"
a <- multi[[1]] %>%
  mutate(fac = factor(get(n[1])))
for (i in 2:nlyr(multi)) {
  b <- multi[[i]] %>%
    mutate(fac = as.factor(get(n[i])))
  a <- c(a, b)
}

multi_fac <- a

names(multi_fac)
#> [1] "test1" "fac"   "test2" "fac"   "test3" "fac"   "test4" "fac"

# Make names unique
names(multi_fac) <- make.names(names(multi_fac), unique = TRUE)

glimpse(multi_fac)
#> Rows: 100
#> Columns: 8
#> $ test1 <int> 4, 1, 3, 2, 1, 3, 3, 2, 2, 1, 3, 2, 3, 1, 1, 2, 2, 4, 4, 4, 2, 1…
#> $ fac   <fct> 4, 1, 3, 2, 1, 3, 3, 2, 2, 1, 3, 2, 3, 1, 1, 2, 2, 4, 4, 4, 2, 1…
#> $ test2 <int> 1, 3, 1, 3, 3, 3, 2, 3, 3, 4, 4, 2, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1…
#> $ fac.1 <fct> 1, 3, 1, 3, 3, 3, 2, 3, 3, 4, 4, 2, 3, 1, 2, 3, 1, 3, 1, 2, 2, 1…
#> $ test3 <int> 1, 1, 4, 4, 2, 2, 3, 4, 4, 1, 4, 2, 1, 4, 1, 3, 2, 1, 2, 2, 4, 2…
#> $ fac.2 <fct> 1, 1, 4, 4, 2, 2, 3, 4, 4, 1, 4, 2, 1, 4, 1, 3, 2, 1, 2, 2, 4, 2…
#> $ test4 <int> 2, 1, 1, 1, 3, 2, 1, 4, 3, 2, 3, 3, 3, 1, 1, 2, 4, 2, 4, 3, 4, 2…
#> $ fac.3 <fct> 2, 1, 1, 1, 3, 2, 1, 4, 3, 2, 3, 3, 3, 1, 1, 2, 4, 2, 4, 3, 4, 2…


# Select test
ggplot() +
  geom_spatraster(data = multi_fac %>% select(starts_with("test"))) +
  facet_wrap(~lyr)

# Select fac
ggplot() +
  geom_spatraster(data = multi_fac %>% select(starts_with("fac"))) +
  facet_wrap(~lyr)

Created on 2023-03-18 with reprex v2.0.2

Thanks a lot!