cucumber flesh

Rを中心としたデータ分析・統計解析らへんの話題をしていくだけ

ggplot2の凡例を制御するためのオプション show.legend

ggplot2の凡例に関する小話を2つ。べ、別に最近知ったわけじゃないんだからね!

geom_*(show.legend = FALSE) で凡例を非表示にする

ggplot2での作図で凡例を制御する関数として guides()があります。この関数内でグラフに使われる凡例のタイトルや並びを調整可能です。例えば、irisデータセットのSpeciesごとに色分けをした図の凡例の並びを入れ替えるには次のようにします。guides(color = guide_legend(reverse = TRUE)) がその処理を指定している箇所です。

library(magrittr)
library(ggplot2)
library(patchwork)
theme_set(theme_gray(base_size = 12, base_family = "IPAexGothic"))
p <-
  iris %>% 
  ggplot(aes(Species, Sepal.Length, color = Species)) +
  geom_boxplot()

p1 <- 
  p +
  ggtitle("color = Speciesを指定した時のデフォルト")
p2 <- 
  p +
  guides(color = guide_legend(reverse = TRUE)) +
  ggtitle("guides()で凡例の並びを変更")
p1 + p2 + plot_layout(ncol = 2)

f:id:u_ribo:20191212065732p:plain

この関数を利用して凡例を非表示にできます。あるいは guides() を使わず theme(legend.position = "none") でも良いです。

# 出力結果は省略
p +
  guides(color = FALSE)

一方で、凡例を非表示にするためにこの方法を利用すると、一つ使う関数が増えてしまいますし、関数内で指定する引数の値をうっかり忘れてしまうことがあります。私はよく、color = NULL とか color = NA と間違った指定をしてしまっていました。

そこで、表示しない凡例については、どの種類の図を描画するかを定義する geom_*()を実行する段階で指定できる show.legend 引数を使うと便利です。例えば先ほどの箱ひげ図、X軸のラベルとしてSpeciesが与えられているので凡例は消そうと思うと次のようにします。

# 出力結果は省略
iris %>% 
  ggplot(aes(Species, Sepal.Length, color = Species)) +
  geom_boxplot(show.legend = FALSE)

この引数オプション、最近実装された訳ではなく、昔からあります。ドキュメントにもしっかり書かれています(既定値はNA)。便利な機能はすでに用意されている…そういう気持ちでドキュメントを読み込んでいきたいと思いましたまる

sfオブジェクトの凡例を変更する

2019-01-12追記 id:yutannihilation さんのタレコミによると ggplot2 v3.3.0 からはgeometryの種類の判別が自動的に行われるようになるそうです。

notchained.hatenablog.com

ggplot2の凡例についてもう一つ。次は地理空間データを描画する際に利用する geom_sf() での話です。

geom_sf()でなんらかの凡例を表示させた際、デフォルトでは fill を指定した時のように四角形の枠が表示されます。

library(sf)
sf_nc <- 
  system.file("shape/nc.shp", package = "sf") %>% 
  st_read() %>% 
  .[seq.int(3), ]
ggplot() + 
  geom_sf(data = sf_nc, aes(fill = NAME))

f:id:u_ribo:20191212070124p:plain

対象の地物がポリゴンだと良いですがポイントやラインのデータだとモヤっとした気持ちになります。こうした凡例の種類を調整するのにも先ほどの show.legend が使えます。凡例の種類を枠ではなく点にしたいのであれば show.legend = "point" を与えます。

sf_point$size <- 
  as.character(sample(10))

p1 <- 
  ggplot() +
  geom_sf(data = sf_point, aes(color = size)) +
  ggtitle("geom_sf()のデフォルト")

p2 <- 
  ggplot() +
  geom_sf(data = sf_point, aes(color = size), 
          show.legend = "point") +
  ggtitle("show.legend = で凡例の種類を変更")

p1 + p2 + plot_layout(ncol = 2)

f:id:u_ribo:20191212070531p:plain

よかったですね。

また、この場合の凡例としては不適切ですが、 "line" を指定して線の凡例を得も得られます。

# 出力結果は省略
ggplot() +
  geom_sf(data = sf_point, aes(color = size), 
          show.legend = "line")

Enjoy!

標準的な公共交通機関の情報形式 GTFS をRで処理する: gtfsrouter編

f:id:u_ribo:20191117103306j:plain

この記事はRアドベントカレンダー2019の5日目の投稿です。昨日は id:ando_Roid さんの投稿でした。

はじめに

今回で4回目となる「東京公共交通オープンデータチャレンジ」の応募が始まりました。これは公共交通オープンデータやその他のオープンデータを活用したアプリケーションおよびサービスの提案に関するコンテストです。ここでは、鉄道、バス、航空などの交通機関のデータが、GTFS (General Transit Feed Specification) 形式で公開されています。

