如何在ggplot中用shape展示year与position变量并优化误差线?
解决方案
需求回顾
- 在现有可视化中新增
position变量(Upper/Lower)的展示:同一year分组内,用空心/实心形状区分不同position,形状颜色保持与stream变量一致 - 隐藏形状内部的误差线,仅显示外部部分
数据与现有代码
数据结构
rep <- structure(list(stream = c("Rannoch", "Rannoch", "Vaich", "Vaich", "Rannoch", "Rannoch", "Vaich", "Vaich", "Blackwater", "Blackwater", "Rannoch", "Rannoch", "Vaich", "Vaich", "Rannoch", "Rannoch", "Vaich", "Vaich", "Blackwater", "Blackwater"), position = c("Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower", "Upper ", "Lower"), year = c("2020", "2020", "2020", "2020", "2021", "2021", "2021", "2021", "2021", "2021", "2020", "2020", "2020", "2020", "2021", "2021", "2021", "2021", "2021", "2021"), deg_hour_23 = c(197, 25, 6, 92, 24, 123, 0, 15, 23.7, 29, 197, 25, 0, 92, 24, 123, 3, 15, 23.7, 29 ), density = c(14L, 19L, 32L, 7L, 9L, 24L, 40L, 14L, 16L, 2L, 16L, 17L, 28L, 9L, 15L, 20L, 36L, 18L, 12L, 6L), sample = c("A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "D", "D", "D", "D", "D", "D")), row.names = c(NA, -20L), class = "data.frame")
现有绘图代码
rep$year <- as.character(rep$year) rep %>% ggplot(aes(x= deg_hour_23, y= density, col=stream, shape=year))+ stat_summary(fun.y=mean, geom="point", size=4) + scale_shape_manual(values = c(19, 17), name="Year:", labels = c("2020", "2021")) + scale_color_manual(values= c("#AD9300", "#1566AD", "#FF677B"), name="Stream:", labels = c("Blackwater", "Rannoch", "Vaich"))+ stat_summary(fun.data = mean_se, geom = "errorbar", linetype=1, width = 2.5)+ theme(legend.title = element_text(size=20), legend.text=element_text(size=20))+ labs(x="Degree hours exceeding 23ºC", y= expression(Ln(fry~density)~(g/m^{"2"})))+ theme_classic(base_size = 25)+ scale_x_continuous(breaks = seq(0, 200, by = 25))+ theme(legend.position="bottom", legend.margin=margin())
修改后的代码及说明
完整代码
# 清理position变量的多余空格 rep$position <- trimws(rep$position) rep$year <- as.character(rep$year) rep %>% ggplot(aes(x= deg_hour_23, y= density, col=stream)) + # 先绘制误差线,确保在点图层下方 stat_summary(fun.data = mean_se, geom = "errorbar", linetype=1, width = 2.5, size=1) + # 将shape映射为year与position的组合,实现同year内空心/实心区分 stat_summary(aes(shape=interaction(year, position)), fun.y=mean, geom="point", size=4) + # 手动指定形状:2020用圆(实心/空心),2021用三角(实心/空心) scale_shape_manual( values = c("2020.Upper"=19, "2020.Lower"=1, "2021.Upper"=17, "2021.Lower"=2), name="Group", labels = c("2020 - Upper", "2020 - Lower", "2021 - Upper", "2021 - Lower") ) + scale_color_manual( values= c("#AD9300", "#1566AD", "#FF677B"), name="Stream:", labels = c("Blackwater", "Rannoch", "Vaich") ) + labs( x="Degree hours exceeding 23ºC", y= expression(Ln(fry~density)~(g/m^{"2"})) ) + theme_classic(base_size = 25) + scale_x_continuous(breaks = seq(0, 200, by = 25)) + theme( legend.title = element_text(size=20), legend.text=element_text(size=20), legend.position="bottom", legend.margin=margin() )
关键修改点
- 清理数据:用
trimws()去掉position变量中"Upper "的多余空格,避免分组识别错误 - 形状映射调整:将
shape映射改为interaction(year, position),让每个年份+位置的组合对应唯一形状 - 形状值指定:为每个组合匹配对应形状——2020年Upper用实心圆(19)、Lower用空心圆(1);2021年Upper用实心三角(17)、Lower用空心三角(2),既区分年份形状,又通过空心/实心区分位置
- 图层顺序调整:先绘制误差线,再绘制点,利用点图层覆盖误差线穿过形状内部的部分,只保留外部可见的误差线段
- 图例优化:修改图例名称和标签,让分组信息更直观
内容的提问来源于stack exchange,提问作者Fionn
相关产品推荐
相关产品推荐

