次元の海で溺れる

Rとデータ解析と統計手法たちとわたし

【sp,ggplot2,leaflet】日曜日なので豆について考えてみた(3)

待てど暮らせど春が来ない。

本日のテーマ

使い回し続けている大豆データで、
コロプレス図を色んな方法で書きまくります。

コロプレス図、色んな方法で描けるのだけど、
各方法の描画の仕方と見え方について比較などしてみたくなった、というのが動機です。

あとどさくさに紛れてWindowsfontの適用をやっと覚えたのでメモ。

データ

wafdata.hatenablog.com
wafdata.hatenablog.com


シリーズで使いまわしている大豆に関するデータ(農林水産省/大豆関連データ集)と、
Nipponパッケージをインストールすると入る日本のシェープファイルを使います。

前処理については前回(たぶん)やっているので端折りますが、

・NipponパッケージのシェープファイルをSpatialPolygonsDataFrameとして読み込み
・@data部に、大豆データの「都道府県別納豆消費量(円)」「都道府県別豆腐消費量(円)」「都道府県別大豆生産量(t)」をマージ

して、以下の状態になっています。

#データ部だけ抜き出すとこんな感じ

> knitr::kable(map@data)


|SP_ID |jiscode |name      | population|region           | natto| tofu| mame_t|
|:-----|:-------|:---------|----------:|:----------------|-----:|----:|------:|
|1     |01      |Hokkaido  |    5506419|Hokkaido         |  3847| 4362|  73600|
|2     |02      |Aomori    |    1373339|Tohoku           |  4807| 5140|   5370|
|3     |03      |Iwate     |    1330147|Tohoku           |  4654| 6945|   5470|
|4     |04      |Miyagi    |    2348165|Tohoku           |  5485| 6264|  19300|
|5     |05      |Akita     |    1085997|Tohoku           |  4477| 5123|   9640|
|6     |06      |Yamagata  |    1168924|Tohoku           |  5569| 5906|   7720|
|7     |07      |Fukushima |    2029064|Tohoku           |  5298| 5254|   2220|
|8     |08      |Ibaraki   |    2969770|Kanto            |  5916| 4839|   5410|
|9     |09      |Tochigi   |    2007683|Kanto            |  3962| 5111|   4250|
|10    |10      |Gunma     |    2008068|Kanto            |  4808| 5226|    444|
|11    |11      |Saitama   |    7194556|Kanto            |  4406| 6328|    786|
|12    |12      |Chiba     |    6216289|Kanto            |  4064| 6151|   1080|
|13    |13      |Tokyo     |   13159388|Kanto            |  3618| 5969|      4|
|14    |14      |Kanagawa  |    9048331|Kanto            |  3418| 5820|     64|
|15    |15      |Niigata   |    2374450|Chubu            |  4586| 5070|   8840|
|16    |16      |Toyama    |    1093247|Chubu            |  4329| 4927|   7630|
|17    |17      |Ishikawa  |    1169788|Chubu            |  3505| 5176|   2310|
|18    |18      |Fukui     |     806314|Chubu            |  3238| 4815|   2430|
|19    |19      |Yamanashi |     863075|Chubu            |  4501| 5274|    289|
|20    |20      |Nagano    |    2152449|Chubu            |  4157| 4510|   3380|
|21    |21      |Gifu      |    2080773|Chubu            |  3160| 5078|   3430|
|22    |22      |Shizuoka  |    3765007|Chubu            |  3735| 6057|    317|
|23    |23      |Aichi     |    7410719|Chubu            |  3348| 5350|   7180|
|24    |24      |Mie       |    1854724|Chubu            |  2429| 5307|   3750|
|25    |25      |Shiga     |    1410777|Kinki            |  2912| 5059|   9450|
|26    |26      |Kyoto     |    2636092|Kinki            |  2680| 5982|    455|
|27    |27      |Osaka     |    8865245|Kinki            |  1945| 5470|     20|
|28    |28      |Hyogo     |    5588133|Kinki            |  2289| 5709|   3320|
|29    |29      |Nara      |    1400728|Kinki            |  2421| 5408|    256|
|30    |30      |Wakayama  |    1002198|Kinki            |  1994| 4864|     43|
|31    |31      |Tottori   |     588667|Chugoku          |  2658| 6728|   1120|
|32    |32      |Shimane   |     717397|Chugoku          |  2605| 6213|   1320|
|33    |33      |Okayama   |    1945276|Chugoku          |  2428| 4534|   2370|
|34    |34      |Hiroshima |    2860750|Chugoku          |  2592| 5258|    667|
|35    |35      |Yamaguchi |    1451338|Chugoku          |  2744| 4971|   1020|
|36    |36      |Tokushima |     785491|Shikoku          |  2306| 6763|     45|
|37    |37      |Kagawa    |     995842|Shikoku          |  2528| 5425|     97|
|38    |38      |Ehime     |    1431493|Shikoku          |  2628| 6170|    457|
|39    |39      |Kochi     |     764456|Shikoku          |  2017| 6009|     61|
|40    |40      |Fukuoka   |    5071968|Kyushu / Okinawa |  3125| 4563|  14300|
|41    |41      |Saga      |     849788|Kyushu / Okinawa |  3317| 6053|  15300|
|42    |42      |Nagasaki  |    1426779|Kyushu / Okinawa |  2672| 4824|    496|
|43    |43      |Kumamoto  |    1817426|Kyushu / Okinawa |  3861| 5417|   3710|
|44    |44      |Oita      |    1196529|Kyushu / Okinawa |  3604| 6288|   1690|
|45    |45      |Miyazaki  |    1135233|Kyushu / Okinawa |  2937| 5239|    317|
|46    |46      |Kagoshima |    1706242|Kyushu / Okinawa |  3513| 5471|    301|
|47    |47      |Okinawa   |    1392818|Kyushu / Okinawa |  2389| 7478|      1|

