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

在R语言中绘制带主次坐标轴的图表:实现方法与轴范围调整

实现双轴复合图表(柱状+折线)的R方案

一、ggplot2 实现方法(支持灵活调整轴范围)

ggplot2从2.2.0版本开始就支持次轴功能,只是需要通过数据线性转换来实现(这是其设计逻辑,避免随意使用次轴造成数据误解)。针对你的需求,我们可以通过自定义转换规则,让柱状图(人口数据)始终位于折线图(变量数据)下方,同时支持手动或自动调整轴范围。

代码示例

library(ggplot2)
library(tidyr)

# 将多列变量转成长格式,方便绘制多条折线
df_long <- df %>%
  pivot_longer(cols = starts_with("var_"), names_to = "variable", values_to = "value")

# 自定义轴范围:可根据需求修改
main_y_min <- -500   # 主轴(变量)最小值
main_y_max <- 1500   # 主轴(变量)最大值
sec_y_min <- 0       # 次轴(人口)最小值
sec_y_max <- 30000000# 次轴(人口)最大值

# 定义人口数据到主轴刻度的转换函数
pop_to_main <- function(pop) {
  ((pop - sec_y_min) / (sec_y_max - sec_y_min)) * (main_y_max - main_y_min) + main_y_min
}
# 定义主轴刻度到人口数据的反向转换函数(用于次轴标签)
main_to_pop <- function(y) {
  ((y - main_y_min) / (main_y_max - main_y_min)) * (sec_y_max - sec_y_min) + sec_y_min
}

# 绘制图表
ggplot() +
  # 绘制柱状图:使用转换后的人口值映射到主轴
  geom_col(data = df, aes(x = city, y = pop_to_main(pop)), fill = "#4a86e8", width = 0.6) +
  # 绘制折线和数据点:使用原始变量值
  geom_line(data = df_long, aes(x = city, y = value, color = variable, group = variable), linewidth = 1) +
  geom_point(data = df_long, aes(x = city, y = value, color = variable), size = 3) +
  # 设置主/次轴参数
  scale_y_continuous(
    name = "Variable Values",
    limits = c(main_y_min, main_y_max),
    sec.axis = sec_axis(~ main_to_pop(.), name = "Population")
  ) +
  # 自定义折线颜色
  scale_color_manual(values = c("var_1" = "#ff0000", "var_2" = "#009933", "var_3" = "#ff9900")) +
  labs(x = "City", color = "Variables") +
  theme_minimal() +
  # 区分主次轴颜色,提升可读性
  theme(
    axis.title.y.right = element_text(color = "#4a86e8"),
    axis.text.y.right = element_text(color = "#4a86e8")
  )

核心说明

  • 通过pop_to_main函数将人口数据缩放到主轴的刻度区间内,确保柱状图视觉上位于折线下方;
  • 修改main_y_min/main_y_max/sec_y_min/sec_y_max即可灵活调整轴范围;
  • 次轴标签通过反向转换函数还原真实人口数值,避免数据失真。

二、其他替代方案

1. Plotly 交互式图表

Plotly支持更直观的双轴设置,无需手动转换数据,适合需要交互操作的场景:

library(plotly)
library(tidyr)

df_long <- df %>% pivot_longer(cols = starts_with("var_"), names_to = "variable", values_to = "value")

plot_ly() %>%
  # 添加柱状图,绑定到次轴
  add_bars(data = df, x = ~city, y = ~pop, name = "Population", yaxis = "y2", marker = list(color = "#4a86e8")) %>%
  # 添加折线和数据点,绑定到主轴
  add_lines(data = df_long, x = ~city, y = ~value, color = ~variable, name = ~variable, line = list(width = 2)) %>%
  add_markers(data = df_long, x = ~city, y = ~value, color = ~variable, name = ~variable, marker = list(size = 6)) %>%
  # 设置轴范围和布局
  layout(
    xaxis = list(title = "City"),
    yaxis = list(title = "Variable Values", range = c(-500, 1500)),
    yaxis2 = list(title = "Population", range = c(0, 30000000), overlaying = "y", side = "right"),
    legend = list(x = 1.1, y = 1)
  )

2. Base R 原生绘图

如果不需要ggplot2的语法糖,Base R也可以直接实现双轴图表:

# 调整图形边距,预留次轴空间
par(mar = c(5, 4, 4, 4) + 0.1)

# 先绘制折线图(主轴)
plot(df$city, df$var_1, type = "b", col = "#ff0000", lwd = 2, pch = 16,
     ylim = c(-500, 1500), xlab = "City", ylab = "Variable Values")
lines(df$city, df$var_2, type = "b", col = "#009933", lwd = 2, pch = 16)
lines(df$city, df$var_3, type = "b", col = "#ff9900", lwd = 2, pch = 16)

# 开启新图层,绘制柱状图(次轴)
par(new = TRUE)
barplot(df$pop, names.arg = df$city, col = "#4a86e8", width = 0.6,
        ylim = c(0, 30000000), axes = FALSE, xlab = "", ylab = "")
axis(side = 4)
mtext("Population", side = 4, line = 3)

# 添加图例
legend("topright", legend = c("var_1", "var_2", "var_3", "Population"),
       col = c("#ff0000", "#009933", "#ff9900", "#4a86e8"),
       lty = c(1,1,1,NA), pch = c(16,16,16,15), bty = "n")

三、关于ggplot2次轴的支持情况

目前ggplot2已经完全支持次轴功能(通过sec_axis()函数实现),只是官方文档不鼓励滥用双轴——因为双轴容易造成数据解读偏差,但如果是像你这种需要对比量级差异极大的两类数据,合理使用是完全可行的,只要保证转换逻辑清晰、轴标签明确即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:29:44