404 Not Found

404 Not Found


nginx

Rによる地図と空間データ:sf、ggplot2、Leafletの完全チュートリアル

地理空間データは、パンデミックマップ、Didiの配車サービス利用状況のヒートマップ、JD.comの配送対象エリアなど、実世界のプロジェクトにおいてますます重要になっています。このレッスンでは、Rを用いた地図の可視化について学びます。具体的には、sfパッケージを使ってベクトルデータを処理し、ggplot2で地図を作成し、Leafletを使ってインタラクティブな地図を構築する方法を解説します。

このレッスンを修了すると、R を使用して 4 種類の地図を作成できるようになります。具体的には、静的地図(ggplot2 + sf)、コロプレース地図、点密度地図、およびインタラクティブ地図(leaflet)です。

1. 学習内容



2. 物流ヒートマップにまつわるストーリー

(1) 課題:販売データに規模感が欠けている

アリスは全国販売を担当している。マネージャーが「どの州の売り上げが一番いい?」と尋ねた。アリスはスプレッドシートをしばらく眺めた後、マネージャーに「地図を見せて」と言った。

(2) Rを用いた解決策

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行のコードで、中国における売上を可視化した出版物レベルの地図



3. 空間データの基礎

(1) ベクターとラスター

100%
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

このレッスンでは、ベクトルデータ(点、線、面)について解説します。

(2) シェープファイルとは何ですか?

シェープファイル = ESRIのベクトルデータ規格であり、以下の4つのファイルで構成されています:

R
data/
├── china.shp         # Geometric Information (Coordinates)
├── china.shx         # Shape Index
├── china.dbf         # Property Information (Name, Population, etc.)
└── china.prj         # Projection Information (Coordinate System)
⚠️ 注意:4つのファイルは必ず同じディレクトリに配置してくださいshpファイルが「メインファイル」であり、その他は補助ファイルです。

GeoJSON

現代のウェブマップでは、一般的にGeoJSON(JSONをベースとした形式)が使用されています:

R
{
  "type": "Feature",
  "properties": {"name": "Beijing", "value": 1000},
  "geometry": {
    "type": "Point",
    "coordinates": [116.4, 39.9]
  }
}


4. sf パッケージ:Spatial Data Framework

(1) なぜSFを使うのか?

バッグ 特徴 おすすめ
sf モダン、Rのtidyverseスタイル、ggplot2との統合 ⭐⭐⭐
sp 旧式、Rの基本構文 ❌ 新規コードでは推奨されません
ラスター ラスターデータのみ ラスター

(2) インストールと読み込み

R
install.packages("sf")
library(sf)

(3) シェープファイルを読み込む

R
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) GeoJSONの読み込み

R
# Read GeoJSON
cities <- st_read("data/cities.geojson")
# or from URL
cities <- st_read("https://example.com/cities.geojson")

(5) シェープファイル/GeoJSONの作成

R
# Write shapefile
st_write(china, "output/china_new.shp")

# Write GeoJSON
st_write(china, "output/china.geojson")


5. CRS座標系

(1) CRSとは何ですか?

CRS(座標参照系)—地球の「球面」を「平面」に投影すること:

100%
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) 一般的なCRSコード

EPSG 名称 用途
4326 WGS84 GPS / 一般 (最も一般的)
3857 Web Mercator Google マップ、OpenStreetMap
4490 CGCS2000 中国国家座標系
32650 UTM 50N 高精度ローカル

(3) 座標系の変換

R
# 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) 緯度・経度の抽出

R
# Extracting Latitude and Longitude from Geometric Objects
coords <- st_coordinates(china)
# X = Longitude, Y = Latitude


6. ggplot2 と geom_sf を使った地図の作成

(1) ベースマップ

R
library(ggplot2)
library(sf)

ggplot(china) +
  geom_sf() +
  labs(title = "Map of China")

(2) 地図の着色(属性による着色)