早速描く~spplot編~

spパッケージの中に、spplot()なる関数があるので、これでSP系の地図描画が出来ます。

これの便利なとこは、
何も考えずにSPDFを突っ込んじゃってOKなところ、と、
zcolという引数にc()で束ねた列を与えることで、同じ凡例を使った複数のコロプレス図を並べて描けるところ。
(何を言っているのか分からない文章)

とりあえずまずはデフォルトの状態で描いてみる。

#納豆と豆腐の消費額コロプレス図を並べて描く

> sp::spplot(map,zcol=c("natto","tofu"),names.attr=c("納豆","豆腐"))

f:id:WAFkw:20160221215205p:plain


簡単にすっきり並べられた!!

....けどこう...なんかこう...デフォルトの色味がこう...いかがわしい。
なんかとてもいかがわしい色味。

ということでもう少し手を入れてみる。

消費額を離散化して、at引数に入れる。(1000円ごとに8グループ)
かつ、RColorBrewerパッケージの色パレットを適用させてみる。

#8階層に分けて色を決める

c(0,1000,2000,3000,4000,5000,6000,7000,8000) %>% 
sp::spplot(map,zcol=c("natto","tofu"),at=.,names.attr=c("納豆","豆腐"),
           col.regions=RColorBrewer::brewer.pal(8,"BuPu"))

f:id:WAFkw:20160221215645p:plain

清純な感じになりました。
親御さんもこれで一安心です。

結果については前回記事でもグダグダ言ってましたが、
納豆の地域差が東西ではっきり出ていて、豆腐はそんなに地域差は無さそう,,

早速描く~ggplot2編~

次はみんな大好きggplot2で描きます。

が、その前に、
「plot内のフォントがどうしても綺麗じゃなくてやる気が出ない」
症状が現れ始めたので、fontについて考えます。

ggplot2の描画にお好きなfontを指定するには、
theme()を使ってelement_textを変更して、(font)familyを指定してあげればOK!なんだけど、

その前にfontfamilyにお好きなfontを追加したい...メイリオとかメイリオとかメイリオとかね...

font変更周りはmacの情報しか見つからず、
挙げ句うまくいかなくて唸っておりました。

