alt text

GET00183 - Visualização de Dados

Jony Arrais Pinto Junior

Nos dias atuais, é muito comum nos depararmos com dados georreferenciados. O crescimento de dados espaciais é relativamente recente. Porém, já experimentamos seus efeitos no dia a dia.

Visualizações de dados espaciais é fundamental para quem trabalha com análise de dados.

1 - Shapefile

Se o intuito é representar o espaço de interesse, precisamos inicialmente discutir sobre o shapefile.

Um shapefile é um formato popular de arquivo contendo dados geoespaciais em forma de vetor usado por Sistemas de Informações Geográficas (SIG). Shapefiles espaciais descrevem geometrias: pontos, linhas e polígonos. Entre outras coisas, essas geometrias podem representar Poços, Rios, cidades, respectivamente.

O formato shapefile define a geometria e os atributos dos recursos referenciados geograficamente em três ou mais arquivos com extensões de arquivo específicas que devem ser armazenadas no mesmo espaço de trabalho do projeto. Eles são:

  • .shp - O arquivo principal que armazena a geometria do recurso, obrigatório,
  • .shx - O arquivo de índice que armazena o índice da geometria do recurso, obrigatório,
  • .dbf - A tabela do dBASE que armazena as informações de atributos dos recursos, obrigatório,
  • .prj, .sbn, .sbx, .fbn, .fbx, .ain, .aih, .atx, .ixs, .mxs, .xml, .cpg são outras extensões possíveis.

