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

多geom_sf数据集绘制ggplot时图例颜色不匹配问题排查

问题:ggplot绘制多SF线图层时颜色与图例不匹配

使用ggplot绘制两个简单要素(sf)线数据集的地图,希望线能共用一个图例,但当前代码导致绘图颜色与图例颜色不匹配——图例中A、B、D对应指定调色板颜色,C为黑色,但绘图中D和C的颜色被错误交换。将df2的id改为"X"时显示正常。

复现代码:

library("sf")
library("sfheaders")
library("ggplot2")

df1 <- data.frame(
  x = c(0,1,0,1,0,1), 
  y = c(1,1,2,2,3,3),
  id = c("A","A","B","B","D","D")
)
df2 <- data.frame(
  x = c(0,1), 
  y = c(4,4),
  id= c("C","C")
)

set1_sf <- sfheaders::sf_linestring(
  obj = df1, x = "x", y = "y", linestring_id = "id"
)
set2_sf <- sfheaders::sf_linestring(
  obj = df2, x = "x", y = "y", linestring_id = "id"
)

palette <- c("#7FC97F","#BEAED4","#FDC086")   

ggplot() +
  geom_sf(set1_sf, mapping=aes(colour=id), lwd=0.8) + 
  geom_sf(set2_sf, mapping=aes(colour=id), lwd=0.8) +
  scale_colour_manual(name="Lines",
                      values = c(palette,"black"),
                      labels = c(set1_sf$id, set2_sf$id))

错误原因

ggplot处理分类颜色映射时,是按照因子的水平顺序来匹配scale_colour_manual中的values,而非图层加载顺序或labels的顺序。

在你的代码中:

  • 两个数据集的id合并后,默认因子水平按字母排序为:A, B, C, D
  • 你在values中指定的顺序是palette(A、B、D的颜色) + black,即#7FC97F, #BEAED4, #FDC086, black,对应逻辑顺序是A,B,D,C
  • labels的顺序是A,B,D,C,但实际因子水平顺序是A,B,C,D,导致:
    • 因子C匹配到values的第3个值(原本给D的#FDC086)
    • 因子D匹配到values的第4个值(原本给C的black)
      因此出现颜色交换问题。当id改为"X"时,字母排序后X在最后,与你指定的顺序一致,所以显示正常。

解决方法

方法1:合并两个SF数据集(推荐)

将两个sf对象合并为一个,只需一次geom_sf调用,颜色映射会自动按统一因子水平处理,避免顺序混乱:

# 合并数据集
combined_sf <- rbind(set1_sf, set2_sf)

# 手动指定因子水平(可选,确保图例顺序符合预期)
combined_sf$id <- factor(combined_sf$id, levels = c("A", "B", "D", "C"))

ggplot(combined_sf) +
  geom_sf(aes(colour = id), lwd = 0.8) +
  scale_colour_manual(
    name = "Lines",
    values = c(A = "#7FC97F", B = "#BEAED4", D = "#FDC086", C = "black"),
    labels = c("A", "B", "D", "C")
  )

方法2:用命名向量指定颜色映射

不合并数据集,在scale_colour_manual的values中直接用命名向量绑定每个id与对应颜色,无视因子顺序也能正确匹配:

ggplot() +
  geom_sf(set1_sf, mapping = aes(colour = id), lwd = 0.8) + 
  geom_sf(set2_sf, mapping = aes(colour = id), lwd = 0.8) +
  scale_colour_manual(
    name = "Lines",
    values = c(A = palette[1], B = palette[2], D = palette[3], C = "black"),
    labels = c("A", "B", "D", "C")
  )

方法3:统一两个数据集的因子水平

如果坚持分开绘制图层,可先统一两个数据集的因子水平,确保顺序一致:

# 收集所有id并指定顺序
all_ids <- c(set1_sf$id, set2_sf$id)
set1_sf$id <- factor(set1_sf$id, levels = all_ids)
set2_sf$id <- factor(set2_sf$id, levels = all_ids)

ggplot() +
  geom_sf(set1_sf, mapping = aes(colour = id), lwd = 0.8) + 
  geom_sf(set2_sf, mapping = aes(colour = id), lwd = 0.8) +
  scale_colour_manual(
    name = "Lines",
    values = c(palette, "black"),
    labels = all_ids
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:32:03