You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言双Y轴散点图坐标轴设置问题及ggplot实现方法

双Y轴散点图实现方案

原代码出现标签重叠、刻度异常的核心原因有两个:一是第二个图层X轴错用anneemut变量,和主图层X轴valeurfonc不匹配导致坐标体系错位;二是未手动指定坐标轴参数,默认生成的刻度、标签不符合需求。以下分别给出base R修复版本和ggplot2实现版本。

1. Base R 修复版代码

修复逻辑对应问题点逐一调整:

  • 绘图初始关闭科学计数法,避免X轴出现科学计数格式
  • 第一个主图层直接定义好X、Y轴标签,第二个叠加图层强制清空轴标签,从根源避免标签重叠
  • 手动指定第一Y轴(年份)的刻度值为数据集中所有出现的年份,保证刻度完整
  • 修正第二个图层的X轴映射变量,和主图层保持一致,统一坐标体系
# 全局关闭科学计数法
options(scipen = 999)
# 调整画布边距,为第二Y轴预留展示空间
par(mar = c(5, 4, 4, 4) + 0.3)

# 绘制第一个散点图层:X轴映射交易价格,左Y轴映射交易年份
plot(
  x = px$valeurfonc, 
  y = px$anneemut, 
  pch = 16, 
  col = 2,
  xlab = "交易价格(valeurfonc)",
  ylab = "交易年份(anneemut)",
  yaxt = "n" # 关闭默认Y轴,后续手动添加完整年份刻度
)
# 手动添加左Y轴刻度,展示数据集中所有出现的年份
axis(side = 2, at = sort(unique(px$anneemut)))

# 叠加第二个散点图层
par(new = TRUE)
plot(
  x = px$valeurfonc, # 修正原代码的X变量映射错误,和主图层X轴保持一致
  y = px$sbati, 
  pch = 17, 
  col = 3,
  axes = FALSE, # 关闭默认坐标轴,避免覆盖主图层
  xlab = "", # 清空轴标签,避免和主图层标签重叠
  ylab = ""
)
# 添加右Y轴刻度与标签
axis(side = 4, at = pretty(range(px$sbati, na.rm = TRUE)))
mtext("房屋面积(sbati)", side = 4, line = 3)

# 添加图例区分两组散点
legend(
  "topright",
  legend = c("交易年份", "房屋面积"),
  pch = c(16,17),
  col = c(2,3)
)

2. ggplot2 实现版本

ggplot2从2.2.0版本开始支持sec_axis()函数实现双Y轴,由于两个Y轴量纲差异较大(年份为2014以上的四位整数,面积为几十到几百的数值),需要先计算缩放系数将次轴数据缩放到主轴数值范围,再在次轴定义时反向还原为真实刻度值:

library(ggplot2)
# 全局关闭科学计数法
options(scipen = 999)

# 计算双Y轴缩放系数:将面积值映射到年份的数值区间
y_range_year <- range(px$anneemut, na.rm = TRUE)
y_range_sbati <- range(px$sbati, na.rm = TRUE)
scale_factor <- diff(y_range_year) / diff(y_range_sbati)

ggplot(px, aes(x = valeurfonc)) +
  # 左Y轴散点:映射交易年份
  geom_point(aes(y = anneemut, color = "交易年份", shape = "交易年份"), size = 2) +
  # 右Y轴散点:映射房屋面积,先按系数做缩放适配主轴范围
  geom_point(aes(y = (sbati - y_range_sbati[1])*scale_factor + y_range_year[1], 
                 color = "房屋面积", shape = "房屋面积"), size = 2) +
  # 配置X轴:使用逗号格式标注数值,禁用科学计数法
  scale_x_continuous(name = "交易价格(valeurfonc)", labels = scales::comma) +
  # 配置双Y轴
  scale_y_continuous(
    name = "交易年份(anneemut)",
    breaks = sort(unique(px$anneemut)), # 左Y轴显示所有年份刻度
    # 配置右Y轴,反向缩放还原为真实面积刻度
    sec.axis = sec_axis(
      trans = ~(. - y_range_year[1])/scale_factor + y_range_sbati[1],
      name = "房屋面积(sbati)"
    )
  ) +
  # 自定义散点的颜色和形状
  scale_color_manual(values = c("交易年份" = 2, "房屋面积" = 3)) +
  scale_shape_manual(values = c("交易年份" = 16, "房屋面积" = 17)) +
  theme_bw() +
  theme(
    axis.title.y.right = element_text(color = 3),
    axis.text.y.right = element_text(color = 3),
    axis.title.y.left = element_text(color = 2),
    axis.text.y.left = element_text(color = 2),
    legend.position = "top",
    legend.title = element_blank()
  )

注意:双Y轴图表容易因刻度缩放比例问题造成视觉误导,正式分析场景建议优先使用分面图替代双Y轴做多变量展示。

内容的提问来源于stack exchange,提问作者mmcr_economics

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:57:12