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
相关产品推荐
相关产品推荐

