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)

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

このとき、各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)

結果を見ると、並び替えは起きているようだが上手くいっていない。
データを出力してみると、以下のようになっており先程と同様にデータフレームでcutが出てきた順で、グラフの下からIdeal,Fair,...といった表示になっている。
df_filtered %>% mutate(cut = fct_reorder2(cut, n, clarity)) %>% # nで並び替える arrange(cut)

グラフで使う場合は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変数のみ

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

なお、コード中に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')

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)

これをそのまま出力すると、当たり前だがclarityの順でfacetが表示される。
df2 %>% ggplot(aes(n, cut, fill = clarity)) + geom_col() + facet_wrap(. ~ clarity)

これを同じclarity_groupを固めて表示したい。
facetに2軸を指定する方法
1つ目の方法として、clarity_groupもfacetに表示する方法が考えられる。
df2 %>% ggplot(aes(n, cut, fill = clarity)) + geom_col() + facet_wrap(. ~ clarity_group + clarity)

目的通りclarity_groupが固まって表示されているが、facetと凡例の順が一致していないし、表示があまりきれいではない。
fct_reorderを使う方法
前節でちらっと出たfct_reorderを使い、clarityをclarity_group基準に並び替える。
df2 %>% mutate(clarity = fct_reorder(clarity, clarity_group)) %>% ggplot(aes(n, cut, fill = clarity)) + geom_col() + facet_wrap(. ~ clarity)

この場合は、facetと凡例の順番が一致している。
任意の順にする
また、今回clarity_groupはcharなのでアルファベット順だが任意の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)
