如何在ggplot中绘制双轴图并匹配刻度实现图层叠加?
搞定ggplot双Y轴刻度匹配问题
问题背景
要做一个双Y轴图表,但production(产量,数值在10000-10500之间)和price(价格,数值98-110)的刻度差太大,直接叠图层的话,其中一个会显示得完全不正常。核心是要让右侧Y轴的刻度和左侧对应,让两个图层能准确对齐展示。
示例数据
df <- data.frame(year= c(2000, 2001, 2002, 2003, 2004, 2005), price= c(100, 105, 102, 110, 98, 102), production= c(10000, 10500, 10250, 10300, 10450, 10320))
现有代码的问题
你现在写的代码把左侧Y轴范围设成了价格的区间,导致产量柱子被压得几乎看不见,右侧轴也没做任何有效转换,完全起不到双Y轴的作用:
ggplot() + geom_bar(data= df, aes(x=year, y=production), stat = "identity") + geom_line(data= df, aes(x=year, y=price), color= "red") + labs(x="Year", y = "Production (Kg)") + scale_y_continuous(limits=c(95, 110), sec.axis = sec_axis(~ . *1 , name = "Price ($)")) + theme_bw()
正确的实现方法
ggplot的双Y轴本质是把其中一组数据按比例转换到另一组的刻度区间,然后右侧轴再用反向公式还原原始刻度。具体步骤如下:
- 先算出两组数据的极值:产量的最小/最大值、价格的最小/最大值;
- 把价格数据转换到产量的刻度区间里,这样折线图就能和柱状图的高度匹配;
- 给右侧Y轴设置反向转换公式,让它显示原始的价格数值。
直接用下面的代码就行:
library(ggplot2) # 计算两组数据的极值,用来做转换 prod_min <- min(df$production) prod_max <- max(df$production) price_min <- min(df$price) price_max <- max(df$price) ggplot(df, aes(x = year)) + # 产量柱状图,用原始数据 geom_bar(aes(y = production), stat = "identity", fill = "steelblue", alpha = 0.7) + # 价格折线图:把价格转成产量区间的数值,这样能和柱子对齐 geom_line(aes(y = (price - price_min)/(price_max - price_min)*(prod_max - prod_min) + prod_min), color = "red", linewidth = 1) + # 设置双Y轴:左侧是产量,右侧通过反向公式还原价格 scale_y_continuous( name = "Production (Kg)", sec.axis = sec_axis( trans = ~ (. - prod_min)/(prod_max - prod_min)*(price_max - price_min) + price_min, name = "Price ($)" ) ) + labs(x = "Year") + theme_bw()
效果说明
这样改完之后,折线图的位置会和柱状图的刻度范围完全匹配,右侧Y轴显示的是真实的价格数值,两个图层都能正常展示,不会出现其中一个被压缩的情况。
内容的提问来源于stack exchange,提问作者YouLocalRUser
相关产品推荐
相关产品推荐