が、下記記事でWindowsfont()をかませないとダメなことを知る。

http://sudori.info/stat/stat_fig_font.htmlsudori.info

#フォントファミリーの指定
#メイリオを"MEI"というfamilyとして定義

windowsFonts(MEI=windowsFont("Meiryo"))

これでいける、はず。

気を取り直して描画。
ggplot2ではSPDFも受け入れてくれるらしいのだけれど、
いったんfortify()してデータ整形する練習をしてみる。

> map_df<-ggplot2::fortify(map) #dataframeに変換
> knitr::kable(head(map_df,10))


|     long|     lat| order|hole  |piece |group |id |
|--------:|-------:|-----:|:-----|:-----|:-----|:--|
| 139.7707| 42.3018|     1|FALSE |1     |0.1   |0  |
| 139.8711| 42.6623|     2|FALSE |1     |0.1   |0  |
| 140.1895| 42.8243|     3|FALSE |1     |0.1   |0  |
| 140.3062| 42.7741|     4|FALSE |1     |0.1   |0  |
| 140.5259| 42.9885|     5|FALSE |1     |0.1   |0  |
| 140.3279| 43.2196|     6|FALSE |1     |0.1   |0  |
| 140.3500| 43.3315|     7|FALSE |1     |0.1   |0  |
| 140.4959| 43.3704|     8|FALSE |1     |0.1   |0  |
| 140.7945| 43.1928|     9|FALSE |1     |0.1   |0  |
| 141.0210| 43.2348|    10|FALSE |1     |0.1   |0  |

SPDFをfortify()すると、
ポリゴン部の情報がdataframe化されるので、元々data部にあったregionや納豆&豆腐情報は載ってこない。
描画に使用するデータをマージする必要がありそう。

(変換前)SPDFのdata部・・・・・SP_ID:1~47
(変換後)fortify()後・・・・・id:0~46

ちょっとごちゃごちゃするけど、今回はSP_IDを1ズラして、idとJOINすることにした。
(後々考えたら行番号で一致させるのが正解。たぶん。)

>map_join<-data.frame(id=as.numeric(as.character(map@data$SP_ID)-1),map@data)#ポリゴンIDとのJOINKeyを強引に生成
>map_join$id<-as.character(map_join$id)

>map_df<- dplyr::left_join(map_df,map_join,by="id") #JOIN

> knitr::kable(head(map_df,10))


|     long|     lat| order|hole  |piece |group |id |SP_ID |jiscode |name     | population|region   | natto| tofu| mame_t|
|--------:|-------:|-----:|:-----|:-----|:-----|:--|:-----|:-------|:--------|----------:|:--------|-----:|----:|------:|
| 139.7707| 42.3018|     1|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 139.8711| 42.6623|     2|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.1895| 42.8243|     3|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.3062| 42.7741|     4|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.5259| 42.9885|     5|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.3279| 43.2196|     6|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.3500| 43.3315|     7|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.4959| 43.3704|     8|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 140.7945| 43.1928|     9|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|
| 141.0210| 43.2348|    10|FALSE |1     |0.1   |0  |1     |01      |Hokkaido |    5506419|Hokkaido |  3847| 4362|  73600|

やり方きれいじゃないですが、とりあえずJOINは成功。
ついでに離散化周りをやってから、描画。

#離散化
cut.line<-c(0,1000,2000,3000,4000,5000,6000,7000,8000)
cut.label<-c("0-1000円","1000-2000円","2000-3000円","3000-4000円","4000-5000円","5000-6000円","6000-7000円","7000-8000円")

map_df$natto.c<-cut(map_df$natto,cut.line,labels=cut.label)
map_df$tofu.c<-cut(map_df$tofu,cut.line,labels=cut.label)


#描画
(nattomap_2<-ggplot(map_df,aes(x=long,y=lat,map_id=region,fill=natto.c))+
  geom_map(map=map_df,colour="gray",size=0.8)+
  scale_fill_manual(values=RColorBrewer::brewer.pal(8,"Reds"))+
  ggtitle("都道府県別納豆消費量")+
  theme(plot.title=element_text(size = rel(2),family = "MEI"))+
  coord_map(projection="mercator"))

