Mapas usando ggplot

Caio VAOS

2024


Pacotes

library(tidyr)
library(dplyr)
library(ggplot2)
library(sf)
library(ggspatial)
library(geobr)
library(plotly)
library(gganimate)

Bases de Dados

# Shape
map_br <- read_country(showProgress = FALSE)
map_state <- read_state(showProgress = FALSE)
map_state <- map_state |> 
  select(1,6) # pegando apenas o necessário
map_state$code_state <- as.character(map_state$code_state) # pareando classe

# Preenchimento
DATA <- data.frame(code_state = map_state$code_state,
                   "ano_2000" = sample(80:100, 27, replace = TRUE),
                   "ano_2010" = sample(60:80, 27, replace = TRUE),
                   "ano_2022" = sample(30:60, 27, replace = TRUE))

# Junção
DF_MAPA_1 <- inner_join(map_state, DATA, by="code_state")
DF_MAPA_2 <- DF_MAPA_1 |> 
  pivot_longer(cols = c(2:4),
               names_to = "ano",
               values_to = "preenchimento")|> 
  mutate(ano = case_when(
    ano == "ano_2000" ~ 2000,
    ano == "ano_2010" ~ 2010,
    ano == "ano_2022" ~ 2022))

DATA

## # A tibble: 6 × 4
##   code_state ano_2000 ano_2010 ano_2022
##   <chr>         <int>    <int>    <int>
## 1 11               91       71       33
## 2 12               83       65       45
## 3 13               94       78       31
## 4 14               88       68       31
## 5 15               98       63       54
## 6 16               98       62       32

DF_MAPA_1

## # A tibble: 6 × 5
##   code_state ano_2000 ano_2010 ano_2022                                     geom
##   <chr>         <int>    <int>    <int>                       <MULTIPOLYGON [°]>
## 1 11               91       71       33 (((-63.32721 -7.97672, -62.86662 -7.975…
## 2 12               83       65       45 (((-73.18253 -7.335496, -72.58477 -7.55…
## 3 13               94       78       31 (((-67.32609 2.029714, -67.31682 2.0012…
## 4 14               88       68       31 (((-60.20051 5.264343, -60.19273 5.2518…
## 5 15               98       63       54 (((-54.95431 2.583692, -54.93542 2.5185…
## 6 16               98       62       32 (((-51.1797 4.000081, -51.17739 3.99402…

DF_MAPA_2

## # A tibble: 6 × 4
##   code_state                                            geom   ano preenchimento
##   <chr>                                   <MULTIPOLYGON [°]> <dbl>         <int>
## 1 11         (((-63.32721 -7.97672, -62.86662 -7.975868, -6…  2000            91
## 2 11         (((-63.32721 -7.97672, -62.86662 -7.975868, -6…  2010            71
## 3 11         (((-63.32721 -7.97672, -62.86662 -7.975868, -6…  2022            33
## 4 12         (((-73.18253 -7.335496, -72.58477 -7.552004, -…  2000            83
## 5 12         (((-73.18253 -7.335496, -72.58477 -7.552004, -…  2010            65
## 6 12         (((-73.18253 -7.335496, -72.58477 -7.552004, -…  2022            45

Simples

básico

ggplot(DF_MAPA_1)+
  geom_sf(aes(fill = ano_2000))+
  scale_fill_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"))+
  geom_sf(data= map_br, fill= "transparent", lwd= 0.4, col= "black")+
  labs(title = "Mapa Simples - Básico", x="", y="",
       fill= "Taxa", caption = "Fonte: ...")+
  annotation_scale(location = "br",
                   height = unit(0.2, "cm"))+
  annotation_north_arrow(location = "tr",
                         style = north_arrow_nautical,
                         height = unit(1.8, "cm"), width = unit(1.8, "cm"))+
  theme_bw()+
  theme(legend.position = c(0.15,0.3),
        plot.title = element_text(hjust = 0.5),
        legend.background = element_blank(),
        plot.caption = element_text(hjust = 0, size = 7),
        panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank())+
  annotate("text", x = -35, y = -28.5,
           label = "Brasil\n...", size = 4.2, color = "black")


taxa padronizada

# Padronização de taxa
limite_pdr <-  c(min(DATA[2:4]), max(DATA[2:4]))

