如何对含双因子的ggplot2 geom_col图X轴进行分组排序
问题描述
我已尝试过本站同类问题的解决方法,但始终未能解决该问题。
我使用Kaggle平台的泰坦尼克数据集,期望实现的效果为:在每个Pclass因子分组内,代表age.class的柱状条按照计数n从低到高排序。
原实现代码如下:
library(tidyverse) library(titanic) df <- titanic::titanic_train head(df) # Start ------------------------------------------------------------------- df = df %>% mutate(has.cabin = if_else(Cabin == '', 0, 1) %>% as.factor(), Pclass = Pclass %>% as.factor(), age.class = case_when( Age < 5 ~ 'baby', Age >5 & Age < 12 ~ 'Child', Age > 12 & Age < 18 ~ 'Teen', Age > 18 & Age < 25 ~ 'Young Adult', Age > 25 & Age <35 ~ 'Mid Adult', Age > 35 & Age < 60 ~ 'Adult', Age > 60 ~ 'Elderly', TRUE ~ 'Undefined' ) ) plot.data = df %>% count(has.cabin, Pclass, age.class) lvls <- unique(plot.data$Pclass[order(plot.data$age.class,-plot.data$n)]) plot.data$age.classv2 = factor(plot.data$age.class, levels=lvls) plot.data %>% ggplot(., aes(x = Pclass, y = n, fill = age.class)) + geom_col(position = 'dodge') + facet_grid(~ has.cabin)
问题原因
原代码的因子设置逻辑存在两个核心错误:
- 生成水平向量时取错了变量:
lvls提取的是Pclass列的排序结果,Pclass仅包含3个等级,完全无法匹配age.class的7个分类,后续创建的age.classv2变量因子水平不匹配,绘图时根本不会生效。 - 普通全局因子水平无法实现分组内独立排序:R的因子水平是全局统一的,同一个分类值只能对应一个固定顺序,直接设置全局因子没法做到不同Pclass分组下age.class的排序随组内n值变化。
解决方案
使用tidytext包提供的组内重排函数可以快速实现需求,不需要手动拼接处理因子:
library(tidyverse) library(titanic) # 未安装tidytext可先运行下一行 # install.packages("tidytext") library(tidytext) df <- titanic::titanic_train # 基础数据预处理逻辑保持不变 df = df %>% mutate(has.cabin = if_else(Cabin == '', 0, 1) %>% as.factor(), Pclass = Pclass %>% as.factor(), age.class = case_when( Age < 5 ~ 'baby', Age >5 & Age < 12 ~ 'Child', Age > 12 & Age < 18 ~ 'Teen', Age > 18 & Age < 25 ~ 'Young Adult', Age > 25 & Age <35 ~ 'Mid Adult', Age > 35 & Age < 60 ~ 'Adult', Age > 60 ~ 'Elderly', TRUE ~ 'Undefined' ) ) plot.data = df %>% count(has.cabin, Pclass, age.class) %>% # 核心步骤:按has.cabin、Pclass分组,组内按n值从小到大重排age.class顺序 mutate(age.class_ordered = reorder_within(age.class, n, list(has.cabin, Pclass))) plot.data %>% ggplot(aes(x = Pclass, y = n, fill = age.class_ordered)) + geom_col(position = 'dodge') + # 调整图例显示,去掉自动拼接的分组后缀,展示原始age.class名称 scale_fill_reordered("age.class", labels = ~gsub("___.*", "", .)) + facet_grid(~ has.cabin)
如果不想额外安装tidytext包,也可以手动实现相同逻辑:计数后按has.cabin、Pclass、n排序,给每个「分组+age.class」组合生成唯一标识后设置为因子,绘图时同样调整刻度标签去掉分组后缀即可,核心逻辑和上述函数完全一致。
内容的提问来源于stack exchange,提问作者McGez
相关产品推荐
相关产品推荐

