使用ggplot2绘制具有多个子多边形和空洞的SpatialPolygons

10
我希望在 ggplot2 中使用 sp 库中的 SpatialPolygons 函数绘制具有孔洞的图形。感谢 Stack Overflow 上其他用户的问题,我知道处理顺时针多边形时可以这样做:
http://stackoverflow.com/questions/12047643/geom-polygon-with-multiple-hole/12051278#12051278
实际上,在使用 broom::tidy(替换 ggplot2::fortify)转换 SpatialPolygons 时,孔洞多边形按顺时针方向保存以便作为孔洞绘制。
在 ggplot2 中,绘制具有孔洞的多边形需要用 fill 和 colour 分别绘制两次,否则可能会看到线穿过多边形。当处理包含多个子多边形和孔洞的情况时,这更加棘手,由 broom::tidy 定义的点特征顺序可能不允许填充多边形(见下面的图像)。您们有没有什么解决办法来解决这个填充问题?

以下是一个可复现的示例:

library(sp)
library(ggplot2)

# Create two polygons: second would be a hole inside the first
xy = cbind(
  x = c(13.4, 13.4, 13.6, 13.6, 13.4),
  y = c(48.9, 49, 49, 48.9, 48.9)
    )
hole.xy <- cbind(
  x = c(13.5, 13.5, 13.45, 13.45, 13.5),
  y = c(48.98, 48.92, 48.92, 48.98, 48.98)
  )

# Transform as SpatialPolygons with holes
xy.sp <- SpatialPolygons(list(
  Polygons(list(Polygon(xy),
                Polygon(hole.xy, hole = TRUE)), "1"),
  Polygons(list(Polygon(xy + 0.2),
                Polygon(xy + 0.35),
                Polygon(hole.xy + 0.2, hole = TRUE)), "2")
  ))

# Transform SpatialObject to be used by ggplot2
xy.sp.l <- broom::tidy(xy.sp)

ggplot(xy.sp.l) +
  geom_polygon(aes(x = long, y = lat, group = id, fill = id))

ggplot填充存在孔洞的空间多边形问题
(来源:statnmap.com)


一个解决方案将涉及分离 SpatialPolygons 函数调用中的多边形。例如,具有id = 2的两个多边形变为2a和2b。这是一种可能性,还是您正在寻找从xy.sp.l开始的解决方案? - Jeremy Voisey
3个回答

11

现在是“转换”到sf包的好时机。在ggplot中使用sf对象实际上要容易得多,这要归功于geom_sf几何图形:

library("sf")
library("rgeos")
sf_poly <- as(xy.sp, "sf")
sf::st_crs(sf_poly) <- 4326
sf_poly$id <- c(1,2)
ggplot(sf_poly) +
  geom_sf(aes(fill = as.factor(id)))

在这里输入图片描述


确实如此。您的答案以简单的方式解决了这里提出的问题。我猜这会鼓励遇到这个问题的人转移到sf...我个人一直在等待sf稳定,带有参数和函数名称。但是,这引发了我另一个问题,即能否使用sf要素绘制阴影区域多边形。我将不得不修改我的功能,以便使用sf,然后使用带有sf的leaflet。但这是另一个问题,留待以后...谢谢。 - Sébastien Rochette
我接受这个答案是为了让人们转移到 sf。但第二个答案获奖,因为这是我的问题的答案。 - Sébastien Rochette

1
这篇文章提出了一个好问题,并已经得到了很好的回答。我也认为人们应该学习如何使用 sf 对象,因为它是 R 中下一代空间数据类型。但是我想分享一下,在这种情况下,ggspatial 包中的 geom_spatial 可以是绘制 SpatialPolygons 的选项。
library(sp)
library(ggplot2)
library(ggspatial)

ggplot() +
  geom_spatial(xy.sp, aes(fill = id))
# Ignoring argument 'mapping' in geom_spatial.SpatialPolygons
# Autodetect projection: assuming lat/lon (epsg 4326)

enter image description here


1

添加线条可以显示问题的源头。蓝色的“多边形”被绘制,从下到上再到孔。

enter image description here

这段代码(并不十分优雅,抱歉)使路径在前往第三个部分之前回到第一部分的起点。
 library(dplyr)
    extra <- xy.sp.l %>%
        filter(piece != 1) %>%
        group_by(id, group) %>%
        summarise(last_pt = max(order))


for (n in 1:nrow(extra)) {
    id_ex <- as.character(extra[n,"id"])
    x <- subset(xy.sp.l, id == id_ex & piece == 1 & order == 1)
    x$order <- as.numeric(extra[n,"last_pt"]) + 0.5
    xy.sp.l <- rbind(xy.sp.l,x)
}

xy.sp.l <- xy.sp.l[order(xy.sp.l$id, xy.sp.l$order),] 

enter image description here


感谢您的回答。 回到第一个多边形的一个点似乎可以解决任何新的子多边形或多边形顺序的问题。 我想这个技巧可以用于在ggplot2中绘制的sp库的任何多边形。 - Sébastien Rochette
我认为这样做是对的,因为它避免了创建额外多边形(例如上面的三角形)的问题。 - Jeremy Voisey
我授予这个答案,因为它直接回答了我的问题。然而,为了鼓励人们转移到 sf,我接受第一个答案。 - Sébastien Rochette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接