GTFSは公共交通機関の時刻表と地理的情報に関するオープンフォーマットとして定義されます。リアルタイムの運行情報を反映した動的データ (GTFS Realtime)と、ダイヤ改正等の事情がない限り安定した静的データがあり、GTFSといえば厳密には静的データの方を指します。複数の事業者・交通機関が共通の形式に従ってデータを整備することで、経路探索や時刻表のアプリケーション開発が容易になるのが利点です。そのため、GTFSを提案したGoogle以外でも広く使われています。日本の交通機関に関しても、GTFSをベースに日本独自の交通事情を加味しながら拡張されたフォーマット (GTFS-JP) が整備されています。

さて、今回はそんなGTFSをRで扱ってみようという記事になります。日本語の内容として id:nonki1974 さんがgtfsrパッケージの利用方法を スライドにまとめています。なのでここでは、もう一つの例として gtfsrouterパッケージを紹介します。

目次です。

  • はじめに
  • gtfsrouterパッケージ
    • デモデータの処理
    • data.tableによるGTFSデータの操作
  • RでGTFSデータを扱う際のTips
    • 連続値になっている時刻の変換
    • sfオブジェクトへの変換

gtfsrouterパッケージ

github.com

gtfsrouterパッケージの特徴として次の点が挙げられます。

  • 2019年12月5日現在、CRANに登録されている。gtfsrは未登録
    • ただし、現在はGitHub上の開発版を利用するのが良さそう (issue #14 参照)
  • GTFSデータをdata.tableオブジェクトとして処理するため、処理速度の高速化が期待できる
  • 指定時間内に移動可能な領域 (Isochrone map) の描画ができる

まずはパッケージを利用可能な状態にしておきます。CRANに登録されているバージョンではなくGitHub上の開発版をインストールします。

install.packages("remotes")
remotes::install_github("ATFutures/gtfs-router")
# gtfs_isochrone()を実行する際に必要です
# install.packages(c("alphahull", "geodist"))
続きを読む

住所や年号、漢数字のデータ操作を楽にするRパッケージをCRANに登録しました

副題「失われた『Nippon』を求めて」(仰々しい)。

f:id:u_ribo:20191202115448j:plain
Kajikazawa in Kai Province (Koshu Kajikazawa), from the series “Thirty-six Views of Mount Fuji (Fugaku sanjurokkei)”, 1825–1838 by Katsushika Hokusai. Image via Art Institute of Chicago

NipponパッケージというRパッケージがあります。 このパッケージは、日本人が頻繁に遭遇するであろう、全角英数字や元号の変換、祝日の判定といった処理を効率的に行うための関数や日本の都道府県名を含んだデータセットを提供していました。

いました、と過去形にするのは今年(2019年)の7月にCRANからアーカイブされてしまったためです。現在は install.packages("Nippon") を実行してもインストールできません。

Nipponパッケージは当然日本人の利用者も数多く、日本人Rユーザが集うSlack、r-wakalang上でも「なぜアーカイブされたのか」「今後はどうなるのか」というやり取りもありました。 パッケージがCRANから除外されてしまった経緯はさておき、このパッケージの関数は私自身も重宝していたのでなんとかしたいという気持ちでいました。 そして今回、Nipponパッケージの代替え、そしてより便利な機能を提供することを目指して、新たにzipanguという名前のパッケージをCRANに登録しました。

cran.rstudio.com

とりあえずCRANからインストールできる状態を目標にしていたため、まだ使える機能は限定的ですが各関数の使い方を解説します。 まずはパッケージを利用するために、パッケージのインストールを行います。

install.packages("zipangu") # v.0.1.0
library(zipangu)

zipanguパッケージの関数

Address: 住所文字列の要素分割

与えられた住所文字列をその要素、すなわち都道府県、市区町村、それ以下の住所に分割、リストとして返却します。

separate_address("東京都千代田区大手町一丁目")
#> $prefecture
#> [1] "東京都"
#> 
#> $city
#> [1] "千代田区"
#> 
#> $street
#> [1] "大手町一丁目"
separate_address("北海道余市郡余市町朝日町")
#> $prefecture
#> [1] "北海道"
#> 
#> $city
#> [1] "余市郡余市町"
#> 
#> $street
#> [1] "朝日町"
separate_address("宮城県柴田郡村田町大字村田")
#> $prefecture
#> [1] "宮城県"
#> 
#> $city
#> [1] "柴田郡村田町"
#> 
#> $street
#> [1] "大字村田"

住所の一部が与えられた時は、欠損する要素をNAとして処理します。

separate_address("岡山市")
#> $prefecture
#> [1] NA
#> 
#> $city
#> [1] "岡山市"
#> 
#> $street
#> [1] NA
separate_address("奈良県高市郡高取町")
#> $prefecture
#> [1] "奈良県"
#> 
#> $city
#> [1] "高市郡高取町"
#> 
#> $street
#> [1] NA

ソースコードを見たらわかるのですが、力づくでの正規表現によるパターンマッチで実装しているのでもっとスマートに書ける気がしています。

Year: 元号が使われる年表記を西暦に変換

convert_jyear()関数で「平成元年」や「昭和52年」、「T5」(大正5年)といった元号を用いた年表記を西暦での表記に変換します。Nipponパッケージが対応していなかった「令和」にも対応しています。

convert_jyear("平成元年")
#> [1] 1989
convert_jyear(c("R1", "昭和52年"))
#> [1] 2019 1977

この処理の逆、西暦から元号へは対応していません。次のバージョンでの課題です。

Kansuji: 漢数字をアラビア数字に変換

デフォルトでは変換したアラビア数字は文字列型として処理されますが、数値として返却させるなど、いくつかのオプションがあります。

kansuji2arabic(c("一", "百"))
#> [1] "1"   "100"
# 返り値を数値にします
kansuji2arabic(c("一", "百"), convert = FALSE)
#> [1]   1 100
# .under = で指定した値未満の漢数字だけを対象とします
kansuji2arabic(c("一", "百", "千"), .under = 1000)
#> [1] "1"   "100" "千"

住所のように、文字列中のすべての漢数字をアラビア数字に変えるには kansuji2arabic_all()が利用できます。

kansuji2arabic_all("北海道札幌市中央区北一条西二丁目")
#> [1] "北海道札幌市中央区北1条西2丁目"

str_jconv: 全角・半角、ユニコード正規化

この関数はCRAN登録のv0.1.0では利用できません。

Nipponパッケージではzen2han()han2zen()kata2hira()hira2kata()といった関数で全角文字列を半角にしたり、片仮名と平仮名の変換を行える関数がありました。 zipanguでも以下の関数を用意する予定です。

str_conv_hirakana("アイウエオ", to = "hiragana")
#> [1] "あいうえお"
str_conv_hirakana("あいうえお", to = "katakana")
#> [1] "アイウエオ"
str_conv_zenhan("a0", "hankaku")
#> [1] "a0"
str_conv_zenhan("ガッ", "zenkaku")
#> [1] "ガッ"

また、Nipponにはなかったユニコード正規化のための関数も実装予定です。

str_conv_normalize("①②③", "nfkc")
#> [1] "123"

祝日の判定

この関数はzipangu v0.1.0では未実装です。 Nippon::is.jholiday()として提供されていたものです。日付オブジェクトを与えると、その日が祝日かどうかを返却する関数です。

Nippon::is.jholiday(as.Date("2019-11-03"))
#> [1] TRUE
# 天皇誕生日の変更についてはサポートされていない
Nippon::is.jholiday(as.Date("2019-12-23"))
#> [1] TRUE

祝日のリストから対応する日付を判定させれば良いのですが、今年のようにイレギュラーな祝日が入ったりすることまでサポートしようとすると実装は大変そうです。

Nipponパッケージを使いたい

まだ未実装の関数もあり、アーカイブされたとはいえNipponパッケージを使いたい方は、下記のコードを実行することでNipponパッケージが利用可能になります。

remotes::install_github("cran/Nippon")

開発に協力してください

最後にお願いです。

NipponパッケージのソースコードGitHub等で公開されてはいませんでした。 機能改善やバグ報告は受け付けていましたが、メールでのやり取りに敷居の高さを感じていた方もいたのではないでしょうか。

zipanguパッケージは多くのRパッケージ同様、オープンソースで開発、ソースコードGitHub上で公開しています。 問題の報告や改善点の要望もGitHubのissueで受け付けています。 これらは誰でもできるので、今更言うほどでもないのですが、このパッケージの開発ならびに保守を手伝ってくれる方を募集しています。

これは私自身が、いつまでこのパッケージをメンテナンスし続けられるのかわからないためであります。 コラボレータがいることで、このパッケージがNipponと同じ轍を踏むリスクを低下させられるのではと考えています。

github.com

コラボレータを募る背景には、日本人のRパッケージ開発者を養成したいと言う気持ちがあるのですが、これについては別の記事を書くつもりです。

日本語データの処理でよく使う機能がある方はぜひお願いします。 Rのパッケージ開発についてはわからない...そんな場合でも、パッケージの作成方法についていくらか教えることができますので、遠慮なく手を挙げていただければ幸いです。

まだ小さなパッケージですが、どうぞよろしくお願いします。