求助:用ggplot绘制按acquiYear分组的直方图及密度曲线
R语言实现:按年份分组绘制带密度曲线的条形图
需求说明
针对数据表dt,实现以下可视化需求:
- 按
acquiYear(获取年份)分组,每个年份下的month(月份)对应一个条形,条形高度为nrOrders(订单数量) - 为每个年份添加一条跨月份的订单数量密度曲线
- 指定年份颜色:
#00943C(2014)、#4A52A0(2015)、#FDC300(2016)、#6F6F6F(2017)、#EC4C24(2018)
数据表结构
structure(list(acquiYear = c("2014", "2014", "2014", "2014", "2014", "2014", "2014", "2014", "2014", "2014", "2014", "2014", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2015", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", "2018", "2018", "2018", "2018", "2018", "2018", "2018", "2018", "2018", "2018", "2018", "2018"), month = structure(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L), .Label = c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), class = "factor"), nrOrders = c(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 2, 4, 5, 3, 7, 3, 5, 4, 3, 7, 8, 7, 2, 24, 16, 33, 9, 27, 16, 10, 27, 9, 31, 35, 11, 11, 25, 15, 18, 19, 19, 8, 27, 34, 43, 51, 0, 11, 2, 0, 0, 0, 0, 0, 4, 5, 1, 0), ), row.names = c(NA, -60L), class = c("data.table", "data.frame"))
实现代码
我们使用ggplot2包完成可视化,同时利用data.table处理数据结构:
# 加载依赖包 library(ggplot2) library(data.table) # 定义年份对应颜色 year_colors <- c("#00943C", "#4A52A0", "#FDC300", "#6F6F6F", "#EC4C24") names(year_colors) <- unique(dt$acquiYear) # 绑定颜色与年份 # 绘制分面式可视化(每个年份单独面板,更清晰) ggplot(dt, aes(x = month)) + # 绘制月份订单条形图 geom_col(aes(y = nrOrders, fill = acquiYear), width = 0.7, show.legend = FALSE) + # 添加密度曲线:将月份转为数值计算密度,缩放y轴匹配订单数量范围 stat_density(aes(x = as.numeric(month), y = ..density.. * max(dt$nrOrders), color = acquiYear), geom = "line", size = 1, show.legend = FALSE) + # 按年份分面 facet_wrap(~acquiYear, ncol = 2) + # 设置填充色与曲线颜色 scale_fill_manual(values = year_colors) + scale_color_manual(values = year_colors) + # 添加右侧密度轴,便于观察密度趋势 scale_y_continuous(sec.axis = sec_axis(~./max(dt$nrOrders), name = "订单密度")) + # 设置坐标轴标签 labs(x = "月份", y = "订单数量") + # 调整主题样式 theme_minimal() + theme( axis.text.x = element_text(angle = 45, hjust = 1), strip.text = element_text(size = 10, face = "bold", color = year_colors) )
代码说明
- 颜色绑定:将指定颜色与年份一一对应,确保可视化风格统一
- 条形图绘制:每个月份对应一个条形,高度为订单数量,填充色为对应年份颜色
- 密度曲线:将离散的月份转为数值型,计算订单数量的核密度估计,通过缩放密度值使其与订单数量的y轴范围匹配,便于同时观察绝对值与分布趋势
- 分面布局:每个年份单独一个面板,避免不同年份的数据拥挤重叠
- 双y轴:右侧添加密度轴,清晰展示订单数量在各月份的分布密度
备选:分组条形图(同一面板展示所有年份)
如果需要在同一个面板展示所有年份的条形与曲线,可使用以下代码:
ggplot(dt, aes(x = month)) + # 分组条形图,按年份错开排列 geom_col(aes(y = nrOrders, fill = acquiYear), position = position_dodge(width = 0.8), width = 0.7) + # 分组密度曲线,与条形对齐 stat_density(data = dt, aes(x = as.numeric(month), y = ..density.. * max(dt$nrOrders), color = acquiYear, group = acquiYear), geom = "line", size = 1, position = position_dodge(width = 0.8)) + # 设置颜色 scale_fill_manual(values = year_colors, name = "获取年份") + scale_color_manual(values = year_colors, name = "获取年份") + labs(x = "月份", y = "订单数量") + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1))
内容的提问来源于stack exchange,提问作者Miko
相关产品推荐
相关产品推荐

