まずは蝋の翼から。

学んだことを書きながら確認・整理するためのメモブログ。こういうことなのかな?といったことをふわっと書いたりしていますが、理解が浅いゆえに的はずれなことも多々あると思うのでツッコミ歓迎

ggplotで他の変数を基準に並び替える

数値で並び替える場合

以下のようなグラフで考える。

library(tidyverse)

data(diamonds)

# データ作成
df = diamonds %>% 
  group_by(clarity, cut) %>% 
  summarise(n = n()) %>% 
  ungroup()

# わかりやすいものだけ抽出
df_filtered = df %>% 
  filter(clarity %in% c('SI2', 'VVS2', 'IF'))

# clarityの標準の順番
df_filtered %>% 
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~ clarity)

f:id:chito_ng:20200620180711p:plain:w600

このとき、各facetでの棒グラフはデータフレームでcutが出てきた順で、グラフの下からFair,Good,...といった表示になっている。

f:id:chito_ng:20200620180828p:plain:w300

このとき、各facet毎に、棒グラフの長さ順で並び替えたい。

factor変数に対して、他の変数を基準に並び替えたい場合は一般的にfct_reorderで並び替える。今回は2変数を基準にするのでfct_reorder2を使う。

df_filtered %>% 
  mutate(cut = fct_reorder2(cut, n, clarity)) %>% # nで並び替える
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~ clarity)

f:id:chito_ng:20200620181124p:plain:w600

結果を見ると、並び替えは起きているようだが上手くいっていない。

データを出力してみると、以下のようになっており先程と同様にデータフレームでcutが出てきた順で、グラフの下からIdeal,Fair,...といった表示になっている。

df_filtered %>% 
  mutate(cut = fct_reorder2(cut, n, clarity)) %>% # nで並び替える
  arrange(cut)

f:id:chito_ng:20200620182246p:plain:w300

グラフで使う場合はreorder_withinを使う。

df_filtered %>% 
  mutate(cut = reorder_within(cut, n, clarity)) %>% # n, clarityで並び替える
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  scale_y_reordered() + # __で結合されているのを削除
  facet_wrap(. ~ clarity, scales = 'free_y') # 自分のfacet変数のみ

f:id:chito_ng:20200623104254p:plain:w600

これは内部的に指定した変数(cut, clarity)を結合した新たな変数を用いてnで並び替えをおこなっている。
そのため、新たな結合された変数cut__clarityの出た順になるため各clarityのfacetでは自分のclarityが入っているcut__clarity以外はデータがないので「出た順に並び替える」ことができる。

df_filtered %>% 
  mutate(cut = reorder_within(cut, n, clarity)) %>% 
  arrange(cut)

f:id:chito_ng:20200620182732p:plain:w300

なお、コード中にscale_y_reorderedおよび、scales = 'free_y'を追加しているが、前者は「表示を結合状態から元に戻す」働きがある。

また、後者はデータがない部分を非表示にする働きがある。今回の場合、cut__clarityが自facet内のclarity以外はデータがないが表示自体はされるためscales = 'free_y'で非表示にできる。

これらを外して表示すると意味がわかりやすい。

df_filtered %>% 
  mutate(cut = reorder_within(cut, n, clarity)) %>% # n, clarityで並び替える
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  # scale_y_reordered() + # __で結合されているのを削除
  facet_wrap(. ~ clarity) #, scales = 'free_y')

f:id:chito_ng:20200620183407p:plain:w600

www.rdocumentation.org

facetを並び替える

facetは一般的にfactorとなっている。これを別変数を基準にしてfacetを並び替える。

データとして、clarity毎に1文字目を基準にgroupを作り、このgroup毎にclarityのfacetを並び替えて先程と同様のグラフを作成する。

df2 = diamonds %>% 
  mutate(clarity_group = substr(clarity, 1, 1)) %>% 
  group_by(clarity_group, clarity, cut) %>% 
  summarise(n = n()) %>% 
  ungroup()

df2 %>% 
  distinct(clarity_group, clarity) %>% 
  arrange(clarity_group, clarity)

f:id:chito_ng:20200620184047p:plain:w300

これをそのまま出力すると、当たり前だがclarityの順でfacetが表示される。

df2 %>% 
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~ clarity)

f:id:chito_ng:20200620184520p:plain:w600

これを同じclarity_groupを固めて表示したい。

facetに2軸を指定する方法

1つ目の方法として、clarity_groupもfacetに表示する方法が考えられる。

df2 %>% 
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~ clarity_group + clarity)

f:id:chito_ng:20200620184739p:plain:w600

目的通りclarity_groupが固まって表示されているが、facetと凡例の順が一致していないし、表示があまりきれいではない。

fct_reorderを使う方法

前節でちらっと出たfct_reorderを使い、clarityclarity_group基準に並び替える。

df2 %>% 
  mutate(clarity = fct_reorder(clarity, clarity_group)) %>% 
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~  clarity)

f:id:chito_ng:20200620185325p:plain:w600

この場合は、facetと凡例の順番が一致している。

任意の順にする

また、今回clarity_groupcharなのでアルファベット順だが任意のclarity_group順にしたい場合は、factorに変換する。

この際、そのままfct_reorderに指定すると型エラーになるのでas.numericでnumericに変換する必要がある。なお、factorをnumericにするとlevel部分の数値となる。

df2 %>% 
  mutate(clarity_group = factor(clarity_group, levels = c('S', 'V', 'I')),
         clarity = fct_reorder(clarity, as.numeric(clarity_group))) %>% # numericにする
  ggplot(aes(n, cut, fill = clarity)) +
  geom_col() +
  facet_wrap(. ~  clarity)

f:id:chito_ng:20200620185744p:plain:w600