R: R, mapas e dados espaciais
Última atualização: 2026-08-26
Dados geoespaciais estão se tornando cada vez mais importantes em projetos do mundo real — como mapas de pandemia, mapas de calor do serviço de transporte Didi e áreas de cobertura de entregas da JD.com. Nesta aula, aprenderemos sobre visualização de mapas no R: usando o pacote sf para processar dados vetoriais, o ggplot2 para criar mapas e o Leaflet para construir mapas interativos.
Ao concluir esta aula, você será capaz de criar quatro tipos de mapas usando o R: mapas estáticos (ggplot2 + sf), mapas coropléticos, mapas de densidade de pontos e mapas interativos (leaflet).
1. O que você vai aprender
- Fundamentos de dados espaciais (vetoriais/rastéricos, Shapefile, sistemas de coordenadas)
- O pacote sf lê e processa arquivos shapefile
- Criação de mapas com o ggplot2 e o geom_sf
- Sistemas de coordenadas CRS (WGS84 / Web Mercator)
- Mapa coroplético
- Mapa interativo do folheto
- Na prática: mapas de calor das vendas nas cidades chinesas
2. A história por trás de um mapa de calor de logística
(1) Desafio: os dados de vendas não dão uma noção de escala
Alice é responsável pelas vendas nacionais. O gerente perguntou: “Qual província tem as melhores vendas?” Depois de examinar a planilha por um tempo, o gerente disse: “Mostre-me um mapa.”
(2) Solução usando R
library(sf)
library(ggplot2)
# 1. View a Map of China
china <- st_read("china.shp")
# 2. Consolidate Sales Data
china_sales <- china |>
left_join(sales_by_province, by = c("name" = "province"))
# 3. Line Chart of Categorical Statistics
ggplot(china_sales) +
geom_sf(aes(fill = sales)) +
scale_fill_gradient(low = "lightblue", high = "darkred") +
labs(title = "National Sales Distribution", fill = "Sales")
3 linhas de código → um mapa das vendas na China com qualidade de publicação.
3. Fundamentos dos dados espaciais
(1) Vetorial x Raster
graph LR
A[Spatial Data] --> B[Vector Data<br/>Vector]
A --> C[Raster Data<br/>Raster]
B --> D[pt Point<br/>Line<br/>Polygon]
C --> E[Pixel Pixel<br/>Satellite image/Temperature Map]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
Esta aula aborda dados vetoriais (pontos, linhas e superfícies).
(2) O que é um shapefile?
Shapefile = padrão de dados vetoriais da ESRI, composto por quatro arquivos:
data/
├── china.shp # Geometric Information (Coordinates)
├── china.shx # Shape Index
├── china.dbf # Property Information (Name, Population, etc.)
└── china.prj # Projection Information (Coordinate System)
GeoJSON
Os mapas modernos na web costumam usar GeoJSON (baseado em JSON):
{
"type": "Feature",
"properties": {"name": "Beijing", "value": 1000},
"geometry": {
"type": "Point",
"coordinates": [116.4, 39.9]
}
}
4. O pacote sf: Estrutura de Dados Espaciais
(1) Por que usar SF?
| Bolsa | Características | Recomendação |
|---|---|---|
| sf | Moderno, no estilo R tidyverse, com integração ao ggplot2 | ⭐⭐⭐ |
| sp | Sintaxe básica do R no estilo antigo | ❌ Não recomendado para código novo |
| raster | Apenas para dados raster | Para raster |
(2) Instalação e carregamento
install.packages("sf")
library(sf)
(3) Ler o shapefile
library(sf)
# Read shapefile
china <- st_read("data/china.shp")
# Reading layer `china' from data source `data/china.shp' using driver `ESRI Shapefile'
# Simple feature collection with 34 features and 5 fields
# Geometry type: MULTIPOLYGON
# Dimension: XY
# Bounding box: xmin: 73.5 ymin: 3.5 xmax: 135 ymax: 53.5
# CRS: 4326 ← WGS84 Latitude and Longitude
# View Structure
print(china)
# It basically means data.frame More geometry col
# A tibble: 34 × 6
# name population ... geometry
# <chr> <int> <MULTIPOLYGON>
# Geometric Information
st_geometry(china)
st_crs(china) # Coordinate System
st_bbox(china) # Bounding Box
(4) Leitura de GeoJSON
# Read GeoJSON
cities <- st_read("data/cities.geojson")
# or from URL
cities <- st_read("https://example.com/cities.geojson")
(5) Gravar shapefile / GeoJSON
# Write shapefile
st_write(china, "output/china_new.shp")
# Write GeoJSON
st_write(china, "output/china.geojson")
5. Sistema de Coordenadas CRS
(1) O que é o CRS?
CRS (Sistema de Referência de Coordenadas) — Mapeamento da superfície “esférica” da Terra em um “plano”:
graph LR
A[Earth's Surface] -->|WGS84 4326<br/>Latitude and Longitude| B[Cartesian coordinates]
A -->|Web Mercator 3857<br/>m| B
A -->|China 2000<br/>m| B
(2) Códigos CRS comuns
| EPSG | Nome | Finalidade |
|---|---|---|
| 4326 | WGS84 | GPS / Geral (Mais comum) |
| 3857 | Web Mercator | Google Maps, OpenStreetMap |
| 4490 | CGCS2000 | Sistema Nacional de Coordenadas da China |
| 32650 | UTM 50N | Local de alta precisão |
(3) Transformação do sistema de coordenadas
# View Current CRS
st_crs(china)
# Coordinate Reference System:
# EPSG: 4326
# proj4string: "+proj=longlat +datum=WGS84 ..."
# Convert to Web Mercator (3857)
china_3857 <- st_transform(china, 3857)
# Convert to China 2000
china_4490 <- st_transform(china, 4490)
(4) Extração de latitude e longitude
# Extracting Latitude and Longitude from Geometric Objects
coords <- st_coordinates(china)
# X = Longitude, Y = Latitude
6. Criação de mapas com o ggplot2 e o geom_sf
(1) Mapa de base
library(ggplot2)
library(sf)
ggplot(china) +
geom_sf() +
labs(title = "Map of China")
(2) Mapas coloridos (coloração por atributo)
# Color by Province
ggplot(china) +
geom_sf(aes(fill = name)) +
labs(title = "Provinces of China", fill = "Province") +
theme_minimal()
(3) Simplificação geométrica (otimização de desempenho)
# World Map (>100,000 coordinate points) use st_simplify to simplify
china_simple <- st_simplify(china, dTolerance = 1000)
# Drawing (10x faster)
ggplot(china_simple) + geom_sf()
(4) Personalização do tema
ggplot(china) +
geom_sf(fill = "lightblue", color = "white", linewidth = 0.3) +
labs(title = "Map of China") +
theme_void() + # Hide Axes
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
legend.position = "none"
)
7. Mapa coroplético
(1) Combinar dados + Criar um gráfico categórico
# Simulated Sales Data
sales_by_province <- data.frame(
name = c("Beijing", "Shanghai", "Guangdong", "Jiangsu", "Zhejiang", "Sichuan", "Hubei", "Shaanxi"),
sales = c(5000, 4500, 4000, 3500, 3000, 2500, 2000, 1500)
)
# Merge into Map
china_sales <- china |>
left_join(sales_by_province, by = "name")
# Draw a categorical bar chart
ggplot(china_sales) +
geom_sf(aes(fill = sales), color = "white", linewidth = 0.3) +
scale_fill_gradient(
low = "lightyellow",
high = "darkred",
na.value = "gray90"
) +
labs(title = "National Sales Distribution", fill = "Sales (10,000 yuan)") +
theme_void() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
legend.position = "right"
)
(2) Categorização (Contínua → Discreta)
# Use cut to divide continuous values into 5 levels
china_sales <- china_sales |>
mutate(sales_level = cut(sales,
breaks = c(0, 1000, 2000, 3000, 5000),
labels = c("Low", "Mid", "High", "Very high"),
include.lowest = TRUE))
ggplot(china_sales) +
geom_sf(aes(fill = sales_level), color = "white", linewidth = 0.3) +
scale_fill_brewer(palette = "YlOrRd", na.value = "gray90") +
labs(title = "National Sales Grades", fill = "Level") +
theme_void()
8. Gráfico de densidade de pontos
# City Points (Latitude and Longitude + Sales)
cities <- data.frame(
name = c("Beijing", "Shanghai", "Guangzhou", "Shenzhen"),
lon = c(116.4, 121.5, 113.3, 114.1),
lat = c(39.9, 31.2, 23.1, 22.5),
sales = c(5000, 4500, 4000, 3000)
) |>
st_as_sf(coords = c("lon", "lat"), crs = 4326)
# Draw a point on the map
ggplot() +
geom_sf(data = china, fill = "lightgray", color = "white") +
geom_sf(data = cities, aes(size = sales), color = "red", alpha = 0.7) +
scale_size_continuous(range = c(2, 12), name = "Sales") +
labs(title = "Map of City Sales Locations") +
theme_void()
9. Mapa interativo do Leaflet
(1) Instalação e noções básicas
install.packages("leaflet")
library(leaflet)
# Basic Interactive Map
m <- leaflet() |>
addTiles() |> # OpenStreetMap Base Map
setView(lng = 116.4, lat = 39.9, zoom = 4) # Beijing as the center
m # Show in RStudio Viewer
(2) Adicionar uma marca (rótulo)
# Add a city
leaflet(cities) |>
addTiles() |>
addMarkers(
lng = ~lon, lat = ~lat,
popup = ~paste0("<b>", name, "</b><br>Sales: ", sales, " 10,000 yuan"),
label = ~name
)
(3) Adicionar círculos (por tamanho)
leaflet(cities) |>
addTiles() |>
addCircles(
lng = ~lon, lat = ~lat,
radius = ~sqrt(sales) * 1000, # By Sales Radius
color = "red",
fillOpacity = 0.5,
popup = ~paste0(name, ": ", sales, "10,000 yuan")
)
(4) Coloração em tons
# Use sf Data
leaflet(china_sales) |>
addTiles() |>
addPolygons(
fillColor = ~colorNumeric("YlOrRd", sales)(sales),
fillOpacity = 0.7,
color = "white",
weight = 1,
popup = ~paste0("<b>", name, "</b><br>Sales: ", sales, " 10,000 yuan")
) |>
addLegend(pal = colorNumeric("YlOrRd", china_sales$sales),
values = ~sales, title = "Sales")
(5) Salvar como HTML
# Save as a standalone HTML file (Shareable)
library(htmlwidgets)
saveWidget(m, "interactive_map.html", selfcontained = FALSE)
10. Exemplo completo: Mapa de calor das vendas nacionais
A seguir, apresentamos um exemplo de um fluxo de trabalho completo que reúne todos os conceitos relacionados a mapas abordados nesta aula.
▶ Exemplo: 4 mapas de vendas de cidades (estáticos + interativos)
# ============================================
# 4 City Sales Map
# Features: ggplot2 Static Map + leaflet Interactive Map
# ============================================
library(sf)
library(ggplot2)
library(dplyr)
library(leaflet)
library(htmlwidgets)
# 1. Prepare data
# 4 City Points (Latitude and Longitude)
cities <- data.frame(
name = c("Beijing", "Shanghai", "Guangzhou", "Shenzhen"),
lon = c(116.4074, 121.4737, 113.2644, 114.0579),
lat = c(39.9042, 31.2304, 23.1291, 22.5431),
sales = c(5000, 4500, 4000, 3000),
region = c("Northern China", "East China", "South China", "South China")
) |>
st_as_sf(coords = c("lon", "lat"), crs = 4326)
# Simplified Polygons of China's Provinces (Sample data here)
china_provinces <- data.frame(
name = c("Beijing", "Shanghai", "Guangdong Province"),
lat = c(39.9, 31.2, 23.1),
lon = c(116.4, 121.5, 113.3)
)
# 2. Static Map: ggplot2 + sf
p_static <- ggplot() +
# Simplify: use geom_point Replace geom_sf (no shapefile)
borders(database = "world", regions = "China",
fill = "lightgray", color = "white") +
geom_sf(data = cities, aes(size = sales, color = region),
alpha = 0.7) +
geom_text(data = as.data.frame(st_coordinates(cities)),
aes(X, Y, label = cities$name),
vjust = -1.5, size = 4, fontface = "bold") +
scale_size_continuous(range = c(3, 12), name = "Sales (10,000 yuan)") +
scale_color_brewer(palette = "Set1", name = "Region") +
labs(title = "China 4 Sales Distribution in Major Cities",
subtitle = "Data: 2024 Q4",
caption = "Base Map: Natural Earth | Chart: R + ggplot2") +
coord_sf(xlim = c(100, 125), ylim = c(20, 45)) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
legend.position = "bottom"
)
print(p_static)
# 3. Save Static Image
ggsave("static_sales_map.png", p_static,
width = 10, height = 8, dpi = 300)
cat("=== The static map has been saved: static_sales_map.png ===\n")
# 4. Interactive Map: leaflet
cities_df <- as.data.frame(st_coordinates(cities)) |>
rename(lon = X, lat = Y) |>
cbind(name = cities$name, sales = cities$sales, region = cities$region)
m_interactive <- leaflet(cities_df) |>
addTiles() |>
setView(lng = 114, lat = 33, zoom = 4) |>
addCircleMarkers(
lng = ~lon, lat = ~lat,
radius = ~sqrt(sales) / 5,
color = ~case_when(
region == "Northern China" ~ "red",
region == "East China" ~ "blue",
region == "South China" ~ "green"
),
fillOpacity = 0.6,
stroke = TRUE,
weight = 2,
popup = ~paste0(
"<div style='font-family: Arial; font-size: 14px;'>",
"<b>", name, "</b><br>",
"Region: ", region, "<br>",
"Sales: ", sales, " 10,000 yuan<br>",
"Longitude: ", round(lon, 2), "<br>",
"Latitude: ", round(lat, 2),
"</div>"
),
label = ~paste0(name, ": ", sales, "10,000 yuan")
) |>
addLegend(
"bottomright",
colors = c("red", "blue", "green"),
labels = c("Northern China", "East China", "South China"),
title = "Region"
) |>
addScaleBar(position = "bottomleft")
# 5. Show (in RStudio Viewer)
m_interactive
# 6. Save as HTML
saveWidget(m_interactive, "interactive_sales_map.html",
selfcontained = TRUE)
cat("=== The interactive map has been saved: interactive_sales_map.html ===\n")
# 7. Output Statistics
cat("\n=== Sales Statistics ===\n")
print(cities_df |> select(name, region, sales))
Resultado esperado:
- Mapa estático (PNG, 300 dpi, mostrando as vendas por 4 tamanhos de ponto)
- Mapa interativo (HTML; as dicas de informação aparecem ao passar o mouse)
❓ Perguntas Frequentes
P: O que devo escolher, sf ou sp? R: sf (Simple Features) é o padrão moderno para dados espaciais no R, segue o estilo do tidyverse e se integra perfeitamente ao dplyr e ao ggplot2. Use sf para códigos novos; o código antigo do sp não é mais mantido.**
P: Como faço para escolher entre 4326 e 3857? R: 4326 (latitude e longitude WGS84) é para uso geral + GPS; 3857 (Web Mercator) é para serviços de mapas + Google/OSM. O ggplot2 + sf normalmente usa 4326, enquanto o Leaflet usa 3857 por padrão.**
P: Onde posso baixar o shapefile? R:
- Mapa da China: Alibaba Cloud DataV.GeoAtlas (https://datav.aliyun.com/portal/school/atlas/area_selector)
- Mapa-múndi: Natural Earth (https://www.naturalearthdata.com/)
- Mapa detalhado da China: https://github.com/longwosion/geojson-map-china
P: O que devo fazer se o mapa exibir caracteres chineses distorcidos? R: Adicione
family = "SimHei"atheme(). Como alternativa,borders(database = "world", regions = "China")já inclui os nomes em chinês por padrão.
P: Como faço para criar um mapa 3D? R: Use o pacote
rayshader(que converte gráficos do ggplot2 para 3D) ou o gráfico de dispersão 3D doplotlycombinado com um fundo de mapa. Não entraremos em detalhes sobre isso nesta aula.
P: O que devo escolher para mapas — Leaflet ou ggplot2? R:
- Relatórios/artigos que utilizam o ggplot2 (estáticos, com qualidade para publicação)
- Site/Aplicativo utilizando o Leaflet (interativo, com zoom)
- Compartilhável: Exportar HTML usando o Leaflet
📖 Resumo
- Dados espaciais = vetores (pontos/linhas/polígonos) + rasters (pixels); esta aula aborda os vetores
- Um Shapefile é composto por quatro arquivos (.shp, .shx, .dbf e .prj); o GeoJSON é um formato moderno para a web
- sf é o padrão moderno para dados espaciais em R, no estilo do tidyverse
- Sistemas de Referência Cartográfica (CRS) comumente utilizados: 4326 (latitude e longitude WGS84) / 3857 (Web Mercator)
ggplot2 +
geom_sf()para desenhar mapas estáticos; o mapa coroplético utilizaaes(fill = value)+scale_fill_gradient - folheto sobre mapas interativos: addTiles (mapa base) + addMarkers/addCircles (pontos) + addPolygons (regiões)
borders(database = "world")Desenhe rapidamente um mapa-múndi (sem necessidade de arquivo Shapefile)- Salvar:
ggsave()PNG/PDF para conteúdo estático;saveWidget()HTML para conteúdo interativo - Aplicações do R Map: Distribuição geográfica de empresas, pandemia, logística, distribuição de clientes, mapas de calor
📝 Exercícios
-
Exercício básico: Baixe o arquivo GeoJSON das províncias da China no Alibaba Cloud DataV, importe-o usando
st_read()e utilizeggplot() + geom_sf()para desenhar um mapa básico da China (sem preencher com cores). -
Questão básica: Pinte o mapa da questão anterior por província (usando
aes(fill = name)) e, em seguida, adicionetheme_void()e um desenho temático. -
Exercício básico: Use
borders(database = "world", regions = "China")+geom_point(data = cities, aes(lon, lat, size = sales))para traçar um mapa das cidades chinesas, com coordenadas personalizadas de latitude e longitude para quatro cidades. -
Exercício avançado: Simule dados de vendas para 5 cidades (incluindo latitude/longitude, valores de vendas e categorias) e use o Leaflet para criar um mapa interativo: ① Relacione os valores de vendas ao tamanho dos círculos; ② Relacione as categorias às cores; ③ Adicione dicas de ferramenta para exibir detalhes; ④ Adicione uma legenda e uma escala. Salve como HTML.
-
Desafio: Fluxo de trabalho completo — Baixe os dados GeoJSON das províncias da China e simule dados de vendas para as 31 províncias: ① Faça a junção no mapa usando um LEFT JOIN ② Use
cut()para dividir em 5 categorias ③ Crie um gráfico estatístico categorizado usando o ggplot2 ④ Formate o gráfico (título/subtítulo/fonte chinesa) ⑤ Crie uma versão interativa usando o Leaflet (incluindo uma legenda) ⑥ Salve como PNG e HTML. Faça uma captura de tela e salve-a.