Mapas no R com ggmap

Este tutorial mostra como adicionar uma ‘camada base’ ou fundo aos seus mapas de ggplot.

Informação espacial armazenada em data frames - pontos no google maps

Vamos começar a trabalhar com mapas a partir de um exemplo que, veremos, utilizará as ferramentas que aprendemos até então para produzir nossos primeiros mapas. Para tanto, vamos utilizar o cadastro de escolas que a Prefeitura Municipal de São Paulo disponibiliza aqui.

Nossa primeira tarefa é baixar os dados e faremos isso de forma inteligente e sem “cliques”. A partir do url do arquivo do cadastro, que guardaremos no objeto “url_cadatros_escolas”, faremos o download do arquivo e guardaremos o arquivo .csv baixado como o nome “temp.csv”:

library(tidyverse)
## Registered S3 methods overwritten by 'ggplot2':
##   method         from 
##   [.quosures     rlang
##   c.quosures     rlang
##   print.quosures rlang
## Registered S3 method overwritten by 'rvest':
##   method            from
##   read_xml.response xml2
## -- Attaching packages ---------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.1.1       v purrr   0.3.2  
## v tibble  2.1.1       v dplyr   0.8.0.1
## v tidyr   0.8.3       v stringr 1.4.0  
## v readr   1.3.1       v forcats 0.4.0
## -- Conflicts ------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
url_cadatros_escolas <- "http://dados.prefeitura.sp.gov.br/dataset/8da55b0e-b385-4b54-9296-d0000014ddd5/resource/39db5031-7238-4139-bcaa-e620a3180188/download/escolasr34fev2017.csv"
download.file(url_cadatros_escolas, "temp.csv")

Veja que baixar o arquivo diretamente no R é preferível ao processo manual, pois podemos rapidamente reproduzir o processo, além de documentá-lo. Vamos abrir o arquivo:

escolas <- read_delim("temp.csv", delim = ";")
## Parsed with column specification:
## cols(
##   .default = col_character(),
##   CODINEP = col_double(),
##   EH = col_double(),
##   LATITUDE = col_double(),
##   LONGITUDE = col_double()
## )
## See spec(...) for full column specifications.

Explore o arquivo com o comando glimpse:

