使用facet_wrap绘图时如何按指定数值对因子变量排序?
R语言ggplot2按均值排序因子变量的解决方案
问题原因
你当前代码排序未生效的核心原因是:每个language因子水平对应了Male、Female两个不同的meanscore值,fct_reorder()默认会对每个因子水平对应的多个值取中位数作为排序依据,和你预期的排序逻辑不匹配。
解决方案
根据你的排序需求,可选择以下两种方案:
方案1:全局统一排序(两个分面语言顺序一致)
如果希望两个性别分面的语言顺序完全相同,按所有性别的平均得分整体排序,只需在fct_reorder中指定用均值作为汇总函数即可,修改后代码如下:
library(tidyverse) set.seed(200) # 结果可复现 df <- tibble( language = gl(4, 10, labels = c("Python", "R", "Javascipt", "Excel")), gender = factor(ifelse(sign(rnorm(40))==-1, 0, 1), labels = c("Male", "Female")), score = floor(runif(40, 25, 80)) ) df <- df %>% group_by(gender, language) %>% summarise(meanscore = mean(score)) df %>% # 指定用均值作为排序依据 mutate(language = fct_reorder(language, meanscore, .fun = mean)) %>% ggplot(aes(language, meanscore, fill = gender)) + geom_col() + facet_wrap(~gender) + coord_flip()
方案2:分面独立排序(每个分面按自身得分排序)
如果希望每个性别分面内的语言都单独按当前分面的平均得分排序,可以通过绑定因子+释放分面轴限制实现,代码如下:
library(tidyverse) set.seed(200) # 结果可复现 df <- tibble( language = gl(4, 10, labels = c("Python", "R", "Javascipt", "Excel")), gender = factor(ifelse(sign(rnorm(40))==-1, 0, 1), labels = c("Male", "Female")), score = floor(runif(40, 25, 80)) ) df <- df %>% group_by(gender, language) %>% summarise(meanscore = mean(score)) df %>% # 绑定性别和语言为新因子,按得分排序 mutate(lang_group = fct_reorder(interaction(language, gender), meanscore)) %>% ggplot(aes(lang_group, meanscore, fill = gender)) + geom_col() + # 分面释放y轴(翻转前的x轴)限制 facet_wrap(~gender, scales = "free_y") + # 修正轴标签为语言名称 scale_x_discrete(labels = ~stringr::str_remove(.x, "\\..*$")) + coord_flip() + labs(x = "language")
内容的提问来源于stack exchange,提问作者Moses
相关产品推荐
相关产品推荐

