備忘ログ

チラシの裏的備忘録&メモ

`{ggplot2}`で作れるグラフの軸ラベルを縦書きにしたい

{ggplot2}で作れるグラフの軸ラベルを縦書きにしたいと思った。

ラベルを90°回転させて縦にするのではなく、縦書きにしたいと思った。

できればscale_x_discrete()内でlabels引数に関数等を指定することでいい感じにしたいと思った。投入する前のデータでいじるのではなく、ggplot内で簡単にできるようにしたかった。

いい感じの関数が見つからなかったので作ってGitHubにあげている{infun}label_vertical()として入れてみた。ただ、野良パッケージを使いたくない人のために、関数そのものも後の方に貼っておく。

github.com

install.packages("remotes")
remotes::install_github("indenkun/infun")

使ってみる。あえてごちゃごちゃしたグラフにしたいので、47都道府県名を使う。

都道府県名を手入力するのがめんどくさいので{zipangu}パッケージのjpnprefsから引っ張ってくることにする。{zipangu}はインストールしていなければ、install.packages("zipangu")でインストールできる。

適当な値を入れたデータを作る。

df <- data.frame(pref = zipangu::jpnprefs$prefecture_kanji,
                 value = 1:47)

これで、都道府県名をx軸にしてvalueをy軸にした棒グラフを作る。

library(ggplot2)
df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity")

x軸側のラベルが重なってて見にくい。重ならないように小さくするとこうなる。

df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity") +
  theme(axis.text.x = element_text(size = 3))

小さすぎて読めない。

対策としては、軸ラベルをずらして見やすくするか、45°ないし90°回転させることで見やすくする事ができる。

それぞれやってみる。

軸ラベルをずらして見やすくする。今回はデータが多いので3行くらいにしてみる。

df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity") +
  scale_x_discrete(guide = guide_axis(n.dodge = 3))

45°回転させてみる。

df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 5))

90°回転させてみる。

df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 8))

どれも最初のものよりも見やすくなっている気がするが、そもそも日本語なので90°回転じゃなく縦書きにしたほうが見やすいのではないかと思う。

そこで、{infun}label_vertical()をつかって縦書きにする。

df |>
  ggplot(aes(x = pref, y = value)) + 
  geom_bar(stat = "identity") +
  scale_x_discrete(labels = infun::label_vertical())

これが一番見やすいのではと思う。

90°回転させると微妙に書くバーの中心と軸ラベルの文字がずれるし。

label_vertical()の中身

label_vertical()はその本体と、横棒を縦棒に置換するための指定をする式を含むvertical_list()からなっているので、次の2つの関数のコードを読み込むとそのまま使えると思う。

label_vertical <- function(replace_list = vertical_list()){
  function(x){
    if(!is.null(replace_list)){
      list_is_formula <- unlist(lapply(replace_list, function(x){"formula" == class(x)}))
      if(all(list_is_formula)){
        for(i in replace_list){
          x <- gsub(i[[2]], i[[3]], x)
        }
      }else if("formula" == class(replace_list)){
        x <- gsub(replace_list[[2]], replace_list[[3]], x)
      }else{
        stop("the replace_list must be in the formula format, in list.")
      }
    }
    unlist(lapply(strsplit(split="", x), paste0, collapse = "\n"))
  }
}

vertical_list <- function(){
  list("\u30fc" ~ "\uff5c",
       "-" ~ "\u2758")
}

実態としては、縦書きスタイルを実現しているわけではなく、一文字ずう改行しているというもの。

そのため、横棒は縦棒に書き換えなければ横棒のママ表現されてしまうため微妙な日本語になってしまう。

これは横棒しかデフォルトで縦棒に変換しないが、例えば~はどうするのかとかは自前でリスト形式の式形式で指定ができるようにしている。

例えばカッコを含むデータの場合を考える。

もうグラフの上側いらないので、{scales}の軸デモ用の関数を使って例示していく。

test_label <- c("東京都(関東)", "宮城県(東北)")

普通にこれをx軸側のラベルにすると次のようになる。

scales::demo_discrete(test_label)
## scale_x_discrete()

これをただ、label_vertical()すると、

scales::demo_discrete(test_label, labels = infun::label_vertical())
## scale_x_discrete(labels = infun::label_vertical())

カッコがおかしげな感じになる。

これを避けるためにはカッコを別のカッコに指定してやるといい。

scales::demo_discrete(test_label, labels = infun::label_vertical(replace_list = list("(" ~ "︵", ")" ~ "︶")))
## scale_x_discrete(labels = infun::label_vertical(replace_list = list("(" ~ 
##     "︵", ")" ~ "︶")))

一応縦カッコになった。そもそもカッコ消して点にするのもありだと思う。

scales::demo_discrete(test_label, labels = infun::label_vertical(replace_list = list("(" ~ "・", ")" ~ "")))
## scale_x_discrete(labels = infun::label_vertical(replace_list = list("(" ~ 
##     "・", ")" ~ "")))

こんな感じで縦書きから横書きに帰る時に結構いろいろ置換しなければ不自然な日本語となるが、すべてを網羅するのは難しそうだなと思ったので、明らかに横棒は縦棒に変えるものは用意しているけど、それ以外は自分で指定してくれれば受け入れるというスタイルにしている。

{base} plotの場合と参考文献

okumuralab.org

base plotの場合の縦書きについて上記を参照し参考にした。

雑感

ggplot2の軸ラベル縦書きにするのはそれなりに需要ありそうだが、さっと探した感じ見つけられなかった。みんないろいろ工夫しているんだろうか?それとも90°回転で満足しているのだろうか?

あと、調べたら縦書きはCJK環境にあるはあるが、日常的に縦書きを使っているのは現在日本語だけ?かもしえず、あまり需要がない?のかもと思った。

日本語特有の需要なら{zipangu}に機能提案しても良かったと思ったが、そもそもこの様な状況だとそもそも需要がないのかもと思った。

取りあえず、自分で使う時に名前空間がごちゃごちゃしないようにパッケージに入れておいた方が便利なので自前パッケージに収録しておいた。