ggplot双纵轴图表:geom_tile与geom_line组合的图例异常问题
解决双纵轴下geom_tile+geom_line的图例显示问题
你的推测完全正确:shape是geom_point()的专属美学属性,当前图例仅基于geom_line()的color映射,所以设置shape参数会被忽略。要让图例显示柱状图形,需要添加一个虚拟的geom层来承载shape属性,同时不影响实际图表显示。
解决方案代码
library(ggplot2) library(dplyr) library(plotly) # 保留原数据准备代码(此处省略,使用你提供的dfAll、brks2等变量) # 准备geom层:保持原geom_tile和geom_line设置,geom_tile仍需show.legend=FALSE ggtiles <- geom_tile(aes(x = Date, y = Val1/2, height = Val1, fill = ID, group = ID), na.rm = TRUE, stat = "identity", position = position_dodge(preserve = "single"), show.legend = FALSE) gglines <- geom_line(aes(x = Date, y = Val2_scl, color = ID, group = ID), na.rm = TRUE) # 添加虚拟geom_point层:仅用于图例显示,实际图表中不可见 # 只针对左侧的ID(A、B),设置shape=15(方块),alpha=0让点不可见 gg_dummy <- geom_point( aes(x = Date, y = Val1, color = ID), data = dfAll %>% filter(ID %in% c("A", "B")), shape = 15, size = 5, alpha = 0 ) # 调整图例设置:指定不同ID的显示样式 legguides <- guides( color = guide_legend( title.position = "top", override.aes = list( shape = c(15, 15, NA, NA), # A、B显示方块,J、K隐藏形状 linetype = c(0, 0, 1, 1), # A、B隐藏折线,J、K显示折线 fill = c("A" = "#F8766D", "B" = "#00BFC4", "J" = NA, "K" = NA) # 匹配geom_tile的填充色 ) ) ) # 生成图表:添加虚拟层,手动指定颜色确保一致性 ggplot(dfAll) + ggtiles + gglines + gg_dummy + scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = "Val2")) + coord_cartesian(ylim = ylim1) + ylab("Val1") + scale_color_manual(values = c("A" = "#F8766D", "B" = "#00BFC4", "J" = "#F8766D", "K" = "#00BFC4")) + legguides
关键说明
- 虚拟geom层的作用:通过
alpha=0让点在实际图表中不可见,但它会让ggplot识别shape属性,从而在图例中生效。 - 颜色一致性:手动指定
scale_color_manual和override.aes中的fill值,确保geom_tile的填充色和图例方块颜色一致。 - 图例样式控制:通过
override.aes分别设置不同ID的shape和linetype,实现左侧ID显示柱状方块、右侧ID显示折线的效果。
另一种思路:统一美学映射
如果不想用虚拟层,可以将geom_tile的fill和geom_line的color都映射到ID,然后合并图例:
# 修改geom_tile去掉show.legend=FALSE ggtiles <- geom_tile(aes(x = Date, y = Val1/2, height = Val1, fill = ID, group = ID), na.rm = TRUE, stat = "identity", position = position_dodge(preserve = "single")) # 合并fill和color图例 legguides <- guides( fill = guide_legend(title = "ID", title.position = "top", override.aes = list(shape = 15, linetype = 0)), color = guide_legend(title = "ID", title.position = "top", override.aes = list(shape = NA, linetype = 1)) ) # 统一颜色映射 ggplot(dfAll) + ggtiles + gglines + scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = "Val2")) + coord_cartesian(ylim = ylim1) + ylab("Val1") + scale_color_manual(values = c("A" = "#F8766D", "B" = "#00BFC4", "J" = "#F8766D", "K" = "#00BFC4")) + scale_fill_manual(values = c("A" = "#F8766D", "B" = "#00BFC4", "J" = NA, "K" = NA)) + legguides + theme(legend.position = "top")
这种方式会生成两个图例,你可以通过theme(legend.box = "horizontal")让它们并排显示,或者用guide_merge合并为一个(需要ggplot2 3.5.0及以上版本)。
内容的提问来源于stack exchange,提问作者djbetancourt
相关产品推荐
相关产品推荐

