图中最外层 Voronoi 多边形的透明或均匀颜色

p-r*_*bot 1 voronoi r ggplot2 r-sf

我正在尝试删除 Voronoi 图中的外部多边形。主要情节是这样的:

require(ggplot2)
require(ggvoronoi)
set.seed(2023)

N <- 80
x <- runif(N)
y <- runif(N)
df <- data.frame(x, y)
df$dist <- rnorm(N)

ggplot(df, aes(x, y, fill = dist)) +
    geom_voronoi() +
    stat_voronoi(geom = "path") +
    theme_void()
Run Code Online (Sandbox Code Playgroud)

主图

如果我对轴设置限制,就会发生接近我想要的情况。然而,仍然填充了一些外部多边形:

ggplot(df, aes(x, y, fill = dist)) +
    geom_voronoi() +
    stat_voronoi(geom = "path") +
    theme_void() + 
    xlim(0.1, 0.9) + 
    ylim(0.1, 0.9)
Run Code Online (Sandbox Code Playgroud)

[有限图片

隔离/识别图形边缘周围最外层的多边形并使它们透明或统一颜色的最佳方法是什么?

mar*_*usl 7

{sf}基于 的方法(GEOS 的实现st_voronoi)可能看起来像这样:

library(sf)
#> Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
library(ggplot2)
set.seed(2023)

N <- 80
x <- runif(N)
y <- runif(N)
df <- data.frame(x, y)
df$dist <- rnorm(N)

# to sf object
points_sf <- st_as_sf(df, coords = c("x", "y"))
# for st_voronoi we need to go though st_union to create a MULTIPOINT, 
# as `dist` will be lost, we'll do a spatial join as a final step
# to add that attribute back;
# st_voronoi returns GEOMETRYCOLLECTION, 
# st_collection_extract() to extract POLYGONs and st_sf() to convert sfc to sf
voronoi_sf <- 
  points_sf |>
  st_union() |>
  st_voronoi() |>
  st_collection_extract() |>
  st_sf(geometry = _) |>
  st_join(points_sf) |> 
  # crop to the extent of points_sf to align with other implementations
  st_crop(points_sf)
#> Warning: attribute variables are assumed to be spatially constant throughout
#> all geometries

# boundary polygon (currently matches points_sf bbox)
boundary_sf <- st_union(voronoi_sf) |> st_boundary()

# use st_filter with st_disjoint predicate to keep only polygons that 
# have no common points with the boundary of union:
st_filter(voronoi_sf, boundary_sf, .predicate = st_disjoint) |>
  ggplot(aes(fill = dist)) +
  geom_sf() +
  theme_void()
Run Code Online (Sandbox Code Playgroud)

# or flag outer polygons with st_disjoint(), 
# sparse = FALSE: returns dense logical matrix instead of sparse index list
# [,1]: selects 1st matrix column
voronoi_sf$inner <- st_disjoint(voronoi_sf, boundary_sf, sparse = FALSE)[,1]

voronoi_sf
#> Simple feature collection with 80 features and 2 fields
#> Geometry type: POLYGON
#> Dimension:     XY
#> Bounding box:  xmin: 0.03039173 ymin: 0.01943989 xmax: 0.9992733 ymax: 0.9911794
#> CRS:           NA
#> First 10 features:
#>          dist                       geometry inner
#> 1   0.1413685 POLYGON ((0.089608 0.837129... FALSE
#> 2   0.9269828 POLYGON ((0.09466375 0.6231... FALSE
#> 3   0.1516984 POLYGON ((0.05469083 0.3648... FALSE
#> 4   0.3005414 POLYGON ((0.05469083 0.3648...  TRUE
#> 5  -0.1206981 POLYGON ((0.08540603 0.4952... FALSE
#> 6   1.3876944 POLYGON ((0.1273276 0.32198... FALSE
#> 7   2.7046756 POLYGON ((0.2191197 0.09137... FALSE
#> 8   0.2651664 POLYGON ((0.6434843 0.04838... FALSE
#> 9   0.9245641 POLYGON ((0.04950097 0.1988... FALSE
#> 10 -0.3157660 POLYGON ((0.1273276 0.32198...  TRUE
ggplot() +
  geom_sf(data = voronoi_sf, aes(fill = ifelse(inner, dist, NA)), color = "grey10") +
  geom_sf(data = points_sf,  aes(fill = dist), size = 2, show.legend = FALSE, shape = 21) +
  scale_fill_continuous(na.value = "grey80", name = "dist") +
  theme_void()
Run Code Online (Sandbox Code Playgroud)


添加st_crop(points_sf)用于处理大于最佳信封大小的st_voronoi();这可能应该根据实际的数据集和应用程序重新考虑。
第一次修订 - https://stackoverflow.com/revisions/77569621/1

  • `st_filter` (和 `st_join`)默认使用 `st_intersects` 谓词,但还有一组其他谓词使空间过滤和连接变得超级通用,即覆盖、距离内、接触、交叉等。 - https: //r-spatial.github.io/sf/reference/geos_binary_pred.html 。对于 `.predicate = st_disjoint`,`st_filter` 的读法如下:仅返回 x 中与特征 y 没有共同点的那些特征。 (2认同)

ste*_*fan 5

不幸的是我无法安装ggvoronoi。但这里有一种方法ggforce::geom_tile_voronoi,也许也适用于ggvoronoi. 这种方法有点老套,因为我只是从图层中提取数据geom_tile_voronoi,然后过滤接触边界的多边形,然后使用 ageom_polygon绘制没有外部多边形的过滤后的数据:

library(ggplot2)
library(ggforce)
library(dplyr, warn=FALSE)

set.seed(2023)

N <- 80
x <- runif(N)
y <- runif(N)
df <- data.frame(x, y)
df$dist <- rnorm(N)

p <- ggplot(df, aes(x, y, fill = dist)) +
  geom_voronoi_tile() +
  theme_void()

dat <- layer_data(p, i = 1)

outer <- dat |>
  filter(x %in% range(x) | y %in% range(y)) |>
  distinct(group) |>
  pull(group)

dat |>
  filter(!group %in% outer) |>
  ggplot(aes(x, y, fill = fill)) +
  geom_voronoi_tile(
    data = df,
    aes(x, y),
    fill = "white", color = "black"
  ) +
  geom_polygon(aes(group = group), color = "black") +
  scale_fill_identity() +
  theme_void()
Run Code Online (Sandbox Code Playgroud)


dat |>
  filter(!group %in% outer) |>
  ggplot(aes(x, y, fill = fill)) +
  geom_polygon(aes(group = group), color = "black") +
  scale_fill_identity() +
  theme_void()
Run Code Online (Sandbox Code Playgroud)