R Markdownでのハイライトを行うflairパッケージを使ってみた
R MarkdownによるHTML出力を行う時、コードのシンタックスハイライトを取り入れることができます。一方でコードの特定の箇所を強調したり装飾することは困難でした(xaringanパッケージでのプレゼンテーション用の出力では可能)。
ですがそれも過去の話。今日紹介する flair パッケージを使うと、そうした要望に答えられます。
公式のドキュメントが整備されているのでそっちを読んだ方が手っ取り早い、正確な気もしますが備忘録として日本語で整理しておきます。
flairパッケージでできること
- R MarkdownによるRコードのHTML出力の部分ハイライト
- ハイライト対照のコードはコードチャンク、文字列で指定
decorate()
でチャンクオプションの制御flair()
- 特定の文字列、関数、引数をハイライトできる派生関数も豊富
- ハイライトの文字の色、背景色、斜体や太字などの文字装飾を調整可能
なお、ハイライトは便利でわかりやすさを促進する可能性がありますが、ハイライトによって見えにくくなったり混乱を招く恐れがあることも注意が必要です。これについて、公式のドキュメント内で
However, please remember to be judicious in your color choices, and to keep in mind how your colors appear to colorblind individuals.
の一文があるのがとても好印象でした。用法要領を守って適切に使っていきたいですね。
導入
flairは先日CRANに登録されました。Rの標準パッケージ追加関数であるinstall.packages()
を使ってインストールが可能です。開発版を入れたい人は
remotes::install_github("kbodwin/flair)
を実行してください。
library(flair) library(dplyr)
flairではdecorate()
とflair()
が主要な関数となります。あとで触れますがflair()
にはいくつかの派生系が用意されています。基本的な使い方を見ていきましょう。
まずはいつも通りチャンクを使ってRコードを書きます。このコードがハイライトの対象となります。この時、チャンクラベル(チャンク名)をつけておくのが大事です。
```{r how_to_pipe, include = FALSE}
# how_to_pipeがチャンク名になります
iris %>%
group_by(Species) %>%
summarize(sepal_length_avg = mean(Sepal.Length))
```
次の処理がハイライトのための操作となります。まずdecorate()
で先ほどの、ハイライトさせたいコードが書かれてたチャンクラベルを文字列で指定、そのオブジェクトをflair()
に渡します。flair()
の第一引数にdecorate()
の結果が入ることになるのでパイプ演算子 (%>%
)を使うと楽です。複数のハイライトを行う場合も、パイプ演算子でつなげて書けるので便利です。
そしてflair()
関数ではハイライトさせる文字列を指定します。
decorate("how_to_pipe", eval = FALSE) %>% flair("%>%")
iris %>%
group_by(Species) %>%
summarize(sepal_length_avg = mean(Sepal.Length))
上記のハイライトされている部分が出力結果です。Knitするとpre
とcode
タグからなるHTMLが出力される仕組みです。実際の使い所としてはdecorate()
、flair()
のコードは見せなくても良いので、そちらのチャンクコードをecho=FALSE
にしておくと良いと思います。
decorate()
では、引数内でチャンクオプションの値を制御できます。上記のコードでは、irisデータの集計結果を出力しないためにeval = FALSE
を与えました。
また、decorate()
ではチャンクラベルではなく、Rコードを直接記述してハイライトの対象としても良いです。今度はチャンクコードのRコードも実行する様にeval = FALSE
を与えずに実行してみます。
decorate("mean(1:10)") %>% flair("mean")
mean(1:10)
## [1] 5.5
R MarkdownファイルをKnitする前に、どのような出力になるかを確認することも可能です。コンソールで上記のコードを実行してみましょう(Knitする前のチャンク名をどうして把握できているのか、よくわかっていない)。RStudioを使っている場合、Viewerパネルにハイライトされた結果が表示されます。
flairの派生系
先ほどはflair()
で特定の文字列をハイライトする例でしたが、関数や引数をハイライトするための関数も用意されています。それぞれflair_funs()
とflair_args()
です。このほかにも指定した行をハイライトするflair_lines()
、関数に与えた引数と値のためのflair_input_vals()
、正規表現によるパターン指定が可能なflair_rx()
などがあります。
decorate("how_to_pipe", eval = FALSE) %>% flair_funs()
iris %>%
group_by(Species) %>%
summarize(sepal_length_avg = mean(Sepal.Length))
decorate("how_to_pipe", eval = FALSE) %>% flair_args()
iris %>%
group_by(Species) %>%
summarize(sepal_length_avg = mean(Sepal.Length))
文字装飾
flairパッケージではハイライトしたときの見た目を変更する機能が備わっています。これはflair()
内で指定しますが、論理値で指定するものと値を指定するものがあります。前者は太字
(bold)、下線 (underline)、斜体 (italic)とするか、後者はハイライトの色
(color) および背景色 (bg_color)などです。
decorate("how_to_pipe", eval = FALSE) %>% flair_lines(2) %>% flair_funs(color = "LightCoral") %>% flair("%>%", color = "Azure", background = "Navy")
iris %>%
group_by(Species) %>%
summarize(sepal_length_avg = mean(Sepal.Length))
こんなてんこ盛りな装飾もできます。
Enjoy!
tabularmaps: カラム地図で行政区の大まかな配置を可視化する
カラム地図と呼ばれるものがあります。 これは日本の47都道府県をはじめとした行政区の配置を表上に圧縮表示することで、それぞれの位置関係をわかりやすく伝えるためのプロジェクトです。
最近では、カラム地図の開発者の一人、福野泰介さん (@taisukef) による新型コロナウイルス対策ダッシュボードのページでの「現在患者数 / 対策病床数」の可視化で「カラム地図」を見る機会が増えた人もいるのではないでしょうか。
COVID-19 Japan 新型コロナ対策ダッシュボード
— taisukef (@taisukef) April 21, 2020
厚労省データと、神奈川県が公表した対策病床3,400反映https://t.co/VNM1ngPG95
病床等確保数1,000床+宿泊療養施設2,400室https://t.co/kVGJbYMNTx \#StopCOVID19JP
対策病床数のオープンデータ化、お願いします!
さて、この「カラム地図」をR言語の中で扱うべく、tabularmapsパッケージの開発を進めています。
以下、この記事ではtabularmapsの使い方を紹介していきます。
パッケージはCRANには登録されていないため、GitHub経由でインストールを行います。以下のコマンドを実行することでパッケージが利用可能になります。
install.packages("remotes") remotes::install_github("uribo/tabularmaps")
library(tabularmaps) library(ggplot2)
可視化の際にggplot2パッケージを利用しているので、そちらも読み込んでおく必要があります。
使い方
現在tabularmapsでは
- 都道府県 (
jpn77
) - 東京23区 (
tky23
) - ISO-3166による国名 (
iso3166
)
の3種類に対応しています。括弧内の文字列がパッケージに含まれるデータフレームオブジェクトで、県や区などの対象行政名の位置関係を記録しています。
冒頭の都道府県のカラム地図は次のコマンドにより描画されます。
tabularmap(jpn77, fill = region_kanji, label = prefecture_kanji, size = 3, family = "IPAexGothic") + theme_tabularmap(base_family = "IPAexGothic") + scale_fill_jpregion(lang = "jp", name = "八地方区分")
tabularmap()
がカラム地図を表示させる関数として機能します。この関数では第一引数に対象のデータフレームを与えて実行します。
そのほかの引数としてggplot2オブジェクトの審美的要素を決定するfill
(塗り分けの色基準)、label (表示するラベル文字列)の変数名を与えます。
これに加え、ggplot2::geom_text()
に渡す値を指定可能です。
これはラベルの大きさを調整する size やフォントのための family
を使うことを想定しています。
上記のコードでは、tabularmap()
に加えてtheme_tabularmap()
、scale_fill_jpregion()
を実行しています。これらの関数はオプションとして利用可能なもので、
よりカラム地図っぽい見た目に調整するためのものです。
都道府県を表示させるカラム地図では地方別に塗り分ける色が決まっているため、それに応じた塗り分けを行うようになります。
続いて東京23区の表示をしてみます。先のコードからtabularmap()
に与えるデータとラベル用の変数名を変更するだけです。
tabularmap(tky23, label = ward_kanji, family = "IPAexGothic") + theme_tabularmap(base_family = "IPAexGothic") + guides(fill = FALSE)
現実の配置や面積がぼやけてしまう欠点もありますが、 行政区域のデータを用意する必要がないのはカラム地図の大きな利点です。 (カラム地図のレイアウト自体はオープンライセンスで開発されています。)
また本来想定されていたダッシュボードでの利用を考える場合、 表示する際のスペースが有効活用できるのも嬉しいです。 日本の場合、細長くなるのでどうしても隙間ができてしまいますが、カラム地図だと基本的にグリッドになるので無駄が少ないです。
今後の機能
本家のカラム地図では、市区町村を対象にしたレイアウトが全国47都道府県分定まったとのことです。 これらの情報を追いながら、tabularmapsパッケージでも市区町村版を追加する作業を進めていくつもりです。
全国のデータを追加するのは時間がかかりそうなので、皆さんからの協力(Pull request)をお待ちしています。
余談
SNSを見ていると、時々ヘンテコな地図が回ってきます。
中学生の地理で習うような問題です。 回答を見ていると、有名な東京都や神奈川県、形のわかりやすい北海道などは簡単な様子。 一方で北関東の群馬、栃木、茨城の配置、島根と鳥取の位置関係などを間違えている例をしばしば見かけます(私も苦手でした)。 またそれ以上にトンデモな解答も…。
行政境界の複雑な幾何学模様を認識し記憶することに対する人間の限界を感じます。 それが特に自分とは関わりのない地域であれば尚更です。
また、行政区は人間が勝手に定めたもの。時間の経過とともに境界も変化していきます。
情報を伝えるとき、これらの行政区をどこまで厳密に再現する必要があるでしょうか。
地図を表示するにはポリゴンないしラインデータを用意しなくてはいけない。そう思っていた時期が私にもありました。
ですがそうではなかったのです。
必要なのは、情報を正しく、わかりやすく伝えること。
カラム地図では、現実に対して幾らかの嘘をつくことになりますが、それは許容されうる範囲なのではと思います。
参考
気象庁提供の潮位表、過去の気象データをRで読み込む
最近、気象庁が提供する各種データをR上で取り扱うパッケージ、jmastatsに新しい関数を追加しました。 このパッケージはちまちまと更新しており、現在のところCRANへの登録は目指していません。 ですが便利なパッケージなのでこの場で宣伝しておきます。
https://gitlab.com/uribo/jmastats
今回追加したのは以下の関数です。いずれも気象庁のウェブサイトでダウンロード可能なファイルを読み込むために使います。
read_tide_level()
,pivot_tide_level()
: 潮汐観測資料から潮位表データの読み込みread_jma_weather()
: 過去の地点気象データを読み込む
この機能を試したい場合、パッケージをGitLab経由(GitHubではありませんので注意)でインストールする必要があります。次のコマンドを実行するとインストールが行われます。
install.packages("remotes") remotes::install_gitlab("uribo/jmastats")
library(jmastats)
次にこれらの関数の使い方を紹介します。
潮汐観測資料
潮汐観測資料および各種潮位データ・品質管理情報のページよりダウンロード可能な、 毎時潮位、満潮・干潮の時刻と潮位が記録されたテキストファイルを与えて実行します。
ダウンロード済みのローカルファイルのパスを指定しても良いですし、気象庁のURLを直接与えても良いです。また引数による年月、地点の指定も可能です。次の例は、2020年2月の「東京」のデータを対象に実行するものです。
# ファイルが置かれているパスがわかる場合は直接パスを指定すると良いです。 #d <- # read_tide_level("https://www.data.jma.go.jp/gmd/kaiyou/data/db/tide/suisan/txt/2020/TK.txt") # path引数以外の引数でデータを指定する場合(こちらは一ヶ月単位のデータになります。) d <- read_tide_level(.year = 2020, .month = 2, .stn = "TK") d #> # A tibble: 29 x 42 #> hry_00 hry_01 hry_02 hry_03 hry_04 hry_05 hry_06 hry_07 hry_08 hry_09 hry_10 #> [cm] [cm] [cm] [cm] [cm] [cm] [cm] [cm] [cm] [cm] [cm] #> 1 176 156 143 143 153 172 194 214 229 237 236 #> 2 195 180 166 160 162 172 188 204 219 230 232 #> 3 197 190 181 174 173 179 191 204 216 224 228 #> 4 204 206 204 201 197 194 194 196 203 211 218 #> 5 197 212 220 223 221 217 212 210 210 215 223 #> 6 172 196 213 222 225 221 211 199 188 182 183 #> 7 130 164 197 222 235 234 224 208 192 180 176 #> 8 112 148 187 224 251 262 258 241 217 196 182 #> 9 87 120 162 204 240 261 264 250 223 194 172 #> 10 69 93 134 183 229 263 279 276 256 226 195 #> # … with 19 more rows, and 31 more variables: hry_11 [cm], hry_12 [cm], hry_13 [cm], hry_14 [cm], #> # hry_15 [cm], hry_16 [cm], hry_17 [cm], hry_18 [cm], hry_19 [cm], hry_20 [cm], hry_21 [cm], #> # hry_22 [cm], hry_23 [cm], date <date>, stn <chr>, low_tide_hm_obs1 <time>, low_tide_level_obs1 [cm], #> # high_tide_hm_obs1 <time>, high_tide_level_obs1 [cm], low_tide_hm_obs2 <time>, #> # low_tide_level_obs2 [cm], high_tide_hm_obs2 <time>, high_tide_level_obs2 [cm], #> # low_tide_hm_obs3 <time>, low_tide_level_obs3 [cm], high_tide_hm_obs3 <time>, #> # high_tide_level_obs3 [cm], low_tide_hm_obs4 <time>, low_tide_level_obs4 [cm], #> # high_tide_hm_obs4 <time>, high_tide_level_obs4 [cm]
潮位の単位がcmで記録されているので、unitsパッケージを使って単位を与えているのが特徴です。
また、元データは毎時潮位と満潮・干潮の潮位データが一つのファイルになっているので列が多いです(行数は日数に対応)。そのため、jmastatsではこのデータを分離し、縦長のデータフレームに変換する関数
pivot_tide_level()
を用意しました。
read_tide_level()
で読み込んだデータを引数に与えて実行します。この関数の返り値は2つのデータフレームを含んだリストです。hourlyが毎時潮位、tideが満潮・干潮の潮位となります。
d_long <- d %>% pivot_tide_level() d_long #> $hourly #> # A tibble: 696 x 3 #> datetime stn tide_value #> <dttm> <chr> [cm] #> 1 2020-02-01 00:00:00 TK 176 #> 2 2020-02-01 01:00:00 TK 156 #> 3 2020-02-01 02:00:00 TK 143 #> 4 2020-02-01 03:00:00 TK 143 #> 5 2020-02-01 04:00:00 TK 153 #> 6 2020-02-01 05:00:00 TK 172 #> 7 2020-02-01 06:00:00 TK 194 #> 8 2020-02-01 07:00:00 TK 214 #> 9 2020-02-01 08:00:00 TK 229 #> 10 2020-02-01 09:00:00 TK 237 #> # … with 686 more rows #> #> $tide #> # A tibble: 112 x 6 #> date stn tide_level count time tide_value #> <date> <chr> <chr> <chr> <time> [cm] #> 1 2020-02-01 TK low 1 09:23 238 #> 2 2020-02-01 TK high 1 02:33 141 #> 3 2020-02-01 TK low 2 21:35 210 #> 4 2020-02-01 TK high 2 15:23 155 #> 5 2020-02-02 TK low 1 09:45 232 #> 6 2020-02-02 TK high 1 03:16 160 #> 7 2020-02-02 TK low 2 23:18 198 #> 8 2020-02-02 TK high 2 16:23 151 #> 9 2020-02-03 TK low 1 10:25 228 #> 10 2020-02-03 TK high 1 03:41 173 #> # … with 102 more rows
せっかくなので可視化してみましょう。
library(ggplot2) library(ggforce)
d_long %>% purrr::pluck("hourly") %>% ggplot(aes(datetime, tide_value)) + geom_line(color = "red") + scale_x_datetime(date_labels = "%m/%d") + theme_light(base_family = "IPAexGothic") + labs(title = "毎時潮位グラフ 2020年2月", subtitle = "東京")
地点名がわからないときは
tide_station
データセットで見つけることができます。なお、年によって観測地点が変わるのでそこは注意です。
tide_station #> Simple feature collection with 1670 features and 6 fields #> geometry type: POINT #> dimension: XY #> bbox: xmin: 122.95 ymin: 24.28333 xmax: 153.9833 ymax: 45.4 #> CRS: EPSG:4326 #> # A tibble: 1,670 x 7 #> year id stn station_name address type geometry #> <chr> <chr> <chr> <chr> <chr> <chr> <POINT [°]> #> 1 1997 1 WN 稚内 北海道 稚内市 新港町 フロート式 (141.6833 45.4) #> 2 1997 2 AS 網走 北海道 網走市 港町 フロート式 (144.2833 44.01667) #> 3 1997 3 HN 花咲 北海道 根室市 花咲港 フロート式 (145.5667 43.28333) #> 4 1997 4 KR 釧路 北海道 釧路市 港町 フロート式 (144.3833 42.96667) #> 5 1997 5 HK 函館 北海道 函館市 海岸町 フロート式 (140.7333 41.78333) #> 6 1997 6 B3 小樽 北海道 小樽市 色内3丁目 音波式 (141 43.2) #> 7 1997 7 SH 下北 青森県 むつ市 大字関根 音波式 (141.25 41.36666) #> 8 1997 8 HC 八戸 青森県 八戸市 新湊3丁目 フロート式 (141.5333 40.53333) #> 9 1997 9 MY 宮古 岩手県 宮古市 日立浜町 フロート式 (141.9833 39.63334) #> 10 1997 10 OF 大船渡 岩手県 大船渡市 赤崎町 フロート式 (141.75 39.01667) #> # … with 1,660 more rows
過去の地点気象データ
jmastatsには、すでにウェブスクレイピングにより気象データを取得する関数
jma_collect()
がありました。一方でこの関数では地点数が多い・期間が長い場合に
気象庁のページへの負荷が多くなってしまう問題がありました。
今回追加した read_jma_weather()
ではデータの用意こそユーザが各自で行う必要がありますが、任意の地点・期間のデータをRで読み込むには便利な関数となっています。
気象庁からダウンロードしたファイルのフォーマットは
https://www.data.jma.go.jp/gmd/risk/obsdl/top/help3.html
にあるようにやや煩雑となっていて、すぐに使える形式ではありません。
read_jma_weather()
はRでの分析、可視化が素早くできるよう、自動的にデータを整形した形式で読み込みます。
関数を実行する前に対象のデータをダウンロードしておきましょう。 過去の気象データ・ダウンロードのページから関心の地点データを取得します。ここでは「つくば(舘野)」の「日平均気温」と「降水量の日合計」について、最近一ヶ月分のデータを用意しました。
d <- read_jma_weather("~/Downloads/data.csv") #> Selected station: つくば(館野) #> Parsed with column specification: #> cols( #> date = col_character(), #> `つくば(館野)_平均気温(℃)` = col_double(), #> `つくば(館野)_平均気温(℃)_品質情報` = col_double(), #> `つくば(館野)_平均気温(℃)_均質番号` = col_double(), #> `つくば(館野)_降水量の合計(mm)` = col_double(), #> `つくば(館野)_降水量の合計(mm)_現象なし情報` = col_double(), #> `つくば(館野)_降水量の合計(mm)_品質情報` = col_double(), #> `つくば(館野)_降水量の合計(mm)_均質番号` = col_double() #> ) dplyr::glimpse(d) #> Rows: 31 #> Columns: 8 #> $ date <date> 2020-03-20, 2020-03… #> $ `つくば(館野)_平均気温(℃)` <dbl> 12.9, 11.2, 14.7, 8.5, 6.0, 7.0,… #> $ `つくば(館野)_平均気温(℃)_品質情報` <dbl> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, … #> $ `つくば(館野)_平均気温(℃)_均質番号` <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, … #> $ `つくば(館野)_降水量の合計(mm)` <dbl> 0.0, 0.0, 0.0, 0.0, 1.5, 0.0, 0.0… #> $ `つくば(館野)_降水量の合計(mm)_現象なし情報` <dbl> 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, … #> $ `つくば(館野)_降水量の合計(mm)_品質情報` <dbl> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8… #> $ `つくば(館野)_降水量の合計(mm)_均質番号` <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
お試しいただき、改善や機能追加のリクエストをいただけると助かります。 また、こうしたRパッケージの開発を支援してくださる方も引き続き募集しています。
https://uribo.hatenablog.com/entry/2020/03/27/170257 uribo.hatenablog.com
どうぞよろしくお願いします。