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

如何为geom_sf绘制的MultiPolygon添加完整图例(支持图层缺失)

问题:为缺失部分图层的GeoJSON数据绘制带完整图例的地图

我从GeoJSON文件读取了MultiPolygon数据:

geojson <- read_sf(filename)

数据如下:

Simple feature collection with 4 features and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -16.64523 ymin: 27.23105 xmax: 39.81916 ymax: 65.99652
Geodetic CRS:  WGS 84
# A tibble: 4 × 2
  id                                                                    geometry
  <chr>                                                       <MULTIPOLYGON [°]>
1 Coverage           (((-7.599085 33.35191, -7.813386 33.43519, -7.728468 33.51…
2 HighInterference   (((30.60789 42.13764, 30.638 42.22092, 30.75046 42.22092, …
3 LowInterference    (((24.75786 59.54255, 24.80001 59.62583, 24.96471 59.62583…
4 MediumInterference (((26.36263 58.87633, 26.40755 58.95961, 26.56905 58.95961…

随后我使用geom_sf为每一行数据设置对应颜色绘制:

library("ggplot2")
library("sf")
library("rnaturalearth")
library("rnaturalearthdata")
library("ggspatial")
library("geojsonR")

europe <- ne_countries(scale = "medium", returnclass = "sf")
class(europe)

filename <- "geojson.geojson"

geojson <- read_sf(filename)

p <- ggplot() + geom_sf(data = europe)
p <- p + geom_sf(data = geojson[geojson$id == "Coverage", ], color = alpha("green", 0.1), fill = alpha("green", 0.1))
p <- p + geom_sf(data = geojson[geojson$id == "LowInterference", ], color = alpha("yellow", 0.5), fill = alpha("yellow", 0.5))
p <- p + geom_sf(data = geojson[geojson$id == "MediumInterference", ], color = alpha("orange", 0.5), fill = alpha("orange", 0.5))
p <- p + geom_sf(data = geojson[geojson$id == "HighInterference", ], color = alpha("red", 0.5), fill = alpha("red", 0.5))
p <- p + coord_sf(xlim = c(-20, 42), ylim = c(33, 72))
plot(p)

ggsave(paste(filename, ".pdf", sep = ""))
ggsave(paste(filename, ".png", sep = ""))

现在需要给地图添加图例,但GeoJSON文件中并非总是包含所有图层(示例是完整的,但可能缺失任意一个或多个),要求图例始终显示所有可能的取值,不知道该怎么实现。


GeoJSON示例

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                0,
                                40
                            ],
                            [
                                10,
                                50
                            ],
                            [
                                0,
                                60
                            ],
                            [
                                -10,
                                55
                            ],
                            [
                                0,
                                40
                            ]
                        ]
                    ]
                ]
            },
            "id": "Coverage"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                20,
                                45
                            ],
                            [
                                25,
                                50
                            ],
                            [
                                20,
                                60
                            ],
                            [
                                0,
                                50
                            ],
                            [
                                20,
                                45
                            ]
                        ]
                    ]
                ]
            },
            "id": "HighInterference"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                10,
                                35
                            ],
                            [
                                20,
                                35
                            ],
                            [
                                20,
                                40
                            ],
                            [
                                10,
                                40
                            ],
                            [
                                10,
                                35
                            ]
                        ]
                    ]
                ]
            },
            "id": "LowInterference"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                30,
                                50
                            ],
                            [
                                40,
                                50
                            ],
                            [
                                40,
                                60
                            ],
                            [
                                30,
                                60
                            ],
                            [
                                30,
                                50
                            ]
                        ]
                    ]
                ]
            },
            "id": "MediumInterference"
        }
    ]
}

解决方案

要实现图例始终显示所有可能取值,通过因子化类别+手动颜色映射即可完成,具体代码和要点如下:

完整修改代码

library("ggplot2")
library("sf")
library("rnaturalearth")
library("rnaturalearthdata")

# 1. 定义所有可能的类别和对应颜色(含透明度)
all_categories <- c("Coverage", "LowInterference", "MediumInterference", "HighInterference")
color_map <- c(
  "Coverage" = alpha("green", 0.1),
  "LowInterference" = alpha("yellow", 0.5),
  "MediumInterference" = alpha("orange", 0.5),
  "HighInterference" = alpha("red", 0.5)
)

# 读取数据
europe <- ne_countries(scale = "medium", returnclass = "sf")
filename <- "geojson.geojson"
geojson <- read_sf(filename)

# 2. 将id转换为包含所有类别的因子,缺失类别会保留在图例中
geojson$id <- factor(geojson$id, levels = all_categories)

# 3. 绘制地图,通过id映射颜色
p <- ggplot() +
  geom_sf(data = europe) +
  geom_sf(data = geojson, aes(color = id, fill = id)) +
  # 手动设置颜色,drop=FALSE强制保留所有类别
  scale_color_manual(values = color_map, drop = FALSE) +
  scale_fill_manual(values = color_map, drop = FALSE) +
  coord_sf(xlim = c(-20, 42), ylim = c(33, 72)) +
  labs(color = "类型", fill = "类型") # 自定义图例标题

plot(p)

ggsave(paste(filename, ".pdf", sep = ""))
ggsave(paste(filename, ".png", sep = ""))

核心要点

  • 因子化类别:把id转为包含所有可能值的因子,确保缺失的类别不会被自动剔除。
  • 统一映射颜色:用aes(color = id, fill = id)替代多次调用geom_sf,代码更简洁且自动关联图例。
  • 保留所有图例项:scale_*_manual中设置drop = FALSE,强制显示所有预定义的类别,哪怕对应数据不存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:40:58