# Plot
ggplot(DF_MAPA_1)+
  geom_sf(aes(fill = ano_2000))+
  scale_fill_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"),
                       limits= limite_pdr)+
  geom_sf(data= map_br, fill= "transparent", lwd= 0.4, col= "black")+
  labs(title = "Mapa Simples - Taxa Padronizada", x="", y="",
       fill= "Taxa", caption = "Fonte: ...")+
  annotation_scale(location = "br",
                   height = unit(0.2, "cm"))+
  annotation_north_arrow(location = "tr",
                         style = north_arrow_nautical,
                         height = unit(1.8, "cm"), width = unit(1.8, "cm"))+
  theme_bw()+
  theme(legend.position = c(0.15,0.3),
        plot.title = element_text(hjust = 0.5),
        plot.background = element_rect(fill = "#e2ece9", colour = "black"),
        legend.background = element_blank(),
        plot.caption = element_text(hjust = 0, size = 7),
        panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank())+
  annotate("text", x = -35, y = -28.5,
           label = "Brasil\n...", size = 4.2, color = "black")


Facetado

ggplot(DF_MAPA_2)+
  geom_sf(aes(fill = preenchimento, col= preenchimento))+
  geom_sf(data= map_br, fill= "transparent", lwd= 0.3, col= "black")+
  geom_text(data = data.frame(x = c(-70, -70, -70),
                              y = c(-30, -30, -30),
                              ano = c(2000, 2010, 2022),
                              label = c("Brasil\nI", "Brasil\nII", "Brasil\nIII")), 
            aes(x = x, y = y, label = label), color = "black", size = 2.5)+
  facet_wrap(~ano, ncol = 3, labeller = labeller(ano = c("2000" = "Ano 2000",
                                                         "2010" = "Ano 2010",
                                                         "2022" = "Ano 2022")))+
  scale_color_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"))+
  scale_fill_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"))+
  labs(title = "Mapa Facetado",
       fill= "Taxa",
       col="Taxa",
       x = "", y = "",
       caption = "Fonte: ...")+
  theme_bw()+
  theme(plot.title = element_text(hjust = 0.5),
        legend.background = element_blank(),
        plot.caption = element_text(hjust = 0, size = 7),
        axis.text = element_text(size = 6))


Interativo

Basta aplicar em um ggplot objetificado.

# Plot
gg_plot <- ggplot(DF_MAPA_1)+
  geom_sf(aes(fill = ano_2000))+
  scale_fill_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"))+
  geom_sf(data= map_br, fill= "transparent", lwd= 0.4, col= "black")+
  labs(title = "Mapa Interativo", x="", y="",
       fill= "Taxa", caption = "Fonte: ...")+
  annotation_scale(location = "br",
                   height = unit(0.2, "cm"))+
  annotation_north_arrow(location = "tr",
                         style = north_arrow_nautical,
                         height = unit(1.8, "cm"), width = unit(1.8, "cm"))+
  theme_bw()+
  theme(legend.position = c(0.15,0.3),
        plot.title = element_text(hjust = 0.5),
        legend.background = element_blank(),
        plot.caption = element_text(hjust = 0, size = 7))+
  annotate("text", x = -35, y = -28.5,
           label = "Brasil\n...", size = 4.2, color = "black")
ggplotly(gg_plot)

Animado

Existem vários tipos de transições, essa se enquadra melhor aos Mapas.

{current_frame} = texto que mudara em cada frame;

transition_manual() = variação discreta.

animate() = anima o plot, controlando o número e frames e a velocidade.

anim_save() = salva o plot animado como gif.

# Plot
mapa_animado <-  ggplot(DF_MAPA_2)+
  geom_sf(aes(fill = preenchimento))+
  geom_text(data = data.frame(x = c(-35, -35, -35),
                              y = c(-28.5, -28.5, -28.5),
                              ano = c(2000, 2010, 2022),
                              label = c("Brasil\nI", "Brasil\nII", "Brasil\nIII")), 
            aes(x = x, y = y, label = label), color = "black", size = 10)+
  scale_fill_gradientn(colours= c("#0d1b2a","#415a77","#e0e1dd","#588157","#344e41"))+
  geom_sf(data= map_br, fill= "transparent", lwd= 0.4, col= "black")+
  labs(title = "Mapa Animado - Ano {current_frame}", x="", y="",
       fill= "Taxa", caption = "Fonte: ...")+
  annotation_scale(location = "br",
                   height = unit(0.2, "cm"))+
  annotation_north_arrow(location = "tr",
                         style = north_arrow_nautical,
                         height = unit(1.8, "cm"), width = unit(1.8, "cm"))+
  theme_bw()+
  theme(legend.position = c(0.15,0.3),
        plot.title = element_text(hjust = 0.5),
        legend.background = element_blank(),
        plot.caption = element_text(hjust = 0, size = 7),
        panel.grid = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank())+
  transition_manual(ano)
# Salvar:
#anim_save("mapa_animado.gif", animate(mapa_animado, nframes = length(unique(DF_MAPA_2$ano)), fps = 0.7))
# Rodar:
#animate(mapa_animado, nframes = length(unique(DF_MAPA_2$ano)), fps = 0.7)
mapa_animado