Mapas no R - Parte 02
Nesta parte vamos mostrar como podemos utilizar mapas para informar o leitor de nosso trabalho a respeito de algum fato. Vamos para isso dividir este capitulo em duas parte. Na primeira vamos trabalhar com uma base de dados na qual gostaríamos de mostrar alguma estatística por meio de uma mapa. Na segunda será mostrado o passo a passo necessário para deixar os dados prontos para o uso em um mapa.
1 Representando informações em um mapa
Nosso objetivo aqui é reproduzir o seguinte mapa para o Estado do RS mostrando os municípios e seu PIB per capita. Qualquer outro mapa que tenhamos que representar terá um procedimento semelhante a este que iremos reproduzir.
Na sequência vamos aprender que existem duas possíbilidades quanto ao tipo de informação que gostaríamos de mostrar em um mapa. Vamos começar mostrando como seria a representação de uma variável contínua e então passaremos para representação de uma variável discreta, como a que acabamos de mostrar no mapa reproduzido acima, onde utilizamos categorias/faixas do PIB per capita dos municípios.
1.1 Representando Variáveis Contínuas no Mapa
Qualquer variável que quisermos mostrar em um mapa deverá ser indicada na função geom_sf() e dentro da função aes(fill = variavel), como mostrado no exemplo abaixo.
# Criando nosso primeiro mapa com um variável
# uma variável contínua
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
theme_void()Nosso mapa ficou um pouco diferente do que vimos até aqui. Isso acontece devido ao tipo de variável no qual utilizamos para associar os dados nos mapas, pib_pc, uma variável que é contínua em seus valores. Quando temos esse tipo de variável, o R vai sempre associar um mesmo tom de cor, no caso aquele tom mais azul, e então vai diferenciar seus valores em tons mais claros e mais escuros. Claramente, esse tipo de variável não parece ser o mais útil para o nosso propósito, embora para outras aplicações ele possa ser a escolha mais interessante.
Embora nossa escolha não será por representar variáveis dessa maneira, nossa escolha vai ser por variáveis discretas, com aquele tipo de intervalo que vimos no primeiro mapa, podemos utilizar o exemplo acima para trabalhar alguns conceitos no mapa que serão úteis.
Uma das coisas que vamos poder modificar são as cores, nesse caso, podemos mudar o tom da cor da mesma forma que vinhamos fazendo e para isso temos duas opções, cada uma especificada por uma função. No primeiro caso podemos utilizar a função scale_fill_gradient() onde dentro dela teremos que especificar dois argumento, low e high, que vão corresponder as cores do limite inferior e superior de nossos dados. Alguns exemplos são mostrados abaixo para diferentes opções de cores.
# primeiro exemplo
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#fef9e7", high = "#9a7d0a") +
theme_void()dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#d5d8dc", high = "#1c2833") +
theme_void()dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#f2d7d5", high = "#7b241c") +
theme_void()A outra possibilidade de modificação das cores vem da função scale_fill_gradient2(). Nele seria possível especificar três cores, a do último intervalo, do meio, e da extremidade superio, sendo que as cores seriam colocadas nessa faixa de valores de acordo com uma estatística definida em midpoint, ponto que seria utilizado para dividir o espectro de cores no meio, estatistica que pode ser a média, mediana ou alguma outra variável de interesse.
Esse tipo de gráfico, quando estivermos trabalhando as cores, precisa atender ao critério de que as cores estejam em uma mesma faixa de tons. Como pode ser percebido pelos exemplos, pode ser difícil encontrar as melhores cores devido ao gráfico com uma variável contínua não ser o mais interessante do ponto de vista de nossos propósitos.
# dividindo as cores por meio do valor mediano
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient2(low = "yellow",
mid = "darkblue",
high = "red",
midpoint = 31529) +
theme_void()Outro ponto que podemos modificar é relacionado a legenda, onde poderemos modificar sua posição, seus títulos e rótulos. Vamos começar modificando a posição da legenda por meio do argumento legend.position dentro da função theme().
# modificando a posição da legenda
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#f2d7d5", high = "#7b241c") +
theme_void() +
theme(legend.position = "bottom")Vão existir quatro opções para modificarmos a posição da legenda em nosso gráfico: top, left, right e bottom.
O título da legenda pode ser modificado dentro de labs() ao colocarmos no argumento fill o nome que gostaríamos de aparecer na legenda. Uma vez modificado esse nome, podemos utilizar dentro de theme() o argumento legend.title para controlarmos seu tamanho, cor e outros atributos de interesse. Ainda é possível também modificar o nome dentro da própria função scale_fill_gradiente() por meio do argumento name onde devemos passar o nome, entre aspas, que gostaríamos de indicar no gráfico.
# modificando o título da legenda e seus aspectos
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
labs(fill = "PIB per capita") +
scale_fill_gradient(low = "#f2d7d5", high = "#7b241c") +
theme_void() +
theme(legend.position = "left",
legend.title = element_text(size = 13,
colour = "#7b241c",
face = "italic"))Por fim, podemos modificar os rótulos das legendas mostradas no gráfico de duas maneiras. Podemos antes de realizar qualquer gráfico no R rodar o código options(scipen = 999) fazendo com que nenhum valor seja mostrado com sua representação exponencial. Por outro lado, poderíamos manualmente indicar os valores a serem indicados na legenda com a função
Quando queremos especificar diretamente os valores e rótulos que devem aparecer na legenda podemos utilizar os argumentos breaks e labels dentro de scale_fill_gradient(), como visto no exemplo abaixo.
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#f2d7d5",
high = "#7b241c",
name = "PIB Per Capita",
breaks = c(50000, 150000, 250000),
labels = c("R$ 50.000", "R$ 150.000", "R$ 250.000")
) +
theme_void() +
theme(legend.position = "left",
legend.title = element_text(size = 13,
colour = "#7b241c",
face = "italic"))No exemplo acima, é importante verificar que o número de breaks vai definir a quantidade de rótulos que podemos utilizar. Além disso, como mostrado na sequência, podemos controlar a cor, tamanho desses rótulos com o argumento legend.text dentro do theme().
dados %>%
ggplot() +
geom_sf(aes(fill = pib_pc)) +
scale_fill_gradient(low = "#f2d7d5",
high = "#7b241c",
name = "PIB Per Capita",
breaks = c(50000, 150000, 250000),
labels = c("R$ 50.000", "R$ 150.000", "R$ 250.000")
) +
labs(title = "RS e suas desigualdades",
subtitle = "Valores do PIB per capita em 2018") +
theme_void() +
theme(legend.position = "left",
plot.title = element_text(size = 25,
colour = "#7b241c",
face = "bold"),
plot.title.position = "plot",
plot.subtitle = element_text(size = 13,
colour = "#7b241c"
),
legend.title = element_text(size = 11,
colour = "#7b241c",
face = "italic"),
legend.text = element_text(size = 11,
colour = "#7b241c",
face = "italic")
)Na sequência vamos trabalhar com a outra possibilidade de inserir variáveis no mapa, variáveis que são de um tipo discreto.
1.2 Representando Variáveis Categóricas no Mapa
A maneira de associar uma variável discreta, ou categórica como é o nosso interesse, é semelhante ao feito anteriormente. Basta, como mostrado no código abaixo, indicar o nome da variável por meio do argumento fill na função geom_sf().
dados %>%
ggplot() +
geom_sf(aes(fill = faixa_pib)) +
theme_void()Do ponto de vista prático, nossa únida diferença é que teremos que mudar a função que controla os rótulos que são mostrados no mapa com as faixas do PIB per capita mostrados. Nesse caso, teremos que utilizar a função scale_fill_manual(), como indicada no código abaixo.
dados %>%
ggplot() +
geom_sf(aes(fill = faixa_pib)) +
scale_fill_manual(
values = c("[R$ 11.000 - R$ 19.000)" = "#FFFFFF",
"[R$ 19.000 - R$ 27.000)" = "#D5E9D5",
"[R$ 27.000 - R$ 35.000)" = "#BDDDBD",
"[R$ 35.000 - R$ 43.000)" = "#7DBD7D",
"[R$ 43.000 - R$ 51.000)" = "#339933",
"[R$ 51.000 - R$ 304.209]" = "#008000"),
name = "Intervalos para o\nPIB per capita de 2018"
) +
theme_void()A diferença com a variável contínua quando colocada em um mapa é muito significativa, com a variável definida acima permitindo uma melhor visão da diferença entre os níveis de PIB per capita entre os municípios. O gráfico final pode ser formatado como.
dados %>%
ggplot() +
geom_sf(aes(fill = faixa_pib),
color = "#353535") +
scale_fill_manual(
values = c("[R$ 11.000 - R$ 19.000)" = "#FFFFFF",
"[R$ 19.000 - R$ 27.000)" = "#D5E9D5",
"[R$ 27.000 - R$ 35.000)" = "#BDDDBD",
"[R$ 35.000 - R$ 43.000)" = "#7DBD7D",
"[R$ 43.000 - R$ 51.000)" = "#339933",
"[R$ 51.000 - R$ 304.209]" = "#008000"),
name = "Intervalos para o\nPIB per capita de 2018"
) +
theme_void() +
labs(
title = "DESIGUALDADES",
subtitle = "Diferenças no nível de renda per capita entre municípios gaúchos" ) +
theme(
plot.title = element_text(
size = 30,
color = "#008000" ),
plot.subtitle = element_text(
size = 13,
color = "#BDDDBD" ),
plot.caption = element_text(
size = 10,
color = "#353535" ),
legend.title = element_text(
size = 8,
color = "#353535" ),
legend.text = element_text(
size = 8,
color = "#353535" )
)Na sequência vamos tratar da parte que mais demora em uma análise como a feita acima, a construção de nossos dados.
2 Manipulações dos Dados
Esta parte vai mostrar o processo de estruturação de uma base de dados para que seja possível visualizar no R por meio de mapas. O que faremos será unir os dados de nosso interesse, aqueles que gostaríamos de visualizar em um mapa, com nossa base de mapas, ou seja, aquela objeto que contém a coluna geometry.
2.1 Importação das estatísticas do PIB per capita
Vamos começar por preparar nossa base de dados para que depois a mesma possa ser unida ao nosso mapa. Vamos assumir que nosso objetivo seja o de visualizar uma variável que indique diferentes categorias e que para isso vamos precisar fazer a construção dessas categorias. Para facilitar nosso entendimento, vamos utilizar a base de dados que contém informações sobre o Produto Interno Bruto per capita dos municípios do RS para o ano de 2018, como mostrada abaixo.
Obs.: Não esqueça que primeiro precisamos carregar os pacotes a serem utilizados. Nesse caso vamos utilizar os pacotes tidyverse e sf.
# carregando a base de dados do meu diretório de trabalho
# dados sobre o PIB
pib_rs_2018 <- read_csv2("dados_brutos/pib.csv") %>%
filter(estado == "RS", ano == 2018) %>%
select(1,2,pib)
# dados sobre a População
pop_rs_2018 <- read_rds("dados_brutos/populacao.rds") %>%
filter(estado == "RS", ano == 2018) %>%
select(municipio_codigo, municipio, populacao)No passo anterior fizemos a importação de duas bases de dados separadas, nas quais chamamos de pib_rs_2018 e pop_rs_2018. Vamos precisar fazer a união dessas duas bases já que o valor do PIB per capita será a divisão da variável pib pelo valor da população. Isso é feito no código abaixo.
left_join(pib_rs_2018, pop_rs_2018)Joining with `by = join_by(municipio_codigo, municipio)`
Error in `left_join()`:
! Can't join `x$municipio_codigo` with `y$municipio_codigo` due to
incompatible types.
ℹ `x$municipio_codigo` is a <double>.
ℹ `y$municipio_codigo` is a <character>.
Como foi possível observa pela mensagem de erro, as variáveis que deveriam ser utilizadas para unir as bases são de tipos diferentes, quando elas deveriam ser de um mesmo tipo, no caso character. Esse tipo de erro pode ser rapidamente solucionado ao utilizarmos a função mutate() para transformar o tipo de variável, como será mostrado no código abaixo onde vamos transformar com a ajuda da função as.character().
pib_rs_2018 <- read_csv2("dados_brutos/pib.csv") %>%
filter(estado == "RS", ano == 2018) %>%
select(1,2,pib) %>%
mutate(municipio_codigo = as.character(municipio_codigo))Tentando novamente podemos verificar que agora as bases de dados estão unidas em um único objeto, que vamos passar a chamar pib_pc_rs.
pib_pc_rs <- left_join(pib_rs_2018, pop_rs_2018, join_by(municipio_codigo, municipio)) %>%
mutate(pib_pc = pib/(populacao/1000))Foi possível perceber que no código acima, imediatamente ao processo de união foi pedido para que a variável pib_pc fosse construida. Foi feito a divisão do valor da população por 1000 apenas para que os valores ficassem na mesma dimensão que os valores do PIB.
2.2 Construção das categorias de interesse - função cut()
A partir dessa base de dados, teremos que construir uma nova coluna, por isso vamos utilizar a função mutate(), para indicar difentes categorias nas quais os municípios vão se encaixar. Nesse sentido, o que faremos é indicar para cada valor do PIB per capita de determinado município, em que faixa esse município deverá pertencer, se por exemplo, esse município deverá estar na faixa [100.000 - até 500.000] ou [20.000 - 50.000). No decorrer do nosso exemplo, vamos assumir as seguintes faixas de valores nas quais o PIB per capita de determinado município pode entrar.
| Faixas de valores escolhidas para o exemplo e total de municípios que vão ficar em cada faixa. | |
| Faixa | Nº de Municípios |
|---|---|
| [R$ 11.000 - R$ 19.000) | 45 |
| [R$ 19.000 - R$ 27.000) | 121 |
| [R$ 27.000 - R$ 35.000) | 118 |
| [R$ 35.000 - R$ 43.000) | 74 |
| [R$ 43.000 - R$ 51.000) | 53 |
| [R$ 51.000 - R$ 304.209] | 86 |
Antes de prosseguir é importante indicar que as faixas de valores que forem mostradas foram definidas em termos puramente arbitrários, apenas para exposição e entendimento do exemplo. É recomendado que em qualquer trabalho real essas faixas deveriam ser obtidas por algum critério mais científico.
Como indicado, as faixas acima deverão ser construídas por meio da função mutate() responsável por adicionar variáveis em um banco de dados já existente. Além disso, para efetiva construção dessas faixas vai ser preciso utilizar dentro da função mutate() a função cut(). O código para sua construção é mostrado abaixo:
pib_pc_rs %>%
select(municipio, municipio_codigo, pib_pc) %>%
mutate(
faixa_pib = cut(pib_pc,
breaks = c(-Inf, 11000, 19000, 27000, 35000, 43000, 51000, Inf),
include.lowest = T,
right = F,
labels = c(
"[R$ 4.562 - R$ 11.000)",
"[R$ 11.000 - R$ 19.000)",
"[R$ 19.000 - R$ 27.000)",
"[R$ 27.000 - R$ 35.000)",
"[R$ 35.000 - R$ 43.000)",
"[R$ 43.000 - R$ 51.000)",
"[R$ 51.000 - R$ 304.209]"
)
)
)# A tibble: 497 × 4
municipio municipio_codigo pib_pc faixa_pib
<chr> <chr> <dbl> <fct>
1 Aceguá 4300034 51069. [R$ 51.000 - R$ 304.209]
2 Água Santa 4300059 88151. [R$ 51.000 - R$ 304.209]
3 Agudo 4300109 30258. [R$ 27.000 - R$ 35.000)
4 Ajuricaba 4300208 42299. [R$ 35.000 - R$ 43.000)
5 Alecrim 4300307 18159. [R$ 11.000 - R$ 19.000)
6 Alegrete 4300406 29467. [R$ 27.000 - R$ 35.000)
7 Alegria 4300455 31929. [R$ 27.000 - R$ 35.000)
8 Almirante Tamandaré do Sul 4300471 83157. [R$ 51.000 - R$ 304.209]
9 Alpestre 4300505 76015. [R$ 51.000 - R$ 304.209]
10 Alto Alegre 4300554 40017. [R$ 35.000 - R$ 43.000)
# ℹ 487 more rows
A função cut() exige alguns argumentos para que os valores sejam calculados de maneira correta. Como é possível perceber do código, a primeira coisa que precisamos definir são os intervalos desejados, pois serão eles que vão ser colocados no argumento chamado de breaks. No vetor escrito em breaks, o valor -Inf está indicando para o R procurar dentro da variável pib_pc os menores valores possíveis até chegar no limite superior da nossa primeira faixa, que no caso foi estabelecida em 11000. Na sequência o R vai procurar todos os valores que começam em 11000 e vão até 19000 para serem os valores que vão cair dentro da segunda faixa, e assim por diante.
Observe-se que no caso do argumento include.lowest = T, ele serve apenas para indicar que o valor do lado esquerdo de nossas faixas deve ser fechado, ou seja, deve incluir esse valor, como é o caso dos valores 11.000, 19.000, .... O argumento right = F serve para indicar que o intervalo a esquerda deve ser aberto, ou seja, não deve conter o valor indicado à direita das faixas estabelecidas.
O Último argumento a ser utilizado é apenas para indicar como as faixas de valores devem ser mostradas. Os valores possíveis para essas faixas precisam estar alinhados com aquilo que os dados nos revelam. Nesse caso, uma análise dos valores da variável que vai ser utilizada para construir as categorias é muito importante. Isso pode ser feito utilizando a função summary() que nos permite indentificar rapidamente qual o menor valor da série e o maior valor da série.
Qual seria o código para observarmos as estatísticas resumo de uma determinada variável? R. pib_pc_rs %>% summary(). Veja se as faixas utilizadas seriam as melhores a partir dos valores que esse código retorna. Caso não sejam, qual seria a sua escolha?
Nosso dados estão agora prontos para serem representados em nosso mapa. Nosso último passo é apenas o de inserir essas variáveis dentro do objeto que contenha o mapa do Rio Grande do Sul. Antes contudo, vamos atualizar nosso banco de dados pib_pc_rs para que realmente essas variáveis apareçam quando fomos unir ao mapa.
# pedindo para atualizar nossa base de dados com os valores das faixas construídas
pib_pc_rs <- pib_pc_rs %>%
select(municipio, municipio_codigo, pib_pc) %>%
mutate(
faixa_pib = cut(pib_pc,
breaks = c(-Inf, 11000, 19000, 27000, 35000, 43000, 51000, Inf),
include.lowest = T,
right = F,
labels = c(
"[R$ 4.562 - R$ 11.000)",
"[R$ 11.000 - R$ 19.000)",
"[R$ 19.000 - R$ 27.000)",
"[R$ 27.000 - R$ 35.000)",
"[R$ 35.000 - R$ 43.000)",
"[R$ 43.000 - R$ 51.000)",
"[R$ 51.000 - R$ 304.209]"
)
)
)2.3 Unindo nossa base de dados com o mapa
Nosso mapa poderá ser obtido a partir de algum dos metodos que estudamos antes. Vamos utilizar o método de baixar por meio do pacote geobr, cujo código abaixo indica que o mapa do RS, com seus municípios pode ser obtido da seguinte maneira.
Não esqueça dos pacotes: geobr e sf().
# importando mapa do RS para o ano de 2018
mapa_rs <- read_municipality(code_muni = "RS", year = 2018) %>%
filter(!name_muni %in% c("Lagoa Mirim", "Lagoa Dos Patos")) %>%
# a linha de código abaixo vai ser necessária para transformar as variáveis no mesmo tipo
mutate(code_muni = as.character(code_muni)) Vamos pegar nossa base de dados onde construímos as categorias nas quais os municípios podem estar para os valores do PIB per capita e unir com a base dos mapas. Contudo, precisamos observar que as variáveis que vão fazer a união estão com nomes diferentes, na base dos dados o código de sete digitos tem o nome de codigo_municipio enquanto que na base do mapa essa variável está com o nome de code_muni. Precisamos indicar isso no momento de aplicar a função left_join().
rs_2018_pib <- left_join(mapa_rs, pib_pc_rs, join_by(code_muni == municipio_codigo )) %>%
select(1,pib_pc, faixa_pib, geom)Quando estivermos unindo bases de dados e malhas de mapas, como no exemplo acima, o mapa deve sempre ser unido primeiro, ou seja, ele deve ser sempre aquela base de dados que vem primeiro na função left_join(). Caso isso não seja feito, o mapa não poderá ser gerado.
Nossa base agora está pronta para ser utilizada como mostra o mapa abaixo. Apenas será necessário melhorar a nossa imaginação para escolher as melhores cores.
rs_2018_pib %>%
ggplot() +
geom_sf(aes(fill = faixa_pib)) +
theme_void()