如何为两家经销商的堆叠条形图分别按销量高低排序车型?
问题描述
现有一个名为cars的数据集,用于描述两家经销商的汽车品牌销售占比,数据集定义如下:
cars <- data.frame(dealership = rep(c("a", "b"), 3), car = rep(c("toyota", "ford", "opel"), each = 2), percent = c(10, 65, 40, 5, 50, 30))
需求:用堆叠条形图可视化该数据,每个经销商对应一个条形,且每个条形内的汽车品牌需按销量占比从高到低排序。
尝试了以下代码,但仅经销商B的车型排序正确,经销商A的车型顺序跟随B的顺序(toyota-opel-ford),而非正确的opel-ford-toyota:
#Arrange cars by dealership and sort them cars <- cars %>% group_by(dealership) %>% arrange(percent, .by_group = TRUE) #Create the stacked barplot ggplot(cars, aes(x = dealership, y = percent, fill = car)) + geom_bar(stat = "identity") + labs(title = "Car brands sold by dealership", x = "Dealership", y = "Percent") + coord_flip() + theme_minimal() + scale_fill_brewer(palette = "Set2")
解决方案
问题出在ggplot2中,fill参数使用的car是全局因子,其顺序是统一的,不会因为数据框的行顺序而在分组内独立变化。要实现每个经销商内的车型按销量排序,需要为每个经销商创建独立的车型排序因子。
具体步骤:
- 分组排序后,为每个经销商内的车型生成带分组标识的复合标签,并将其转换为因子,因子顺序与分组排序后的行顺序一致。
- 绘图时使用这个复合因子作为
fill的映射,再通过调整图例标签去掉分组前缀,保持图例简洁。
完整代码:
library(dplyr) library(ggplot2) # 原始数据集 cars <- data.frame(dealership = rep(c("a", "b"), 3), car = rep(c("toyota", "ford", "opel"), each = 2), percent = c(10, 65, 40, 5, 50, 30)) # 分组排序并创建带经销商标识的车型顺序因子 cars_sorted <- cars %>% group_by(dealership) %>% arrange(desc(percent), .by_group = TRUE) %>% # 按销量降序排列,升序去掉desc()即可 mutate(car_order = paste(dealership, car, sep = "-")) %>% # 创建复合标签区分不同经销商的同品牌车型 mutate(car_order = factor(car_order, levels = car_order)) # 按排序后的行顺序设置因子水平 # 绘制堆叠条形图 ggplot(cars_sorted, aes(x = dealership, y = percent, fill = car_order)) + geom_bar(stat = "identity") + labs(title = "Car brands sold by dealership", x = "Dealership", y = "Percent", fill = "Car Brand") + coord_flip() + theme_minimal() + scale_fill_brewer(palette = "Set2", labels = function(x) gsub("^.*-", "", x)) # 移除图例标签中的经销商前缀
代码说明:
arrange(desc(percent), .by_group = TRUE):确保每个经销商内的车型按销量降序排列,若需要升序显示,去掉desc()即可。car_order变量:通过拼接经销商和车型名称,让每个经销商的车型拥有独立的因子水平,彻底避免全局顺序的干扰。scale_fill_brewer的labels参数:用gsub正则匹配去掉复合标签的经销商前缀,让图例仅显示车型名称,保持视觉简洁。
内容的提问来源于stack exchange,提问作者Lucy
相关产品推荐
相关产品推荐

