読者です 読者をやめる 読者になる 読者になる

チョコレート狂地図 leafletバージョン

これをleafletで描きたい。

wafdata.hatenablog.com

こういうデータが手元にあるとする。(以前の記事で前処理したd_spreaddput()した結果です。dput()はオブジェクトをコードとしてダンプできる便利な関数です)

d <- structure(
  list(
    pref_alpha = c("aichi", "akita", "aomori", "chiba", "ehime", "fukui", "fukuoka", "fukushima", "gifu", "gunma", "hiroshima","hokkaido", "hyogo", "ibaraki", "ishikawa", "iwate", "kagawa", "kagoshima", "kanagawa", "kochi", "kumamoto", "kyoto", "mie", "miyagi", "miyazaki", "nagano", "nagasaki", "nara", "niigata", "oita", "okayama", "okinawa", "osaka", "saga", "saitama", "shiga", "shimane", "shizuoka", "tochigi", "tokushima", "tokyo", "tottori", "toyama", "wakayama", "yamagata", "yamaguchi", "yamanashi"),
    チョコレート  = c( 5092, 4639, 3470, 4633, 5038.66666666667, 5235.33333333333, 4090.83333333333, 4922.33333333333, 4804.66666666667, 4839, 5313.33333333333, 5478, 4881, 4805.66666666667, 6543, 4315.66666666667, 5478.33333333333, 5237.66666666667, 5003.75, 5428.33333333333, 4577, 5456, 4986.66666666667, 5063, 4534.66666666667, 5252, 4075.66666666667, 5619, 4799.66666666667, 5377, 4618.66666666667, 4174, 4114.33333333333, 4702.66666666667, 5238.66666666667, 4651.33333333333, 4539, 4790.83333333333, 5797.33333333333, 4477.33333333333, 5247, 5380, 5634.66666666667, 4501, 5697, 5852.33333333333, 5056.66666666667),
    チョコレート菓子  = c( 1147.66666666667, 1214.66666666667, 1125.66666666667, 1196.33333333333, 1667.33333333333, 1612.66666666667, 979.5, 1372.33333333333, 1229.66666666667, 1151.66666666667, 1308, 1975.66666666667, 1183.33333333333, 1221.66666666667, 1905.66666666667, 1358.66666666667, 1343.66666666667, 1629.33333333333, 1343.625, 1933.66666666667, 1080.66666666667, 1188.66666666667, 1354.66666666667, 1499.33333333333, 1247, 1474, 974, 1554.66666666667, 1161.66666666667, 1556.33333333333, 1466.33333333333, 1035.33333333333, 993.833333333333, 1537, 1184, 1395.33333333333, 1580.33333333333, 1400.16666666667, 1713.66666666667, 1557, 1123.33333333333, 1756.33333333333, 1682.66666666667, 1098.33333333333, 1720.66666666667, 1950, 1343.33333333333),
    合計  = c( 6239.66666666667, 5853.66666666667, 4595.66666666667, 5829.33333333333, 6706, 6848, 5070.33333333333, 6294.66666666667, 6034.33333333333, 5990.66666666667, 6621.33333333333, 7453.66666666667, 6064.33333333333, 6027.33333333333, 8448.66666666667, 5674.33333333333, 6822, 6867, 6347.375, 7362, 5657.66666666667, 6644.66666666667, 6341.33333333333, 6562.33333333333, 5781.66666666667, 6726, 5049.66666666667, 7173.66666666667, 5961.33333333333, 6933.33333333333, 6085, 5209.33333333333, 5108.16666666667, 6239.66666666667, 6422.66666666667, 6046.66666666667, 6119.33333333333, 6191, 7511, 6034.33333333333, 6370.33333333333, 7136.33333333333, 7317.33333333333, 5599.33333333333, 7417.66666666667, 7802.33333333333, 6400)
  ),
  .Names = c("pref_alpha", "チョコレート", "チョコレート菓子", "合計"),
  class = c("tbl_df", "tbl", "data.frame"),
  row.names = c(NA,-47L)
)

地図データの読み込み

まず、地図データを読み込み、都道府県ごとにまとめます。これもやり方は以前の記事をご参照ください。

library(rgdal)
library(rgeos)

f <- "C:\\path\\to\\gm-jpn-bnd_u_2_1"

l <- readOGR(f, layer = "polbnda_jpn", encoding = "UTF-8",verbose = TRUE)
l_union <- gUnaryUnion(l, id = as.character(l@data$nam))

leafletでポリゴンを色分けをする方法

leafletにSpatialPolygonsDataFrameなどのGIS系のデータを渡すときにはdataという引数に渡すとだいたいいい感じに処理してくれます。

参考:Leaflet for R - Shapes

なので、単一の色でよければ以下のような感じになります。

leaflet() %>%
  addTiles() %>%
  addPolygons(data = l_union)

これに色を付けるには単純で、ポリゴンの数と同じ長さの色名のベクトルをcolorとかfillColorという変数に渡すことになります。適当に塗り分けるならこんな感じです。

