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

ggplot中如何关联颜色与形状并显示彩色图例?

问题解决方法

你的核心问题有两个:一是颜色没有映射到ggplot的美学映射(aes)中,而是直接在geom层外手动设置,导致图例无法关联颜色;二是误用了scale_fill_manual(点和线的颜色用的是color属性,不是fill)。另外,当前宽格式的写法重复代码太多,建议转成长格式(tidy数据)来简化代码,同时彻底解决图例问题。

方案1:转长格式(推荐,代码更简洁易维护)

步骤1:将宽数据转换为长格式

先用tidyr::pivot_longer把多列y值合并为分组列和数值列,让数据符合ggplot的tidy格式要求:

library(tidyr)
library(dplyr)

long_data <- combined_data %>%
  pivot_longer(
    cols = starts_with(c("anhydrate", "dihydrate")),
    names_to = "sample",
    values_to = "sticking_mass"
  ) %>%
  mutate(sample = case_when(
    sample == "anhydrate_100" ~ "CBZ Anhydrate 100 MPa",
    sample == "anhydrate_250" ~ "CBZ Anhydrate 250 MPa",
    sample == "dihydrate_100" ~ "CBZ Dihydrate 100 MPa",
    sample == "dihydrate_250" ~ "CBZ Dihydrate 250 MPa"
  ))

步骤2:重构ggplot代码

现在用长数据绘图,把color、shape、linetype都映射到分组变量,让图例自动关联所有属性:

ggplot(long_data, aes(x = number_of_compactions, y = sticking_mass)) +
  geom_line(aes(color = sample, linetype = sample), size = 1) +
  geom_point(aes(color = sample, shape = sample), size = 4) +
  labs(x = "Number of Compactions", y = TeX("\\textbf{Sticking Mass (\\textbf{$\\mu}g)}")) +
  scale_x_continuous(breaks = seq(0, 100, by = 10),
                     expand = c(0,0),
                     limits = c(0, 105)) +
  scale_y_continuous(breaks = seq(0, 160, by = 20),
                     expand = c(0,0),
                     limits = c(0, 150)) +
  # 手动设置形状
  scale_shape_manual(values = c(1, 16, 2, 17)) +
  # 手动设置颜色(对应分组顺序)
  scale_color_manual(values = c("red", "blue", "purple", "black")) +
  # 手动设置线型:100MPa用虚线,250MPa用实线
  scale_linetype_manual(values = c(5, 1, 5, 1)) +
  theme(panel.background = element_rect(fill = NA), 
        panel.border = element_rect(fill = NA, colour = "black", size = 1.2),
        axis.text.y = element_text(color = "black", size = 12, face = "bold"),
        axis.text.x = element_text(colour = "black", size = 12, face = "bold"),
        axis.title.x = element_text(size = 18, face = "bold"),
        axis.title.y = element_text(size = 18),
        legend.title = element_blank(),
        legend.background = element_rect(fill = NA),
        legend.box.background = element_rect(fill = NA),
        legend.key = element_rect(fill = NA),
        legend.position = "top")

方案2:不转换数据(临时解决,代码冗余)

如果不想修改数据结构,只需把每个geom的color参数移到aes内部,同时替换scale_fill_manual为scale_color_manual:

ggplot() +
  geom_line(data = combined_data, aes(x = number_of_compactions, y = anhydrate_100, color = "CBZ Anhydrate 100 MPa"),
            linetype = 5, size = 1) +
  geom_point(data = combined_data, aes(x = number_of_compactions, y = anhydrate_100,
                                       shape = "CBZ Anhydrate 100 MPa", color = "CBZ Anhydrate 100 MPa"), 
             size = 4) +
  geom_line(data = combined_data, aes(x = number_of_compactions, y = anhydrate_250, color = "CBZ Anhydrate 250 MPa"),
            size = 1) + 
  geom_point(data = combined_data, aes(x = number_of_compactions, y = anhydrate_250,
                                       shape = "CBZ Anhydrate 250 MPa", color = "CBZ Anhydrate 250 MPa"), 
             size = 4) +
  geom_line(data = combined_data, aes(x = number_of_compactions, y = dihydrate_100, color = "CBZ Dihydrate 100 MPa"),
            linetype = 5, size = 1) +
  geom_point(data = combined_data, aes(x = number_of_compactions, y = dihydrate_100,
                                       shape = "CBZ Dihydrate 100 MPa", color = "CBZ Dihydrate 100 MPa"), 
             size = 4) +
  geom_line(data = combined_data, aes(x = number_of_compactions, y = dihydrate_250, color = "CBZ Dihydrate 250 MPa"),
            size = 1) +
  geom_point(data = combined_data, aes(x = number_of_compactions, y = dihydrate_250,
                                       shape = "CBZ Dihydrate 250 MPa", color = "CBZ Dihydrate 250 MPa"), 
             size = 4) +
  labs(x = "Number of Compactions", y = TeX("\\textbf{Sticking Mass (\\textbf{$\\mu}g)}")) +
  scale_x_continuous(breaks = seq(0, 100, by = 10),
                     expand = c(0,0),
                     limits = c(0, 105)) +
  scale_y_continuous(breaks = seq(0, 160, by = 20),
                     expand = c(0,0),
                     limits = c(0, 150)) +
  scale_shape_manual(values = c(1, 16, 2, 17),
                     labels = c("CBZ Anhydrate 100 MPa", "CBZ Anhydrate 250 MPa",
                                "CBZ Dihydrate 100 MPa", "CBZ Dihydrate 250 MPa")) +
  scale_color_manual(values = c("red", "blue", "purple", "black"),
                    labels = c("CBZ Anhydrate 100 MPa", "CBZ Anhydrate 250 MPa",
                               "CBZ Dihydrate 100 MPa", "CBZ Dihydrate 250 MPa")) +
  theme(panel.background = element_rect(fill = NA), 
        panel.border = element_rect(fill = NA, colour = "black", size = 1.2),
        axis.text.y = element_text(color = "black", size = 12, face = "bold"),
        axis.text.x = element_text(colour = "black", size = 12, face = "bold"),
        axis.title.x = element_text(size = 18, face = "bold"),
        axis.title.y = element_text(size = 18),
        legend.title = element_blank(),
        legend.background = element_rect(fill = NA),
        legend.box.background = element_rect(fill = NA),
        legend.key = element_rect(fill = NA),
        legend.position = "top")

关键修改说明

  • 必须把color放到aes内部,让ggplot识别颜色与分组的关联,图例才能显示对应颜色
  • 用scale_color_manual替代scale_fill_manual,因为点和线的颜色属性是color,fill仅用于填充类图形(如柱状图、实心点填充)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:05:03