ggplot2分面条形图排序 固定All在顶部Z在底部
ggplot2 分面条形图固定指定条目上下位置实现方法
现有基础
我有2个数值变量(sale、cost)和2个分类变量(model、level),样例数据如下:
model level sale cost Colour 1 A HIGH 100 -110 black 2 B HIGH 120 -89 khaki1 3 C HIGH 500 -20 red 4 D HIGH 455 -300 green 5 E HIGH 456 -110 chocolate 6 F HIGH 12 -120 orange 7 G HIGH 56 -56 blue 8 H HIGH 98 -300 gold 9 All HIGH 889 -790 sienna 10 Z HIGH 456 -30 yellow 11 A LOW 432 -70 black 12 B LOW 567 -40 khaki1 13 C LOW 345 -30 red 14 D LOW 345 -120 green 15 E LOW 100 -10 chocolate 16 F LOW 67 -21 orange 17 G LOW 34 -24 blue 18 H LOW 110 -540 gold 19 All LOW 670 -123 sienna 20 Z LOW 160 -45 yellow
基于上述数据绘制了包含正负值的条形图,图表按level列拆分为2个分面,默认按sale值从上到下排序,原有绘图代码如下:
ggplot() + geom_col(aes(value, tidytext::reorder_within(model, value, level), fill = model, color = model), data = df[df$sign == "sale", ], position = "stack") + scale_fill_manual(values = Colour, breaks = df$model) + scale_color_manual(values = Colour, breaks = df$model)+ geom_col(aes(value, tidytext::reorder_within(model, value, level), color = model), data = df[df$sign == "cost", ], fill = "white", position = "stack") + tidytext::scale_y_reordered() + labs(fill = "model") + facet_grid(level ~ ., switch = "y",scales = "free_y") + theme(axis.text.x = element_text(angle = 90), strip.background = element_rect(fill = "white"), strip.placement = "outside", strip.text.y.left = element_text(angle = 0), panel.spacing = unit(0, "lines")) + theme(legend.position="none") + labs(y = " ") + geom_vline(xintercept = 0,linetype="dotted", color="white")
调整需求
修改条形排序逻辑,实现:
model取值为All的条目始终显示在每个分面的最顶部model取值为Z的条目始终显示在每个分面的最底部- 其余条目保持原有按
sale值从上到下排序的规则
实现方案
核心思路是自定义reorder_within用到的排序权重,不需要改动原有绘图的图层逻辑,只需要提前给数据集增加排序键、替换排序变量即可:
- 数据预处理阶段,按
level分组生成自定义排序键:All赋最高排序权重,Z赋最低排序权重,其余条目用sale值作为排序依据,同时完成宽表转长表的操作适配原有绘图逻辑
library(dplyr) library(tidyr) df <- df %>% group_by(level) %>% mutate( sort_key = case_when( model == "All" ~ Inf, # 无穷大权重保证排在最顶 model == "Z" ~ -Inf, # 负无穷权重保证排在最底 TRUE ~ sale # 其余条目保持按sale排序 ) ) %>% ungroup() %>% pivot_longer(cols = c(sale, cost), names_to = "sign", values_to = "value")
- 把原有两处
geom_col调用里reorder_within的排序变量从value替换为刚生成的sort_key,其余代码完全保留即可:
ggplot() + geom_col(aes(value, tidytext::reorder_within(model, sort_key, level), fill = model, color = model), data = df[df$sign == "sale", ], position = "stack") + scale_fill_manual(values = Colour, breaks = df$model) + scale_color_manual(values = Colour, breaks = df$model)+ geom_col(aes(value, tidytext::reorder_within(model, sort_key, level), color = model), data = df[df$sign == "cost", ], fill = "white", position = "stack") + tidytext::scale_y_reordered() + labs(fill = "model") + facet_grid(level ~ ., switch = "y",scales = "free_y") + theme(axis.text.x = element_text(angle = 90), strip.background = element_rect(fill = "white"), strip.placement = "outside", strip.text.y.left = element_text(angle = 0), panel.spacing = unit(0, "lines")) + theme(legend.position="none") + labs(y = " ") + geom_vline(xintercept = 0,linetype="dotted", color="white")
说明:转长表后同一个
model+level组合下的sale和cost行会继承同一个sort_key值,不会出现同一模型两个条形错位的问题。
内容的提问来源于stack exchange,提问作者user18937485
相关产品推荐
相关产品推荐