colors <- rep(c("cyan", "magenta", "yellow"), length.out = length(l_union))

leaflet() %>%
  addTiles() %>%
  addPolygons(data = l_union, fillColor = colors, stroke = FALSE)

f:id:yutannihilation:20151101102917p:plain:w400

地図とデータを紐づける

dの値に応じて色分けするには、以下の処理が必要です。

  1. l_unionから県名を取り出す。
  2. 県名をキーにして、dのデータをl_unionと同じ順に並べる
  3. データの値から色を生成する
  4. addPolygons()に色を渡す

まず、l_unionから県名を取り出します。これは、@polygonsIDというところに値が入っています。

l_union@polygons[[1]]@ID
#> [1] "Aichi Ken"

これを取り出します。dと合わせるため、Kenなどのsuffixは省いて小文字にします。

ids <- sapply(l_union@polygons, function(x) x@ID) %>%
  str_to_lower %>%
  str_split(" ") %>%
  sapply(`[`, 1)

これでだいたい合うんですが、北海道だけはhokkaidoでないと困るので修正します。めんどくさい。。

ids
#>  [1] "aichi"     "akita"     "aomori"    "chiba"     "ehime"     "fukui"     "fukuoka"   "fukuoka"   "fukushima" "gifu"      "gunma"    
#> [12] "hiroshima" "hokkai"    "hyogo"     "ibaraki"   "ishikawa"  "iwate"     "kagawa"    "kagoshima" "kanagawa"  "kochi"     "kumamoto" 
#> [23] "kyoto"     "mie"       "miyagi"    "miyazaki"  "nagano"    "nagasaki"  "nara"      "niigata"   "oita"      "okayama"   "okinawa"  
#> [34] "osaka"     "saga"      "saitama"   "shiga"     "shimane"   "shizuoka"  "tochigi"   "tokushima" "tokyo"     "tottori"   "toyama"   
#> [45] "wakayama"  "yamagata"  "yamaguchi" "yamanashi"

ids[13] <- "hokkaido"

これとdを紐づける方法はたぶんいろいろありますが、いちどdata.frameをつくってからleft_join()するのが簡単そうです。

d_ordered <- 
  data.frame(ids = ids, stringsAsFactors = FALSE) %>%
  left_join(d, by = c("ids" = "pref_alpha"))

head(d_ordered)
#>      ids チョコレート チョコレート菓子     合計
#> 1  aichi     5092.000         1147.667 6239.667
#> 2  akita     4639.000         1214.667 5853.667
#> 3 aomori     3470.000         1125.667 4595.667
#> 4  chiba     4633.000         1196.333 5829.333
#> 5  ehime     5038.667         1667.333 6706.000
#> 6  fukui     5235.333         1612.667 6848.000

色を決める

次に、値の大きさに応じて色を割り当てます。

leafletには、そういうための関数がいくつか用意されています(colorXXX()という名前です)。今回は連続値が対象なのでcolorNumeric()を使います。これは、色のパレットと値の範囲を渡せば、色を割り当てる関数を作ってくれます。

values <- d_ordered$チョコレート
color_generator <- colorNumeric("Oranges", domain = range(values))

color_generator(5000)
#> [1] "#FD8E3D"

color_generator(values)
#>  [1] "#FB8534" "#FDAD69" "#FFF5EB" "#FDAD6A" "#FC8A39" "#F67825" "#FED8B3" "#FED8B3" "#FD9447" "#FE9F55" "#FE9C51" "#F4701D" "#EC620F"
#> [14] "#FD984C" "#FE9E55" "#7F2704" "#FEC997" "#EC620F" "#F67825" "#FD8D3C" "#EF6611" "#FDB271" "#ED6410" "#FD8F3F" "#FB8837" "#FEB678"
#> [27] "#F67624" "#FED9B5" "#E35608" "#FE9F56" "#F16A15" "#FDAE6C" "#FDD4A9" "#FED7B0" "#FDA761" "#F67825" "#FDAC68" "#FEB577" "#FEA057"
#> [40] "#D64701" "#FEBB80" "#F67724" "#F16A14" "#E25407" "#FEB97C" "#DE4F04" "#CE4402" "#FC8837"

値の範囲じゃなくて値そのままを渡しても結果は同じなんですけどよくわかりません。。

color_generator <- colorNumeric("Oranges", domain = values)

ともあれ色も決まったのでこれをleafletに渡せば完成です。

描く

leaflet() %>%
  addTiles() %>%
  addPolygons(data = l_union, color = color_generator(values), fillOpacity = 1, stroke = FALSE)

f:id:yutannihilation:20151101111517p:plain

動くバージョンはRpubsに置きました:RPubs - choropleth map with leaflet package

まとめ

けっこう道のりは長かったですが、choroplethrとくらべてどうでしょうか? shapefileの扱いがけっこうめんどくさいですけど、自由度は高そうです。

そんなかっこいい地図を描けるleafletパッケージについてぞうさんこと@kazutanさんがわかりやすく解説してくれるJapan.Rは 12/5 です。さあ、いますぐ参加登録だ!!!