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

ggplot2图表异常:图例显示但绘图无颜色/有颜色但无图例

问题描述

我正在开发带双Y轴和图例的多变量ggplot2图表,参考相关解决方案后,目前得到两个版本的图表:

  • 一个版本图例正常显示且颜色正确,但绘图元素没有颜色
  • 另一个版本绘图元素有颜色,但图例不显示

我知道这和geom_point()中colour参数的位置有关,参考之前的回答:

colour= XYZ 应该放在 aes() 内部,而不是外部
geom_point(aes(data, colour=XYZ)) #------>显示图例
geom_point(aes(data),colour=XYZ) #------>不显示图例

数据集片段如下:

h1enraw <-structure(list(run = c(1738, 1739, 1740, 1741, 1742, 1743),
                         temp = c(19, 19, 19, 19, 21, 22),
                         avgbase = c(1386, 1386, 1389, 1389, 1352, 1336),
                         no2c = c(6.98, 6.96, 6.94, 6.99, 7.01, 7.01),
                         no3c = c(18.52, 17.6, 18.77, 19.81, 18.22, 18.60)), 
                    row.names = c(NA, 6L), class = "data.frame")

我理解为什么一个版本有图例另一个没有,但不清楚这个设置为何会影响绘图元素的颜色显示,恳请指点方向。

图例显示但绘图无颜色的代码

# 选择第二Y轴的缩放系数
scaleRight <- 40
ymax <-43

h1no2<-ggplot(h1enraw, aes(x=run)) +
  geom_path(aes(y=temp, group=1,colour="cornflowerblue"), size=0.9) +
  geom_point(aes(y=no2c, group=1,colour="red")) +
  geom_point(aes(y=no3c, group=1,colour="darkgreen")) +
  geom_line(aes(y=avgbase/scaleRight, group=1,colour="chocolate1"), size=0.9) +
  scale_y_continuous(breaks=seq(0,40,2), expand = expansion(mult = c(0,.05)),
                     sec.axis = sec_axis(~.*scaleRight, name = "Average Baseline (Transmitance Units)")) +
  coord_cartesian(ylim = c(0, ymax)) +
  theme_classic() +
  labs( y="Temperature (°C) / Concentration (ppm)", x="Run", title = "H1 - High Temperature Cycle") +
  theme(text = element_text(size=9),
        axis.text.x = element_text(angle=90, vjust=0.6),
        axis.text=element_text(size=12),
        axis.title=element_text(size=14,face="bold"),
        panel.border = element_rect(colour = "chocolate1", fill=NA, size=0.5),
        legend.position = "bottom", legend.title=element_text(size=10), legend.text = element_text(size=8),
        axis.title.y = element_text(size=10),
        plot.title = element_text(size=14, face="bold")) +
  theme(legend.title=element_blank()) + 
  scale_fill_manual(breaks=c("temp","no2c","no3c","avgbase"),
                    labels=c("Temperature", "NO2", "NO3", "Avg Baseline"),
                    values = c("temp"="cornflowerblue", "no2c"="red",
                               "no3c"="darkgreen", "avgbase"="chocolate1")) + 
  scale_color_manual(labels = c("Temperature", expression(NO[2]), expression(NO[3]), "Avg Baseline"),
                     values = c("temp"="cornflowerblue", "no2c"="red",
                                "no3c"="darkgreen", "avgbase"="chocolate1"),
                     breaks=c("temp","no2c","no3c","avgbase"))

(对应图表:图例显示但绘图元素无颜色)

绘图有颜色但无图例的代码

# 选择第二Y轴的缩放系数
scaleRight <- 40
ymax <-43

h2no2<-ggplot(h2enraw, aes(x=run)) +
  geom_path(aes(y=temp, group=1), colour="cornflowerblue", size=0.9) +
  geom_point(aes(y=no2c, group=1 ),colour="red") +
  geom_point(aes(y=no3c, group=1 ),colour="darkgreen") +
  geom_line(aes(y=avgbase/scaleRight, group=1 ),colour="chocolate1", size=0.9) +
  scale_y_continuous(breaks=seq(0,40,2), expand = expansion(mult = c(0,.05)),
                     sec.axis = sec_axis(~.*scaleRight, name = "Average Baseline (Transmitance Units)")) +
  coord_cartesian(ylim = c(0, ymax)) +
  theme_classic() +
  labs( y="Temperature (°C) / Concentration (ppm)", x="Run", title = "H2 - High Temperature Cycle") +
  theme(text = element_text(size=9),
        axis.text.x = element_text(angle=90, vjust=0.6),
        axis.text=element_text(size=12),
        axis.title=element_text(size=14,face="bold"),
        panel.border = element_rect(colour = "chocolate1", fill=NA, size=0.5),
        legend.position = "bottom", legend.title=element_text(size=10), legend.text = element_text(size=8),
        axis.title.y = element_text(size=10),
        plot.title = element_text(size=14, face="bold")) +
  scale_fill_manual(name="Legend",
                    breaks=c("temp","no2c","no3c","avgbase"),
                    labels=c("Temperature", "NO2", "NO3", "Avg Baseline"))

