ggplotのfacet日本語テキストを折り返す
これはなにか
ggplotのfacet内の文字を任意の文字数で折り返し(改行)をしたい。
どういうことかというと、下記のようにirisベースでテキトーにSpecies
を日本語化して文字数を増やしたもので考える。
library(dplyr) iris2 = iris %>% mutate(Species_jp = case_when(Species == 'setosa' ~ 'セトサ', Species == 'versicolor' ~ 'バージカラー', Species == 'virginica' ~ 'バージニカ'), Species_jp2 = paste0(Species_jp, Species_jp, Species_jp), Species2 = paste(Species, Species, Species, sep = ' ')) %>% tibble()
このSpecies_jp2
をfacetにすると文字数が長いので見切れる。
iris2 %>% ggplot() + aes(Sepal.Length, Sepal.Width) + geom_point() + facet_wrap(~ Species_jp2) + theme(strip.text = element_text(family = 'HiraKakuProN-W3'))
これをテキトーな文字数で折り返したい。
このようなモチベーションの際、英語であれば label_wrap_gen
を使うことで対応できる。
label_wrap_gen
は、 「空白までの間でn文字以上になった場合折り返して、満たない場合は次の空白までをカウントしてその合計がn文字以上なら直前の空白で折り返す」といった処理をおこなってくれる。
例えば「Mostly harmless econometrics」という文章はn = 10であれば、「Mostly harmless (改行) econometrics」として表示される(下記コードはSpecies
を空白付で3回繰り返したもの)。
iris2 %>% ggplot(aes(Sepal.Length, Petal.Length)) + geom_point() + facet_wrap(. ~ Species2, labeller = label_wrap_gen(5))
しかし、日本語文の場合単語を空白で区切らないので label_wrap_gen
は使えない。
解決方法
facet_xxx
の引数labbeler
は指定した関数でテキストを処理してくれる。
そのため、テキストに対してn文字毎に改行コード\n
を入れる関数を渡すことでやりたいことが実現できる。
ちなみに、 label_wrap_gen
も前述のような処理をおこなっている関数というだけ。
# characterの全列に対して、5文字毎に改行を入れた状態に上書きする関数 facet_splitter = function(x) mutate_all(x, ~ str_extract_all(.x, ".{1,5}") %>% map_chr(., ~ paste(.x, collapse = "\n"))) iris2 %>% ggplot() + aes(Sepal.Length, Sepal.Width) + geom_point() + facet_wrap(~ Species_jp2, labeller = facet_splitter) + # 上記関数を適用 theme(strip.text = element_text(family = 'HiraKakuProN-W3'))
ちなみに、labeller
を使わないでも先にmutateでfacetに指定する列に同様のことをおこなっておいてもよい。
iris2 %>% mutate(Species_jp2 = (str_extract_all(Species_jp2, '.{1,5}') %>% map_chr(., ~ paste(., collapse = "\n")))) %>% # 直接書き換える ggplot() + aes(Sepal.Length, Sepal.Width) + geom_point() + facet_wrap(~ Species_jp2) + # 上記関数を適用 theme(strip.text = element_text(family = 'HiraKakuProN-W3'))
ただし、決まった文字数で改行しているので単語の中途半端なところで改行は発生している。本当は、単語を識別していい感じのところで改行して欲しいがまぁそれは色々と難しそう(Mecabとか使いながら色々処理する?)なので置いておく。
余談
世の中の情報のほとんどは英語で落ちているため、今回のようなことはググっても日本語では見当たらないし、英語で探しても「 label_wrap_gen
を使えばいいよ :)」 という回答ばかりで困っていたので、 r-wakalangで質問した。回答してくださった方々ありがとうございました!