glimpse(escolas)
## Observations: 5,324
## Variables: 51
## $ DRE         <chr> "G", "FO", "MP", "BT", "PJ", "BT", "FO", "JT", "JT...
## $ CODESC      <chr> "000086", "000094", "000108", "000191", "000205", ...
## $ TIPOESC     <chr> "EMEI", "EMEI", "EMEF", "EMEF", "EMEBS", "EMEI", "...
## $ NOMESC      <chr> "PAULO CAMILHIER FLORENCANO", "VICENTE PAULO DA SI...
## $ DIRETORIA   <chr> "GUAIANASES", "FREGUESIA/BRASILANDIA", "SAO MIGUEL...
## $ SUBPREF     <chr> "GUAIANASES", "CASA VERDE/CACHOEIRINHA", "SAO MIGU...
## $ CEU         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
## $ ENDERECO    <chr> "RUA FELICIANO DE MENDON\xc7A", "RUA DOUTOR FLEURY...
## $ NUMERO      <chr> "502", "295", "159", "140", "206", "90", "51", "34...
## $ BAIRRO      <chr> "JARDIM S\xc3O PAULO(ZONA LESTE)", "VILA SANTA MAR...
## $ CEP         <chr> "08460365", "02563010", "08090290", "05742100", "0...
## $ TEL1        <chr> "25578348", "39813227", "25865294", "58450121", "3...
## $ TEL2        <chr> "25571947", NA, "25811484", NA, "39067229", NA, NA...
## $ FAX         <chr> "25571947", NA, NA, "58450121", NA, "58425113", "3...
## $ SITUACAO    <chr> "Ativa", "Ativa", "Ativa", "Ativa", "Ativa", "Ativ...
## $ CODDIST     <chr> "31", "50", "44", "94", "63", "94", "29", "89", "8...
## $ DISTRITO    <chr> "GUAIANASES", "LIMAO", "JARDIM HELENA", "VILA SONI...
## $ SETOR       <chr> "3103", "5002", "4402", "9404", "6301", "9404", "2...
## $ CODINEP     <dbl> 35098711, 35098361, 35098760, 35098462, 35079029, ...
## $ CODCIE      <chr> "098711", "098361", "098760", "098462", "079029", ...
## $ EH          <dbl> 1.610781e+14, 1.610702e+14, 1.610771e+14, 1.610792...
## $ DT_CRIACAO  <chr> "13/06/1988", "04/07/1988", "05/07/1988", "27/05/1...
## $ ATO_CRIACAO <chr> "26.134", "26.314", "26.312", "26.003", "26.229", ...
## $ DOM_CRIACAO <chr> "13/06/1988", "04/07/1988", "05/07/1988", "27/05/1...
## $ DT_INI_FUNC <chr> "22/09/1988", "01/08/1988", "01/09/1988", "02/10/1...
## $ DT_AUTORIZA <chr> "16/03/1991", "16/03/1991", "13/03/2001", "16/03/1...
## $ NOME_ANT    <chr> NA, NA, "VILA NITRO OPERARIA", NA, NA, NA, "INSTAL...
## $ T2D3D       <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D15     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D14     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D13     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D12     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D11     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D10     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2...
## $ T2D3D09     <chr> "2D", "2D", "2D", "2D", "2D", "2D", "2D", "2D", "3...
## $ T2D3D08     <chr> "3D", "3D", "2D", "2D", "2D", "3D", "2D", "2D", "3...
## $ T2D3D07     <chr> "3D", "3D", "3D", "2D", "2D", "3D", "2D", "3D", "3...
## $ DTURNOS     <chr> "2D", "3D", "3D", "2D", "2D", "3D", "3D", "3D", "3...
## $ DTURNOS15   <chr> "MT", "MT", "MT", "MT", "MT", "MT", "MT", "MT", "M...
## $ DTURNOS14   <chr> "MT", "MT", "MT", "MT", "MT", "MT", "MT", "MT", "M...
## $ DTURNOS13   <chr> "MT", "MT", "MT", "MT", "MT", "MT", "MT", "MT", "M...
## $ DTURNOS12   <chr> "MT", "MT", "MT", "MT", "MTN", "MT", "MT", "MT", "...
## $ DTURNOS11   <chr> "MT", "MT", "MT", "MT", "MTN", "MT", "MT", "MT", "...
## $ DTURNOS10   <chr> "MT", "MT", "MTN", "MT", "MTN", "MT", "MT", "MT", ...
## $ DTURNOS09   <chr> "MT", "MT", "MTN", "MT", "MTN", "MT", "MT", "MT", ...
## $ DTURNOS08   <chr> "MT", "MT", "MTN", "MT", "MTN", "MT", "MT", "MT", ...
## $ DTURNOS07   <chr> "MIV", "MIV", "MTN", "MT", "MTN", "MIV", "MT", "MT...
## $ LATITUDE    <dbl> -23553905, -23489728, -23478312, -23612237, -23486...
## $ LONGITUDE   <dbl> -46398452, -46670198, -46427344, -46749888, -46733...
## $ REDE        <chr> "DIR", "DIR", "DIR", "DIR", "DIR", "DIR", "DIR", "...
## $ DATABASE    <chr> "28/02/2017", "28/02/2017", "28/02/2017", "28/02/2...

Não há nada de extraordinário no arquivo, que se assemelha aos que vimos até então. Há, porém, uma dupla de variáveis que nos permite trabalhar “geograficamente” com o dado: LATITUDE e LONGITUDE. “Lat e Long” são a informação fundamental de um dos sistemas de coordenadas (coordinate reference system, CRS) mais utilizados para localização de objetos na superfície da terra.

Por uma razão desconhecida, a informação fornecida pela PMSP está em formato diferente do convenional. Latitudes são representadas por números entre -90 e 90, com 8 casas decimais, e Longitudes por números entre -180 e 180, também com 8 casas decimais. Em nosso par de variáveis, o separador de decimal está omitido e por esta razão faremos um pequena modificação na variável. Aproveitaremos também para renomear algumas variáveis de nosso interesse – como tipo da escola (CEI, EMEI, EMEF, CEU, etc) e o ano de início do funcionamento – e selecionaremos apenas as linhas referentes a EMEF (Escolas Municipal de Ensino Fundamental):

emef <- escolas  %>%
  rename(lat = LATITUDE, lon = LONGITUDE, tipo = TIPOESC) %>% 
  mutate(lat = lat / 1000000, 
         lon = lon / 1000000,
         ano = as.numeric(substr(DT_INI_FUNC, 7, 10))) %>%
  filter(tipo == "EMEF")

Pronto! Temos agora uma informação geográfica das EMEFs e uma variável de interesse – ano – que utilizaremos para investigar a expansão da rede.

Para analisar estes dados como dados espaciais precisamos dizer a R quais são as variáveis de localização e transformá-lo em um objeto ‘simple features’ usando o biblioteca sf e a função st_as_sf para criar um objeto tipo “simple features”. Lembre-se de instalar o pacote antes de carregá-lo.

library(sf)
## Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3
emef <- emef %>% st_as_sf(coords=c("lon","lat"), crs=4326)

Vamos construir um primeiro mapa, usando a função que conhecemos – ggplot – a partir das informações de latitude e longitude das escolas:

emef %>% ggplot() +
  geom_sf()

