如何在同一张图中绘制双Y轴:搭配geom_col与geom_line图层
问题描述
我有如下R语言数据集:
yeardesc<-seq(2002,2020,2) prop1<-c(0.6751152,0.6746591,0.6913932,0.74829,0.7085363,0.7679045,0.8328877,0.7802125,0.7992271,0.8180833) prop2<-c(0.02150538,0.07438795,0.05994291,0.08120438,0.09961588,0.07418163,0.07314629,0.1220751,0.1073002,0.1470971) money1<-c(3783.255,4512.181,4237.779,4163.842,4267.878,4708.089,4244.439,4407.01,4193.522,5140.635) money2<-c(382.9129,643.6798,606.3505,600.3303,713.0684,405.1913,463.76,787.4756,572.8035,1010.126) data<-data.frame(yeardesc,prop1,prop2,money1,money2)
我需要绘制满足以下要求的可视化图形:
- 用蓝色线条(
geom_line)展示prop1和prop2的趋势 - 用红色柱状(
geom_col)展示money1和money2的数值 - 配置两个刻度范围不同的Y轴,分别对应比例数据和金额数据
解决方案
在ggplot2中实现双Y轴,核心思路是通过数据缩放让两组不同量级的数据适配同一坐标系,再通过手动设置右侧轴的刻度标签还原原始数值。以下是可直接运行的完整代码:
library(ggplot2) # 计算金额数据的缩放比例,使其最大值匹配比例数据的最大值 scale_ratio <- max(data[, c("prop1", "prop2")]) / max(data[, c("money1", "money2")]) ggplot(data, aes(x = yeardesc)) + # 绘制红色柱状图:先画money1(宽柱),再画money2(窄柱),注意缩放数据 geom_col(aes(y = money1 * scale_ratio), fill = "red", alpha = 0.7, width = 0.8) + geom_col(aes(y = money2 * scale_ratio), fill = "darkred", alpha = 0.7, width = 0.4) + # 绘制蓝色线条:prop1(实线)、prop2(虚线) geom_line(aes(y = prop1), color = "blue", linewidth = 1.2) + geom_line(aes(y = prop2), color = "darkblue", linewidth = 1.2, linetype = "dashed") + # 给线条添加点标记,提升可读性 geom_point(aes(y = prop1), color = "blue", size = 2) + geom_point(aes(y = prop2), color = "darkblue", size = 2) + # 配置双Y轴:左侧为比例数据,右侧为还原后的金额数据 scale_y_continuous( name = "比例值", limits = c(0, max(data[, c("prop1", "prop2")]) * 1.1), breaks = seq(0, 0.9, 0.1), sec.axis = sec_axis( ~ . / scale_ratio, name = "金额值", breaks = seq(0, 6000, 1000) ) ) + # 配置X轴刻度为指定年份 scale_x_continuous(name = "年份", breaks = yeardesc) + # 主题与样式调整 theme_minimal() + theme( axis.title.y = element_text(color = "blue"), axis.title.y.right = element_text(color = "red"), legend.position = "top", plot.title = element_text(hjust = 0.5) ) + # 添加标题与图例 labs( title = "年份-比例与金额趋势对比", color = "指标", fill = "金额指标" ) + # 统一图例(可选,让线条和柱子的图例合并) scale_color_manual(values = c("blue", "darkblue"), labels = c("prop1", "prop2")) + scale_fill_manual(values = c("red", "darkred"), labels = c("money1", "money2"))
关键说明:
- 数据缩放:
scale_ratio将金额数据按比例缩小,使其范围与比例数据对齐,避免柱子过高遮挡线条。 - 图层顺序:先绘制柱状图,再绘制线条,确保线条显示在上方。
- 双Y轴实现:
sec.axis参数通过反向运算(~ . / scale_ratio)将缩放后的数值还原为原始金额,实现右侧轴的刻度匹配。 - 样式优化:用颜色区分两组数据,添加透明度、点标记和主题调整,提升图形的可读性与美观度。
内容的提问来源于stack exchange,提问作者Ludwig Gershwin
相关产品推荐
相关产品推荐

