围绕栅格单元绘制轮廓线

4
使用ggplot2,我想绘制一个多边形(凸包?),以尊重栅格图的单元格边界(使用geom_raster创建)。可以使用凸包方法,但它们会通过x-y坐标而不是绕过栅格图的单元格(对不起,我的术语受到了无知的影响)。例如,给定以下具有分类属性d的x-y坐标数据:
df <- data.frame(x = c(295, 300, 305, 310, 295, 300, 305, 310),
                 y = c(310, 310, 310, 310, 315, 315, 315, 315),
                 d = c(2, 2, 2, 1, 2, 1, 1, 1))

我可以使用ggplot2的geom_raster函数将属性作为填充来绘制:
ggplot(df, aes(x, y)) +
  geom_raster(aes(fill = d)) +
  coord_fixed()

需要提供:

enter image description here

但我想要的是由d定义的类别的轮廓线。大致如下所示:

enter image description here

我是否可以使用基本的R和ggplot2来实现这一点,或者使用raster包或其他网格/栅格/GIS包来完成?我希望尽可能简单。

2个回答

5

你可以使用R的空间功能来获取这些多边形。以下是一种方法:

library(raster)

## Convert your data.frame to a raster object
r <- rasterFromXYZ(df)

## Extract polygons
pp <- rasterToPolygons(r, dissolve=TRUE)

## Convert SpatialPolygons to a format usable by ggplot2
outline <- fortify(pp)

## Put it all together:
ggplot(df, aes(x, y)) +
    geom_raster(aes(fill = d)) +
    coord_fixed() +
    geom_path(aes(x = long, y = lat, group = group), data = outline, 
              size=1.5, col="gold")

enter image description here


这个方法可以工作,但对我来说只是部分解决了问题。有没有办法在ggplot2中将多边形对象用作图层?也许可以使用另一个光栅包转换程序? - Alex Trueman
1
@AlexT 试试这样做,比如执行 obj <- fortify(pp),然后将其附加到你的示例中的 ggplot() 调用中:geom_path(aes(x = long, y = lat, group = group), data = obj)。它可以工作,尽管我猜这不是 ggplot2 用户通常的做法... - Josh O'Brien
这很好用。我似乎需要加载maptools包才能让fortify工作。我可以将整个转换组合在一个dplyr字符串中,这使得它既漂亮又易读:outline <- df %>% rasterFromXYZ() %>% rasterToPolygons(dissolve = TRUE) %>% fortify(region = "d") - Alex Trueman
感谢您更新答案并添加了“fortify”步骤。 - Alex Trueman

3

很遗憾,{ggplot2}的fortify()不再是该软件包作者推荐的。建议替代方案是{broom}包的tidy(),但同样也不再由这些软件包作者推荐!

幸运的是,我们可以使用{sf}包重新创建Josh O'Brien的答案。我们仍然依赖于{raster}包中的一些函数,但是这些可能可以用{stars}包替换,一旦假设中的错误得到修复(请参见https://github.com/r-spatial/sf/issues/1389)。如果您的光栅非常大,则使用{stars}可能更有优势,因为将光栅(或数据框)转换为连续的多边形可能非常缓慢(请参见https://gis.stackexchange.com/a/313550/114075)。

以下是代码(借鉴了Josh O'Brien的设置):

library(raster)
library(rgeos)
library(ggplot2)
library(sf)

df <- data.frame(x = c(295, 300, 305, 310, 295, 300, 305, 310),
                 y = c(310, 310, 310, 310, 315, 315, 315, 315),
                 d = c(2, 2, 2, 1, 2, 1, 1, 1))

## Convert your data.frame to a raster object
r <- raster::rasterFromXYZ(df)

## Extract polygons
pp <- raster::rasterToPolygons(r, dissolve = TRUE)

## Convert SpatialPolygons to a format usable by ggplot2
outline <- sf::st_as_sf(pp)

## Put it all together:
## The polygon "outline" is filled by default so will cover up the
## raster values. Use fill = NA for the geom_sf() to just use the
## gold border color. 
ggplot(df) +
  geom_raster(aes(x = x, y = y, fill = d)) +
  geom_sf(data = outline, size = 1.5, col = "gold", fill = NA)

或者将 sf 对象转换为 LINESTRING,那么在调用 geom_sf() 时就不需要使用 fill = NA 参数:

library(raster)
library(rgeos)
library(ggplot2)
library(sf)

df <- data.frame(x = c(295, 300, 305, 310, 295, 300, 305, 310),
                 y = c(310, 310, 310, 310, 315, 315, 315, 315),
                 d = c(2, 2, 2, 1, 2, 1, 1, 1))

## Convert your data.frame to a raster object
r <- raster::rasterFromXYZ(df)

## Extract polygons
pp <- raster::rasterToPolygons(r, dissolve = TRUE)

## Or you can cast to a linestring instead of using a polygon
## and then having to use the fill = NA argument in the 
## geom_sf() call
outline <- sf::st_as_sf(pp) %>% st_cast("LINESTRING")

ggplot(df) +
  geom_raster(aes(x = x, y = y, fill = d)) +
  geom_sf(data = outline, size = 1.5, col = "gold")

enter image description here


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