Veja que podemos “imaginar” o formato da cidade de São Paulo com os pontos, mas o mapa não é propriamente um mapa. Falta uma “camada” básica, sobre a qual os pontos serão desenhados.

Vamos utilizar o pacote ggmap, que é um pacote para visualização de dados espaciais com o pacote ggplot2 para obter tal “camada”. Com a função get_map, faremos o download de um mapa que servirá de base para os pontos das EMEFs.

Por padrão, utilizaríamos a função get_map, que retorna um mapa de “terreno” e utiliza a API da Google, com zoom e escala automáticos. No entanto, a Google trocou os termos de uso da API e agora é necessário ter uma conta, informar o número do cartão de crédito e fazer autenticação via R. Por esta razão, vamos utilizamos a API ‘stamen’, que utiliza a função get_stamenmap em vez de get_map

library(ggmap)
## Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
## Please cite ggmap if you use it! See citation("ggmap") for details.
bbox_sp <- c(left = -46.869803,
             bottom = -23.774462,
             right = -46.4417181,
             top = -23.3921176)

Com as coordenadas da cidade, vamos obter um mapa de São Paulo:

map_sp <- map_sp <- get_stamenmap(bbox_sp, zoom = 12, maptype = "toner")
## Source : http://tile.stamen.com/toner/12/1514/2321.png
## Source : http://tile.stamen.com/toner/12/1515/2321.png
## Source : http://tile.stamen.com/toner/12/1516/2321.png
## Source : http://tile.stamen.com/toner/12/1517/2321.png
## Source : http://tile.stamen.com/toner/12/1518/2321.png
## Source : http://tile.stamen.com/toner/12/1519/2321.png
## Source : http://tile.stamen.com/toner/12/1514/2322.png
## Source : http://tile.stamen.com/toner/12/1515/2322.png
## Source : http://tile.stamen.com/toner/12/1516/2322.png
## Source : http://tile.stamen.com/toner/12/1517/2322.png
## Source : http://tile.stamen.com/toner/12/1518/2322.png
## Source : http://tile.stamen.com/toner/12/1519/2322.png
## Source : http://tile.stamen.com/toner/12/1514/2323.png
## Source : http://tile.stamen.com/toner/12/1515/2323.png
## Source : http://tile.stamen.com/toner/12/1516/2323.png
## Source : http://tile.stamen.com/toner/12/1517/2323.png
## Source : http://tile.stamen.com/toner/12/1518/2323.png
## Source : http://tile.stamen.com/toner/12/1519/2323.png
## Source : http://tile.stamen.com/toner/12/1514/2324.png
## Source : http://tile.stamen.com/toner/12/1515/2324.png
## Source : http://tile.stamen.com/toner/12/1516/2324.png
## Source : http://tile.stamen.com/toner/12/1517/2324.png
## Source : http://tile.stamen.com/toner/12/1518/2324.png
## Source : http://tile.stamen.com/toner/12/1519/2324.png
## Source : http://tile.stamen.com/toner/12/1514/2325.png
## Source : http://tile.stamen.com/toner/12/1515/2325.png
## Source : http://tile.stamen.com/toner/12/1516/2325.png
## Source : http://tile.stamen.com/toner/12/1517/2325.png
## Source : http://tile.stamen.com/toner/12/1518/2325.png
## Source : http://tile.stamen.com/toner/12/1519/2325.png
## Source : http://tile.stamen.com/toner/12/1514/2326.png
## Source : http://tile.stamen.com/toner/12/1515/2326.png
## Source : http://tile.stamen.com/toner/12/1516/2326.png
## Source : http://tile.stamen.com/toner/12/1517/2326.png
## Source : http://tile.stamen.com/toner/12/1518/2326.png
## Source : http://tile.stamen.com/toner/12/1519/2326.png
plot(map_sp)

Antes de alterar estes argumentos, vamos utilizar uma função “irmã” à ggplot, ggmap, para juntar o mapa de São Paulo com os pontos das escolas:

ggmap(map_sp) +
  geom_sf(data = emef, inherit.aes=F)
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Feio ainda, porém bastante mais informativo. Veja que combinamos duas fontes de dados: o cadastro da PMSP e um mapa obtido na API da Stamen.

Agora, vamos usar uma informação sobre as escolas para diferenciar os pontos. Os dados do cadastro não trazem informações muito interessantes sobre a escola e por isso utilizaremos o ano de criação. Em nosso desafio seguinte trabalharemos com informações sobre a escola que vêm de outra base do mesmo portal da prefeitura.

Introduziremos em nosso mapa uma escala de cores para diferenciar as EMEFs por ano de criação:

ggmap(map_sp) +
  geom_sf(data = emef, inherit.aes=F, aes(color=ano))
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Como era de se esperar, os pontos mais claros na cidade estão nos extremos e as EMEFs mais antigas, e geral, nos bairros que consolidaram mais cedo no processo de urbanização.