如何在ggplot2共享X轴图表中添加右侧独立Y轴?
实现双Y轴的解决方案
嘿,我明白你想要在同一个图表里展示天气天数和物种数量、共用X轴但分开左右Y轴的需求!在ggplot2里,我们可以通过scale_y_continuous()的sec_axis()参数来实现双Y轴,不过要注意:双Y轴本质是共享同一个坐标系,所以需要对其中一个变量进行缩放,让它的数值范围适配另一个轴的刻度。
核心思路拆解
- 左Y轴保留天气数据的天数(降水、温度的
pre_value和tem_value,范围大概0-31) - 右Y轴展示物种数量
nb_species(这里只有一个有效值3),我们需要把nb_species乘以一个缩放因子,让它的位置落在左轴的范围内,再通过sec_axis()把缩放后的数值转换回原始物种数量显示在右轴上。
修改后的完整代码
# 加载ggplot2包 library(ggplot2) # 你的数据集 complet_b <- structure(list(SOUNAME = c("BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)", "BALLYSHANNON (CATHLEENS FALL)" ), year_month = c("2014-05", "2014-05", "2014-05", "2014-05", "2014-06", "2014-06", "2014-06", "2014-06", "2014-07", "2014-07", "2014-07", "2014-07"), pre_type = c("NONE", "HEAVY", "LIGHT", "MEDIUM", "NONE", "HEAVY", "LIGHT", "MEDIUM", "NONE", "HEAVY", "LIGHT", "MEDIUM"), pre_value = c(3, 6, 20, 2, 16, 2, 9, 2, 3, 3, 22, 3), tem_type = c("V_COLD", "COLD", "HOT", "MEDIUM", "V_COLD", "COLD", "HOT", "MEDIUM", "V_COLD", "COLD", "HOT", "MEDIUM"), tem_value = c(0, 31, 0, 0, 0, 24, 6, 0, 0, 23, 8, 0), nb_species = c(NA, 3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), x = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L)), .Names = c("SOUNAME", "year_month", "pre_type", "pre_value", "tem_type", "tem_value", "nb_species", "x"), row.names = c(NA, -12L), class = c("tbl_df", "tbl", "data.frame")) # 计算缩放因子:左轴最大天数是31,右轴最大物种数是3,用左轴最大值除以右轴最大值得到缩放比例 scale_factor <- max(complet_b$tem_value, na.rm = TRUE) / max(complet_b$nb_species, na.rm = TRUE) # 绘制图表 ggplot(data = complet_b) + # 降水柱状图,位置靠左 geom_bar(aes(x = x, y = pre_value, fill = pre_type), width = 0.3, stat = "identity") + # 温度柱状图,位置靠右(x偏移0.4避免重叠) geom_bar(aes(x = x + 0.4, y = tem_value, fill = tem_type), width = 0.3, stat = "identity") + # 物种数量点:y值用缩放后的数值,对应右轴刻度 geom_point(aes(x = x, y = nb_species * scale_factor), color = "darkred", size = 4) + # 设置X轴刻度与标签 scale_x_continuous(breaks = 1:3, labels = unique(complet_b$year_month)) + # 设置双Y轴:左轴显示天数,右轴还原物种数量 scale_y_continuous( name = "Number of Days (Precipitation/Temperature)", sec.axis = sec_axis(~./scale_factor, name = "Number of Species") ) + # 统一设置标题与标签 labs( x = "Date", title = "Weather Data & Species Count per Month", fill = "Frequency Category" ) + # 美化主题,区分双Y轴样式 theme_minimal() + theme( plot.title = element_text(hjust = 0.5), axis.title.y.right = element_text(color = "darkred"), axis.text.y.right = element_text(color = "darkred") )
关键细节说明
- 缩放因子:确保物种数量的点能落在左轴的数值范围内,这里3×10.33≈31,刚好对应左轴的最大值,位置更合理。
- 双Y轴逻辑:
sec_axis(~./scale_factor)是把左轴的缩放数值反向计算,还原为原始物种数量,作为右轴的刻度标签。 - 视觉区分:把物种点和右轴刻度设为深红色,让读者能快速区分两个不同维度的数据,避免混淆。
- 代码优化:合并了你原来重复的
xlab、ylab设置,避免参数覆盖问题。
这样你就能得到一个共用X轴、左右Y轴分别展示天气天数和物种数量的清晰图表啦!
内容的提问来源于stack exchange,提问作者Elodie P.
相关产品推荐
相关产品推荐