Alguns arquivos podem ser obtidos no site do IBGE (https://www.ibge.gov.br/geociencias/downloads-geociencias.html).

Acessem o site e sigam o seguinte caminho: Organização do territorio \(>\) malhas territoriais. Vocês terão acesso:

  • malhas de setores censitários,
  • malhas municipais,
  • malhas do Brasil por município.

Atividade: Baixem o arquivo do Estado do Rio de Janeiro do ano de 2016 contendo os municípios. Vejam quantos arquivos foram baixados e quais suas extensões.

1.1 - Importando Shapefile

Para importamos um shapefile para o R usaremos a função st_read do pacote sf.

A seguir, vamos apresentar os principais argumentos da função st_read:

  - dsn - o nome do arquivo a ser importado (com extensão .shp).

Atividade: Importe o arquivo Bairros_Recife.shp e armazene-o em um objeto chamado recife. Para que a importação ocorra, é preciso que todos os arquivos auxiliares do shapefile estejam na mesma pasta.

# Carregando o pacote
library(sf)

# Importando o shapefile
recife = st_read(dsn = "Bairros_Recife.shp")
Reading layer `Bairros_Recife' from data source 
  `/Users/jonyarrais/Documents/Universidade Federal Fluminense/Disciplinas/GET00183 Visualizacao de Dados/Topico 07 - Mapas/Bairros_Recife.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 94 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 277547.5 ymin: 9098032 xmax: 295287.7 ymax: 9123296
Projected CRS: SIRGAS 2000 / UTM zone 25S
# Verificando a classe do objeto recife
class(x = recife)
[1] "sf"         "data.frame"
# Visualizando o objeto
recife
Simple feature collection with 94 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 277547.5 ymin: 9098032 xmax: 295287.7 ymax: 9123296
Projected CRS: SIRGAS 2000 / UTM zone 25S
First 10 features:
  CBAIRRCODI VBAIRROID         EBAIRRNOME CRPAAACODI CMICROCODI TBAIRRULAT
1         19         0             RECIFE          1          1 1899-12-30
2         27         0      SANTO ANTONIO          1          2 1899-12-30
3         35         0           SAO JOSE          1          2 1899-12-30
4         43         0 ILHA JOANA BEZERRA          1          3 1899-12-30
5         51         0            CABANGA          1          2 1899-12-30
6         60         0            COELHOS          1          3 1899-12-30
  CEMPRECODI AUSUACMATR         EBAIRRNO_1 EBAIRRLINK
1          0          0             Recife       <NA>
2          0          0      Santo Antônio       <NA>
3          0          0           São José       <NA>
4          0          0 Ilha Joana Bezerra       <NA>
5          0          0            Cabanga       <NA>
6          0          0            Coelhos       <NA>
                        geometry
1 MULTIPOLYGON (((294617.4 91...
2 MULTIPOLYGON (((293353.3 91...
3 MULTIPOLYGON (((292458 9107...
4 MULTIPOLYGON (((290464.9 91...
5 MULTIPOLYGON (((291566 9106...
6 MULTIPOLYGON (((291634.3 91...
 [ reached 'max' / getOption("max.print") -- omitted 4 rows ]
# Carregando o pacote
library(tidyverse)

## Para plotar somente o contorno do objeto recife
ggplot(recife) +
  geom_sf(fill = "White")

# Selecionando o shape do bairro de Boa Viagem
Boa_viagem = recife |>  
  filter(EBAIRRNOME=="BOA VIAGEM")

# Visualizando o objeto Boa_viagem
Boa_viagem
Simple feature collection with 1 feature and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 288679.6 ymin: 9098032 xmax: 292546.5 ymax: 9104302
Projected CRS: SIRGAS 2000 / UTM zone 25S
  CBAIRRCODI VBAIRROID EBAIRRNOME CRPAAACODI CMICROCODI TBAIRRULAT CEMPRECODI
1        205         0 BOA VIAGEM          6          1 1899-12-30          0
  AUSUACMATR EBAIRRNO_1 EBAIRRLINK                       geometry
1          0 Boa Viagem       <NA> MULTIPOLYGON (((289794.1 90...
# Plotando o shape de Boa Viagem
ggplot(Boa_viagem) +
  geom_sf() +
  theme_light()

# Unindo poligonos no shapefile
novo_recife = recife |>  
   group_by(CRPAAACODI) |>  
   summarize(n = n())

# Visualizando o novo objeto
novo_recife
Simple feature collection with 6 features and 2 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 277547.5 ymin: 9098032 xmax: 295287.7 ymax: 9123296
Projected CRS: SIRGAS 2000 / UTM zone 25S
# A tibble: 6 x 3
  CRPAAACODI     n                                                      geometry
       <dbl> <int>                                                 <POLYGON [m]>
1          1    11 ((291961.1 9106271, 291904.5 9106181, 291809.5 9106087, 2918…
2          2    18 ((292947.8 9110818, 292828.9 9110761, 292304.3 9110516, 2922…
3          3    29 ((291025.2 9109306, 291015 9109290, 291011.5 9109285, 290968…
4          4    12 ((290538.5 9108381, 290538.7 9108375, 290539.1 9108365, 2905…
5          5    16 ((287570 9103879, 287570.4 9103875, 287570.4 9103875, 287565…
6          6     8 ((292546.5 9104121, 292546.5 9104121, 292509.4 9104020, 2924…
# Plotando o novo objeto
ggplot(data = novo_recife) +
  geom_sf(fill = "White") +
  theme_light()

Determinados shapifiles podem ser porduzidos com uma quantidade muito grande de pontos para definir os contornos da região de interesse. Nestes casos, os mapas que serão plotados serão pesados e provavelmente demoram a carregar. Existe uma forma de deixar esses arquivos mais leves nestes cenários.

# Carregando o pacote
library(rmapshaper)

# Simplificando o shape
Recife_simples = ms_simplify(input = recife,
                             keep = 0.1,
                             keep_shapes = TRUE)

O argumento input é o shape a ser simplificado, o keep é a proporção dos pontos que você deseja manter e o keep_shapes = TRUE impede que características pequenas dos polígonos sumam, no caso de uma grande simplificação.

# Plotando o objeto simplificado
ggplot(data = Recife_simples) +
  geom_sf(fill = "White") +
  theme_light()

2 - Mapa de pontos

Quando possuímos as coordenadas (lat/long) da ocorrência de um evento de interesse, uma visualização apropriada é a criação de um mapa de pontos. Neste mapa é possível avaliar a existência de aglomerações dos pontos em algumas localidades da região de interesse.

Atividade: Importem o arquivo nyshape.shp e armazenem em um objeto chamado NYShp.

# Visualizando o objeto
NYShp
Simple feature collection with 71 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -74.25559 ymin: 40.49612 xmax: -73.70001 ymax: 40.91553
Geodetic CRS:  WGS84(DD)
# A tibble: 71 x 4
   shape_leng boro_cd shape_area                                        geometry
        <dbl>   <dbl>      <dbl>                              <MULTIPOLYGON [°]>
 1     51550.     311 103177785. (((-73.97299 40.60881, -73.97259 40.60667, -73…
 2     65822.     313  88195686. (((-73.98372 40.59582, -73.98305 40.59541, -73…
 3     52246.     312  99525500. (((-73.9714 40.64826, -73.97121 40.64762, -73.…
 4     37008.     304  56663217. (((-73.89647 40.68234, -73.89653 40.682, -73.8…
 5     62240.     209 114266297. (((-73.83979 40.83562, -73.83967 40.8356, -73.…
 6     83998.     212 154896607. (((-73.79386 40.88364, -73.79417 40.88299, -73…
 7     35876.     206  42664311. (((-73.87185 40.84376, -73.87192 40.84345, -73…
 8     47817.     208  92071724. (((-73.89663 40.91142, -73.89663 40.9113, -73.…
 9     32820.     226  50566411. (((-73.8679 40.90294, -73.86796 40.90281, -73.…
10     43327.     317  93810207. (((-73.90755 40.65119, -73.90849 40.65059, -73…
# … with 61 more rows

Atividade: Importem o arquivo NYPD.csv e armazenem em um objeto chamado NYPD.

O arquivo contém dados sobre crimes ocorridos na cidade de Nova York. Entre as variáveis disponibilizadas, podemos citar o tipo do crime (TYPE), as coordenadas (latitude e longitude), entre outras.

# Visualizando o objeto
NYPD
# A tibble: 407 x 6
   LAW_CAT_CD TYPE      BORO_NM         Day Longitude Latitude
   <chr>      <chr>     <chr>         <dbl>     <dbl>    <dbl>
 1 FELONY     VANDALISM QUEENS            1     -73.7     40.7
 2 FELONY     ROBBERY   BRONX             1     -73.9     40.9
 3 FELONY     ROBBERY   QUEENS            3     -73.8     40.7
 4 FELONY     ROBBERY   BROOKLYN          4     -74.0     40.7
 5 FELONY     ROBBERY   QUEENS            2     -73.8     40.7
 6 FELONY     VANDALISM QUEENS            5     -73.8     40.7
 7 FELONY     ROBBERY   STATEN ISLAND     6     -74.2     40.6
 8 FELONY     ROBBERY   QUEENS            3     -73.7     40.7
 9 FELONY     ROBBERY   BRONX             2     -73.9     40.9
10 FELONY     MURDER    QUEENS            3     -73.8     40.7
# … with 397 more rows

Vamos fazer o mapa de pontos dos crimes na cidade de Nova York usando o ggplot2.

#Plotando as localizações dos delitos
ggplot(data = NYShp) +
  geom_sf(fill = "White") +
  geom_point(data = NYPD,
             aes(x = Longitude,
                 y = Latitude),
             colour = 'Dark Blue') +
  theme_light()

Vale ressaltar que o data indicado na função ggplot é o shape, já no geom_point foi preciso especificar um data diferente, a base de dados.

O pacote ggmap fornece uma função que nos permite criar um mapa de pontos diferente.

#Uma outra possibilidade
library(ggmap)
qmplot(x = Longitude, 
       y = Latitude, 
       data = NYPD,
       colour = I('red'), 
       size = I(1.5), 
       darken = 0.3)

No mapa acima, o size controla o tamanho, o darken a opacidade e o colour a cor do ponto. Percebam, que não precisamos do shape para construir o mapa.

Tanto com o ggplot como no ggmap é possível criar mapas de pontos indicando os diferentes tipos de crime, por exemplo.

# Mapa de pontos indicando o tipo de crime com o ggplot2 
mapa1 = ggplot(data = NYShp) +
  geom_sf(fill = "White") +
  geom_point(data = NYPD,
             aes(x = Longitude,
                 y = Latitude,
                 colour = TYPE),
             size = 0.8) +
  theme_light()


# Mapa de pontos indicando o tipo de crime com o ggmap 
mapa2 = qmplot(x = Longitude, 
       y = Latitude, 
       data = NYPD,
       colour = TYPE, 
       size = I(1), 
       darken = 0.3)

# Carregando pacote
library(gridExtra)

#Plotando os dois maps
grid.arrange(mapa1,mapa2, ncol=2)

Atividade: Com base no conteúdo da disciplina visto até o momento, crie o código necessário para reproduzir a visualização abaixo.

3 - Mapa coroplético

Mapas coropléticos são usados em cenários no qual a variável de interesse foi observada de forma agregada para alguma partição em áreas do espaço de interesse. Por exemplo, suponha que foram observados o número de roubos de carros nos bairros da cidade do Rio de Janeiro. Neste cenário, a região de interesse é o Rio de Janeiro, que está particionada em seus bairros e a variável foi observada de forma agregada paea cada área.

Atividade: Importe o arquivo Vendas_agregada_bairro.csv e guarde em um objeto chamado base_venda.

A base fornece o registro do número de produtos vendidos (por semestre e no ano todo) por bairro de um determinado produto, entre outras.

#Visualinado a base de dados
base_venda
# A tibble: 94 x 6
   no_bairro_residencia num.vendas.1sem num.vendas.2sem num.vendas gasto
   <chr>                          <dbl>           <dbl>      <dbl> <dbl>
 1 PAU FERRO                          1               0          1  4460
 2 SANTO ANTONIO                      6               2          8  4590
 3 PAISSANDU                         11               4         15  4369
 4 ILHA DO LEITE                     18               1         19  4614
 5 SOLEDADE                           1              20         21  4788
 6 JAQUEIRA                          20               4         24  4652
 7 TORREAO                            3              27         30  4794
 8 CABANGA                            6              25         31  4647
 9 SANTANA                           12              21         33  4852
10 DERBY                             20              14         34  4832
# … with 84 more rows, and 1 more variable: porc_panfletagem <dbl>

Para criarmos um mapa coropléticos precisamos inicialmente acrescentar a variável de interesse ao shape. Faremos isso, fazendo um merge da base com o shape. Neste caso, usamos o left_join passando como base inicial o shape, para garantir que a base que será retornada terá exatamente as linhas que já existem no shape e usamos os nomes dos bairros para fazer a junção.

#Fazendo a relacao dos dois data frames
recife = left_join(x = recife, 
                   y = base_venda, 
                   by = c("EBAIRRNOME" = "no_bairro_residencia"))

# Visualizando o objeto
recife
Simple feature collection with 94 features and 15 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 277547.5 ymin: 9098032 xmax: 295287.7 ymax: 9123296
Projected CRS: SIRGAS 2000 / UTM zone 25S
First 10 features:
  CBAIRRCODI VBAIRROID         EBAIRRNOME CRPAAACODI CMICROCODI TBAIRRULAT
1         19         0             RECIFE          1          1 1899-12-30
2         27         0      SANTO ANTONIO          1          2 1899-12-30
3         35         0           SAO JOSE          1          2 1899-12-30
4         43         0 ILHA JOANA BEZERRA          1          3 1899-12-30
  CEMPRECODI AUSUACMATR         EBAIRRNO_1 EBAIRRLINK num.vendas.1sem
1          0          0             Recife       <NA>              39
2          0          0      Santo Antônio       <NA>               6
3          0          0           São José       <NA>             163
4          0          0 Ilha Joana Bezerra       <NA>             187
  num.vendas.2sem num.vendas gasto porc_panfletagem
1              42         81  4811        0.7075714
2               2          8  4590        0.1632857
3              58        221  4980        0.7220000
4             271        458  5082        0.7294286
                        geometry
1 MULTIPOLYGON (((294617.4 91...
2 MULTIPOLYGON (((293353.3 91...
3 MULTIPOLYGON (((292458 9107...
4 MULTIPOLYGON (((290464.9 91...
 [ reached 'max' / getOption("max.print") -- omitted 6 rows ]

A seguir, apresentamos o mapa coroplético do número de produtos vendidos no ano.

#Mapa coropletico do numero de vendas de produto
ggplot(data = recife) +
  geom_sf(aes(fill = num.vendas))

Como alterar características deste gráfico?

#Modificando o mapa coropletico
ggplot(data = recife) +
  geom_sf(aes(fill = num.vendas)) +
  scale_fill_gradient(name = "Vendas", 
                      low = "White", 
                      high = "Red") +
  theme_light() +
  theme(legend.title = element_text(size = 16,
                                    colour = "Red",
                                    face = "bold"),
        legend.text = element_text(size = 10,
                                    colour = "Red"))

O pacote tmap é outro pacote bastante útil para a criação de mapas coropléticos.

#Carregando pacote tmap
library(tmap)

#Construindo o mapa coropletico para vendas
tm_shape(shp = recife) + 
  tm_fill(col = "num.vendas",
          palette = "Greens",
          title = "Vendas")

## tm_shape - cria um elemento tmap que especifica um objeto espacial
## tm_fill - cria um elemento tmap que desenha e preenche o mapa
#Argumentos:
#shp - um objeto da classe sf
#col - a variavel/atributo que deseja plotar
#palette - a paleta de cores
#title - Nome que deseja mostrar no titulo da legenda


#Transformando em uma geometria valida
recife = st_make_valid(x = recife)

## st_make_valid - transforma uma geometria invalida em uma valida
#Argumentos:
#x - um objeto da classe sf

#Modificando o numero de intervalos
tm_shape(shp = recife) + 
  tm_fill(col = "num.vendas",
          n = 4,
          palette = "Greens",
          title = "Vendas")

#Definindo os limites e o numero de intervalos
mapa = tm_shape(shp = recife) + 
  tm_fill(col = "num.vendas",
          breaks = quantile(recife$num.vendas, probs = seq(0,1,.1)),
          palette = "Greens",
          title = "Vendas") +
  tm_borders(lwd = 0.75,
             lty = "solid")

## tm_borders - desenha as bordas que separam os poligonos
#Argumentos:
#lwd - espessura da borda
#lty - tipo de linha


#Visualizando o mapa
mapa

#Mudando o estilo do mapa com tm_style (pre-definido)
mapa + 
  tm_style("cobalt")

#Mudando o estilo do mapa com tm_layout (criar)
mapa + 
  tm_layout(title = "2018",
            legend.outside = TRUE,
            legend.text.color = "Dark Green")

## tm_layout - especifica configuracoes para o layout do mapa
#Argumentos:
#title - um titulo acima da legenda
#legend.outside - para a legenda aparecer ao lado de fora do mapa
#legend.text.color - cor da legenda

#Incluindo texto nos mapas
mapa +
  tm_text(text = "EBAIRRNOME",
          size = "num.vendas",
          legend.size.show = FALSE) +
  tm_layout(legend.outside = TRUE)

## tm_text - especifica nomes para os poligonos
#Argumentos:
#text - variavel que deseja aparecer como texto nos poligonos 
#size - numero ou uma variavel que vai determinar o tamanho da fonte
#legend.size.show - se deseja apresentar a legenda para os diferentes tamanhos da letra

#Grafico para mais de uma variavel
tm_shape(shp = recife) + 
  tm_fill(col = c("num.vendas.1sem","num.vendas.2sem"),
          title = c("1 Sem", "2 Sem"),
          palette = "Reds") +
  tm_facets(nrow = 1) +
  tm_borders() +
  tm_layout(legend.position = c("left","bottom"))

#Colocando todos os graficos em uma mesma escala
tm_shape(shp = recife) + 
  tm_fill(col = c("num.vendas.1sem","num.vendas.2sem"),
          title = "Vendas",
          palette = "Reds") +
  tm_facets(nrow = 1,
            free.scales = FALSE) +
  tm_borders() +
  tm_layout(panel.labels = c("1 Sem","2 Sem"))