R
# Color by Province
ggplot(china) +
  geom_sf(aes(fill = name)) +
  labs(title = "Provinces of China", fill = "Province") +
  theme_minimal()

(3) 幾何学的簡略化(パフォーマンスの最適化)

R
# 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) テーマのカスタマイズ

R
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. コロプレット図

(1) データの結合 + カテゴリ別グラフの作成

R
# 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) 分類(連続型 → 離散型)

R
# 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. 点密度プロット

R
# 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. Leaflet インタラクティブマップ

(1) インストールと基本操作

R
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) マーク(ラベル)を追加する

R
# 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) 円を追加する(サイズ順)

R
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) グラデーション着色

R
# 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) HTMLとして保存

R
# Save as a standalone HTML file (Shareable)
library(htmlwidgets)
saveWidget(m, "interactive_map.html", selfcontained = FALSE)


10. 完全な例:全国の売上ヒートマップ

以下は、このレッスンで取り上げた地図関連の概念をすべて結びつけた完全なワークフローの例です。

▶ サンプル:4つの都市の販売マップ(静的+インタラクティブ)

R
# ============================================
# 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))
▶ 試してみよう

期待される出力:


❓ よくある質問

Q: sf と sp、どちらを選べばいいですか? A: sf(Simple Features)は、Rの空間データの現代的な標準であり、tidyverseのスタイルに準拠し、dplyrやggplot2とシームレスに連携します。新しいコードにはsfを使用してください。旧式のspコードはもはやメンテナンスされていません。**

Q: 4326と3857のどちらを選べばいいですか? A: 4326(WGS84の緯度・経度)は一般的な用途やGPS用、3857(Web Mercator)は地図サービスやGoogle/OSM用です。ggplot2とsfでは通常4326が使用されますが、Leafletのデフォルトは3857です。**

Q: シェープファイルはどこからダウンロードできますか? A:

Q 地図に中国語の文字が文字化けして表示される場合はどうすればよいですか?
A family = "SimHei"theme() を追加してください。あるいは、borders(database = "world", regions = "China") にはデフォルトで中国語の名称がすでに含まれています。
Q 3Dマップを作成するにはどうすればよいですか?
A rayshader パッケージ(ggplot2のプロットを3Dに変換する)を使用するか、plotlyの3D散布図とマップの背景を組み合わせて使用してください。このレッスンでは、これについて詳しく説明しません。

📖 まとめ


📝 練習問題

  1. 基本演習:Alibaba Cloud DataVから中国の省に関するGeoJSONファイルをダウンロードし、st_read()を使用してインポートした後、ggplot() + geom_sf()を使って中国の基本地図を描いてください(色の塗りつぶしは行わないでください)。

  2. 基本問題:前の問題の地図を省ごとに色分けし(aes(fill = name)を使用)、さらにtheme_void()とテーマに沿ったデザインを追加してください。

  3. 基本演習borders(database = "world", regions = "China") および geom_point(data = cities, aes(lon, lat, size = sales)) を使用して、4つの都市について独自の緯度・経度座標を指定し、中国の都市地図を作成してください。

  4. 応用演習:5つの都市の販売データ(緯度・経度、売上高、カテゴリーを含む)をシミュレートし、Leaflet を使用してインタラクティブな地図を作成してください。① 売上高を円の大きさに反映させる;② カテゴリーを色で区別する;③ 詳細を表示するためのツールチップを追加する;④ 凡例とスケールを追加する。HTML 形式で保存してください。

  5. 課題:ワークフローの完成—中国の各省のGeoJSONデータをダウンロードし、31省の販売データをシミュレートする:① LEFT JOINを使用して地図に統合する ② cut() を使用して5つのカテゴリーに分類する ③ ggplot2を使用してカテゴリー別の統計グラフを作成する ④ グラフの書式設定を行う(タイトル/サブタイトル/中国語フォント) ⑤ Leafletを使用してインタラクティブなバージョンを作成する (凡例を含む) ⑥ PNGおよびHTML形式で保存する。スクリーンショットを撮影し、保存する。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%