(对应图表:绘图元素有颜色但无图例)


问题解析与解决方案

为什么第一个版本绘图无颜色但图例正常?

当把colour="cornflowerblue"这类颜色值放在aes()内部时,ggplot2会将这些字符串视为分类变量的水平值,而非直接作为颜色代码。此时绘图元素的颜色由后续scale_color_manual决定,但scale_color_manual的breaks是"temp"、"no2c"这类变量名,和aes(colour=...)中传入的颜色字符串完全不匹配,导致ggplot找不到对应颜色映射,只能用默认灰色显示绘图元素。

图例能正常显示,是因为scale_color_manual定义了完整的标签和颜色映射,只是该映射与aes()内的颜色字符串无关联。

为什么第二个版本绘图有颜色但无图例?

当把colour="cornflowerblue"放在aes()外部时,这是直接给绘图元素设置固定颜色,不属于ggplot的“美学映射”范畴。ggplot仅当美学属性(如colour、fill)在aes()内部时,才会生成对应图例——外部设置的固定样式不会触发图例生成,因此看不到图例。

正确的解决方案:规范美学映射

要同时实现绘图元素有颜色+图例正常显示,需将colour映射到变量标识(而非直接写颜色值),再通过scale_color_manual绑定颜色:

方案1:整理为长数据(推荐,符合ggplot规范)

library(tidyr)
scaleRight <- 40
ymax <-43

# 转换为长格式数据
h1enraw_long <- h1enraw %>%
  mutate(avgbase_scaled = avgbase / scaleRight) %>%
  pivot_longer(cols = c(temp, no2c, no3c, avgbase_scaled),
               names_to = "variable",
               values_to = "value")

# 绘图
ggplot(h1enraw_long, aes(x=run, y=value, colour=variable)) +
  # 根据变量类型选择几何对象
  geom_line(data = subset(h1enraw_long, variable %in% c("temp", "avgbase_scaled")), size=0.9) +
  geom_point(data = subset(h1enraw_long, variable %in% c("no2c", "no3c"))) +
  scale_y_continuous(breaks=seq(0,40,2), expand = expansion(mult = c(0,.05)),
                     sec.axis = sec_axis(~.*scaleRight, name = "Average Baseline (Transmitance Units)")) +
  coord_cartesian(ylim = c(0, ymax)) +
  theme_classic() +
  labs(y="Temperature (°C) / Concentration (ppm)", x="Run", title = "H1 - High Temperature Cycle", colour="") +
  theme(text = element_text(size=9),
        axis.text.x = element_text(angle=90, vjust=0.6),
        axis.text=element_text(size=12),
        axis.title=element_text(size=14,face="bold"),
        panel.border = element_rect(colour = "chocolate1", fill=NA, size=0.5),
        legend.position = "bottom", legend.text = element_text(size=8),
        axis.title.y = element_text(size=10),
        plot.title = element_text(size=14, face="bold")) +
  scale_color_manual(labels = c("Temperature", expression(NO[2]), expression(NO[3]), "Avg Baseline"),
                     values = c("temp"="cornflowerblue", "no2c"="red",
                                "no3c"="darkgreen", "avgbase_scaled"="chocolate1"))

方案2:不整理数据,直接映射变量名

scaleRight <- 40
ymax <-43

ggplot(h1enraw, aes(x=run)) +
  geom_path(aes(y=temp, colour="temp"), size=0.9) +
  geom_point(aes(y=no2c, colour="no2c")) +
  geom_point(aes(y=no3c, colour="no3c")) +
  geom_line(aes(y=avgbase/scaleRight, colour="avgbase"), size=0.9) +
  scale_color_manual(labels = c("Temperature", expression(NO[2]), expression(NO[3]), "Avg Baseline"),
                     values = c("temp"="cornflowerblue", "no2c"="red",
                                "no3c"="darkgreen", "avgbase"="chocolate1"),
                     breaks=c("temp","no2c","no3c","avgbase")) +
  scale_y_continuous(breaks=seq(0,40,2), expand = expansion(mult = c(0,.05)),
                     sec.axis = sec_axis(~.*scaleRight, name = "Average Baseline (Transmitance Units)")) +
  coord_cartesian(ylim = c(0, ymax)) +
  theme_classic() +
  labs( y="Temperature (°C) / Concentration (ppm)", x="Run", title = "H1 - High Temperature Cycle", colour="") +
  theme(text = element_text(size=9),
        axis.text.x = element_text(angle=90, vjust=0.6),
        axis.text=element_text(size=12),
        axis.title=element_text(size=14,face="bold"),
        panel.border = element_rect(colour = "chocolate1", fill=NA, size=0.5),
        legend.position = "bottom", legend.text = element_text(size=8),
        axis.title.y = element_text(size=10),
        plot.title = element_text(size=14, face="bold"))

修改后,aes(colour="temp")中的"temp"作为分类键,与scale_color_manual的breaks对应,ggplot就能正确将颜色映射到绘图元素,同时生成对应图例。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:48:25