戯言日記

Rの話だと思ったら唐突にサバゲーが混じってくる何か。

forcatsパッケージでggplot2の因子軸を反転させる

こちらはR Advent Calendar 2020 8日目の記事です。

qiita.com

初参加ですが宜しくお願い致します。

なお、内容的にはggplot2の初心者向けです。
因子型データの軸を反転させたかった時に「ggplot2 軸 factor 反転」とかで検索をかけてもfactorのlevelsを直接変更する以外の情報が上手く検索に引っ掛からなくて苦労した (「ggplot2 forcats」だとガッツリ引っ掛かるので調べ方が悪いだけかもですが……) ので、同じような疑問を抱えている人の一助になれれば幸いです。


では本題。
ggplot2でこんなグラフを作っているとする。

library(tidyverse)

iris %>% tibble() %>%
  ggplot(aes(Species, Sepal.Length, fill=Species)) + geom_boxplot()

f:id:doubtpad:20201207010756p:plain


この時、x軸とy軸を入れ替えたい場合はcoord_flip()を利用する人が大半だと思う。

iris %>% tibble() %>%
  ggplot(aes(Species, Sepal.Length, fill=Species)) + geom_boxplot() + coord_flip()

f:id:doubtpad:20201207010824p:plain


個人的には1枚目のグラフの軸の入れ替えなのでsetosaが上に来てほしいのだが、ggplot2の仕様ではこうなってしまう。
なので、軸を反転させて修正したい。

これが連続値を扱ってる場合はscale_x_reverse()を仕込めば完了なのだが、因子(factor)が絡んでくるとggplot2側で処理ができないので一気に面倒になる。
それなのに反転させたい場合は大体が因子だったりする。


とりあえずグーグル先生に「ggplot2 軸 factor 反転」とかで質問すると「 factor() 内に levels = c() を仕込めば大丈夫だよ」と言われた。

iris %>% tibble() %>%
  mutate(Species = factor(Species, levels = c("virginica", "versicolor", "setosa"))) %>% 
  ggplot(aes(Species, Sepal.Length, fill=Species)) + geom_boxplot() + coord_flip()

f:id:doubtpad:20201207010842p:plain


上の書き方だと因子型データの要素が増えるほど手間も増えてしまうので、たぶん因子型データのlevelsを文字列化して反転させたものを投げるのが一番現実的だと思う。

iris %>% tibble() %>%
  mutate(across(Species, ~factor(.x, levels = rev(levels(.x) %>% as.vector())))) %>% 
  ggplot(aes(Species, Sepal.Length, fill=Species)) + geom_boxplot() + coord_flip()

f:id:doubtpad:20201207010855p:plain


しかし、この方法だと各因子に対するグラフの色が最初のグラフと異なってしまうため、複数のグラフのうちの1つだけに軸の入れ替え+反転をするような場面では使いにくい。

それを回避するにはmutate()を使わず、aes()内でx軸のデータのみ反転させればいい。

iris %>% tibble() %>%
  ggplot(aes( (factor(Species, levels = rev(levels(Species) %>% as.vector()) )), Sepal.Length, fill=Species)) + geom_boxplot() + coord_flip()

f:id:doubtpad:20201207010911p:plain


こちらのやり方の方が直感的に操作できると思うが、コードが非常に見辛い。
流石に毎度こういう書き方をするのはどうかと思ってしまう。


という訳で解決策を探して色々見ていたら、forcatsパッケージでやればいいとの情報を見かけた。

forcats.tidyverse.org

forcatsパッケージ自体はtidyverseの一部で、因子型データを操作するためのもの。
この中のfct_rev()で因子型データのlevelsを反転すればいいらしい。

早速だが試してみる。

library(forcats)

iris %>% tibble() %>%
  ggplot(aes(fct_rev(Species), Sepal.Length, fill=Species)) + geom_boxplot() + coord_flip()

f:id:doubtpad:20201207010933p:plain


上と同じグラフで、しかもmutate()内でごちゃごちゃ書かずに済むので見通しも良くなった。 しかもこのやり方は、forcatsパッケージの関数なら大体対応できるみたいなので、因子型データの軸を上手く操作したい人にとっては応用の幅も広くていいと思う。


因子の軸を反転させたい人が、少しでも簡単に反転させられますように。

Enjoy!!