leafletでのSpatialPolygonsDataFrameの扱いのメモ
前回の記事で、data
引数にSpatialPolygonsDataFrame(以下、SPDF)を渡したときにどうなるかわからなかったのでメモ。
SpatialPolygonsDataFrameとは
そもそもこいつは何者かというと、sp
パッケージの地図データ用のdata.frameです。
?"SpatialPolygonsDataFrame-class"
を見ると、以下のようなスロットを持っています。
data: Object of class "data.frame"; attribute table polygons: Object of class "list"; see SpatialPolygons-class plotOrder: Object of class "integer"; see SpatialPolygons-class bbox: Object of class "matrix"; see Spatial-class proj4string: Object of class "CRS"; see CRS-class
data
は各ポリゴンに関するデータ、polygons
はポリゴンのリストです。あとは細かそうなので省略。
SPDFはdata.frame同様に扱えます。[
やsplit
でサブセットを作ると、ポリゴンとそれに紐づくデータが適切にサブセットされます。
l[1:10, ] %>% is #> [1] "SpatialPolygonsDataFrame" "SpatialPolygons" "Spatial"
SPDF全体のサブセットではなく、データ(data
スロット)だけがほしいときは$
を使います。
l$nam %>% is #> [1] "factor" "integer" "oldClass" "numeric" "vector" "data.frameRowLabels"
data
とかpolygons
とか、S4オブジェクトの要素(スロット)に直接アクセスしたいときは@
を使います。
l@polygons %>% is #> [1] "list" "vector" l@polygons[[1]] %>% is #> [1] "Polygons"
leafletによる扱い
SPDFをdata
引数に指定した場合は以下のような処理になるみたいです。
ポリゴン部分の扱い
derivePolygons()
polygonData()
polygonData.SpatialPolygonsDataFrame()
でsp::polygons()
を適用してSpatialPolygons
クラスに変換polygonData.SpatialPolygons()
polygons2coords()
plural2coords()
あとは追えないのでパス。とりあえずむりやりやってみると、以下のようになります。
leaflet:::derivePolygons(l, NULL, NULL, TRUE, TRUE) %>% .[[1]] %>% str(max.level = 2) #> List of 1 #> $ :List of 2 #> ..$ lng: num [1:255] 141 141 141 141 141 ... #> ..$ lat: num [1:255] 43.2 43.2 43.1 43.1 43.1 ...
ということで、lng
, lat
というベクトルを持つリストのリストができています。addPolygons()
のドキュメントを見ると、lng
のヘルプに以下のような記載があります。
(if not explicitly provided), it will be automatically inferred from data by looking for a column named lng, long, or longitude (case-insensitively)
つまり、lng
とlat
を明示的に指定したりしなくても、ここで変換したポリゴンのdata.frame
の緯度経度を勝手に使ってくれます。
データ部分の扱い
データ部分は~XXX
という形式で列名を参照することができます。これはどういうことかというと、
color_generator <- colorNumeric("Oranges", domain = c(0, 1000)) leaflet() %>% addTiles() %>% addPolygons(data = poly, color = color_generator(poly$x))
と、poly$x
という形で直接値を渡す部分を、
leaflet() %>% addTiles() %>% addPolygons(data = poly, color = ~color_generator(x))
のように書けるということです。(color_generator(~x)
だとエラーになるので注意)
こっちのほうがかっこよさそうなので、前回のを書き直してみたいと思います。
SpatialPolygonsをSpatialPolygonsDataFrameに
rgeos::gUnaryUnion()
した結果は@data
がないSpatialPolygonsというクラスのオブジェクトです。これにデータを紐づけてSPDFをつくります。
SPDFは、data.frameをrownameでポリゴンのIDと紐づけます。なので、rownameのあるdata.frameを作る必要があります。
# d: data.frame # l_union: SpatialPolygons orig_ids <- sapply(l_union@polygons, function(x) x@ID) target_ids <- sapply(str_split(str_to_lower(orig_ids), " "), `[`, 1) id_crsp <- data.frame(orig_id = orig_ids, target_id = target_ids, stringsAsFactors = FALSE) id_crsp[13,"target_id"] <- "hokkaido" d_ordered <- right_join(id_crsp, d, by = c( "target_id" = "pref_alpha" )) rownames(d_ordered) <- id_crsp$orig_id
これをSpatialPolygonsDataFrame()
に渡せばおわりです。
s <- SpatialPolygonsDataFrame(l_union, as.data.frame(d_ordered))
描く
これを~
を使って書くと、以下のような書き方になります。
color_generator <- colorNumeric("Oranges", domain = range(values)) leaflet(s) %>% addTiles() %>% addPolygons(color = ~color_generator(チョコレート), fillOpacity = 1, stroke = FALSE)
(結果は前回と同じなので省略)
感想
一度SPDFを作ってからやるとデータとポリゴンが紐づけられるので間違いがなくて安心ですが、ちょっと手間です。rownameでマッチさせるというのがけっこうトリッキーでつらかったです。