(tofumap_2<-ggplot(map_df,aes(x=long,y=lat,map_id=region,fill=tofu.c))+
  geom_map(map=map_df,colour="gray",size=0.8)+
  scale_fill_manual(values=RColorBrewer::brewer.pal(8,"YlOrRd"))+
  ggtitle("都道府県別豆腐消費量")+
  theme(plot.title=element_text(size = rel(2),family = "MEI"))+
  coord_map(projection="mercator"))

#並べてみる
grid.arrange(nattomap_2,tofumap_2,ncol=2,nrow=1)

f:id:WAFkw:20160221222900p:plain
f:id:WAFkw:20160221223004p:plain
f:id:WAFkw:20160221223029p:plain

描画のところのコードが汚くなってしまった。猛省。。
geom_map()の方のmapの指定は省略したいんだけどなあ..

さっき定義したメイリオフォントはうまく適用できた。幸せ。

しかし、
せっかく同じ基準で離散化してるのに、パレットがなんか5色と4色になってしまっているのが
どうにも納得がいかない。

外出しでちゃんと8レベル分色を決めて、凡例にも8レベル分出したいなあ...む。
spplot()の結果のように、同じ凡例を使えるようにしたいのだけれど。


なにはともあれ
ggplot2で描くコロプレス図の特徴は、
自由度が高いことと綺麗なこと、かな。もっと細かい指定も出来るしちゃんと描く時はこれがメインの方法になりそう。


早速描いてみる~leaflet編~

なんだか眠くなってきたのでさらっと。

SPDFをleafletにそのまま渡すと、
x,yの指定なしの場合はdata内のlong,latを見つけてきてマッピングしてくれます。

leafletでは離散化せず、元の消費額を連続値のままcolorNumeric()を使って色決めしてみます。

map_l<-map

#色決め

colset.n<-colorNumeric("Reds", domain = range(map_l@data$natto))
colset.t<-colorNumeric("Oranges", domain = range(map_l@data$tofu))
map_l$natto.col<-colset.n(map_l@data$natto) #わざわざ列を作らなくていい気がする
map_l$tofu.col<-colset.t(map_l@data$tofu)  #わざわざ列を作らなくていい気がする


#描画
leaflet() %>%
  addTiles() %>%
  addPolygons(data = map_l, color = ~natto.col, fillOpacity = 0.8, stroke = FALSE)
  
leaflet() %>%
  addTiles() %>%
  addPolygons(data = map_l, color = ~tofu.col, fillOpacity = 0.8, stroke = FALSE)

f:id:WAFkw:20160221224605p:plain
f:id:WAFkw:20160221224624p:plain

※動きません


leafletは描くのも楽だし見た目も綺麗だし
少し透過させるとTileの地図情報も読み取れるのがいいですね。



ちからつきる

じつはcoloplethrパッケージで描くのもやりたかったんだけど、
ほんじつはここでちからつきた

ゆうしゃろと、ここにねむる。


P.S 書籍発売ラッシュ

R言語徹底解説

R言語徹底解説

かのHadley神の「AdvancedR」邦訳版がついに。


個人的には7章が好きです。
7章が好きです。

Rをはじめたての頃は、結果が返ればまあいいや、だったところ、
だんだん関数のソースを見てごにょごにょするようになってくると

ここのメソッドの呼び出しはこれ何をどう呼んでんだ...?
とか
結局クラスってなんだ(n回目)
とか

もやもやと悩んでいたので、
そういう「そもそもRって何がどうなっている言語なのか」について向き合える本だと思っています。

(目をそらしていたともいう)

のちのちゆっくりと書きます。



あとあと

岩波DSも2巻が発売されたようで、今回は自然言語処理周りとのこと。

岩波データサイエンス Vol.2

岩波データサイエンス Vol.2

欲しいな..
積読したくないので来月かな・・・