如何使用geom_sf从坐标绘制带有多个孔的多边形?

时间:2019-03-04 22:57:25

标签: r ggplot2 sf

我的物体上有多个孔。我可以使用geom_polypathZ.Lin进行一些几何图形识别来成功绘制它们。请参阅下面的geom_polypath(aes(x = x, y = y, group = section))

我使用geom_sf绘制这些相同的对象。我不清楚使用sf对象时如何维护此几何信息。

st_cast states的文档:

  

ID   整数向量,表示应如何对几何进行分组(默认值:不分组)

这是一个线索吗?对我来说还不清楚。

字母'g'的xml文件为here

library(tidyverse)
library(transformr)
library(ggpolypath)
library(sf)

get_letter <- function(){
  letter_xml <- readRDS("tmp/letter_g")

  # Extract coordinates from Picture object
  x <- letter_xml@paths$text@letters[1]$path@x
  y <- letter_xml@paths$text@letters[1]$path@y

  one_letter <- tibble(
    x, 
    y,
    x.n = names(x),
    id = 1
  )

  one_letter <- one_letter %>%
    mutate(is.move = x.n == "move") %>%
    mutate(section = cumsum(is.move)) %>%

    group_by(section) %>%
    mutate(section.length = n()) %>%
    ungroup() %>%
    filter(section.length >= 3)

  one_letter <- select(one_letter, x, y, id, section)
}

letter_to_sf <- function(one_letter){
  one_letter_sf <- one_letter %>%
    st_as_sf(coords = c("x", "y")) %>%
    summarise(geometry = st_combine(geometry)) %>%
    st_cast(to = "POLYGON") %>% 
    st_normalize()

  df2 <- data.frame(
    id = 1,
    one_letter_sf$geometry
  )
}
one_letter <- get_letter()
one_letter_sf <- letter_to_sf(one_letter)

# Incorrect using xy df
ggplot(one_letter) +
  geom_polygon(aes( x = x, y = y))

# Correct using xy df
ggplot(one_letter) +
  geom_polypath(aes(x = x, y = y, group = section))

# Incorrect using sf
ggplot(one_letter_sf) +
  geom_sf(aes(geometry = geometry))

2 个答案:

答案 0 :(得分:2)

这是一种我认为不太笨拙的方法。我们必须放弃使用内置的st_as_sf(coords = )方法,但是鉴于我们有原始观点,我认为这样做是有必要的。我们使用st_polygon获取点矩阵列表的事实,其中第一个矩阵之后的后续矩阵是孔。因此,我们可以简单地将原始数据帧除以section(也可以使用base::split),遍历各组并强制转换为矩阵,然后将结果放入列表中,然后直接将结果传递给{{ 1}}。然后,您可以将此st_polygon几何(POLYGON)包装在sfgsfc对象中,以获取数据框样式对象,然后我们可以sf

ggplot

reprex package(v0.2.1)于2019-03-04创建

答案 1 :(得分:0)

这是我的第一种方法,尽管感觉有点笨拙。我下载了letter_g,并制作了one_letter的reprex版本,因此您可以使用它。首先要做的是通过按部分分组来获得边界和每个孔的多边形,但是要从边界多边形擦除孔有点费时费力。我在这里通过使用st_intersection并仅保留完全源自边界的结果多边形来做到这一点。我还假设section变量的编号正确,因此边界是第一组点。如果我们不知道应该将哪个边界作为边界,我也不知道如何找到合适的孔。

我不确定此方法是否比手动将点转换为st_polygon构造函数的格式更好。

library(tidyverse)
library(sf)
#> Linking to GEOS 3.7.1, GDAL 2.4.0, PROJ 5.2.0

one_letter <- tibble::tibble(
  x = c(317.422, 315.605, 310.16, 304.367, 300.527, 299.141, 299.141, 299.141, 299.797, 301.297, 301.719, 300.805, 298.199, 295.684, 294.172, 293.672, 293.672, 293.672, 294.172, 295.684, 298.199, 300.805, 301.719, 300.684, 297.75, 294.93, 293.246, 292.688, 292.688, 292.688, 294.367, 299.203, 306.891, 314.566, 317.125, 319.695, 327.41, 335.234, 340.207, 341.953, 341.953, 341.953, 340.152, 334.797, 325.941, 316.715, 313.641, 312.145, 307.656, 303.695, 301.5, 300.828, 300.828, 300.828, 301.121, 301.906, 303.047, 304.066, 304.406, 305.078, 306.82, 307.094, 308.059, 312.82, 317.008, 318.406, 320.199, 325.586, 331.316, 335.109, 336.484, 336.484, 336.484, 336.016, 334.609, 332.25, 329.828, 328.938, 328.953, 329.332, 330.355, 332.008, 333.723, 334.297, 334.863, 336.563, 338.102, 338.375, 338.004, 336.723, 336.188, 336.188, 336.188, 336.516, 337.395, 338.664, 339.793, 340.172, 340.664, 342.148, 343.793, 344.91, 345.328, 345.328, 345.328, 344.5, 342.234, 338.832, 335.664, 334.609, 333.41, 329.813, 326.332, 324.152, 323.328, 323.281, 322.734, 318.75, 317.422, 317.422, 317.719, 318.82, 322.137, 325.664, 327.996, 328.844, 328.844, 328.844, 328.023, 325.723, 322.172, 318.75, 317.609, 316.52, 313.258, 309.871, 307.672, 306.891, 306.891, 306.891, 307.727, 310.031, 313.469, 316.656, 317.719, 317.719, 317.813, 319.559, 324.809, 330.023, 333.281, 334.406, 334.406, 334.406, 333.215, 329.797, 324.387, 319.008, 317.219, 315.516, 310.41, 305.215, 301.898, 300.734, 300.734, 300.734, 301.906, 305.289, 310.66, 316.023, 317.813, 317.813),
  y = c(8101.36, 8101.36, 8100.18, 8096.9, 8091.93, 8087.22, 8085.66, 8084.56, 8081.29, 8078.09, 8077.52, 8077.23, 8075.97, 8073.87, 8071.21, 8068.79, 8067.98, 8067.23, 8064.98, 8062.39, 8060.21, 8058.79, 8058.44, 8058.05, 8056.45, 8053.89, 8050.75, 8047.95, 8047.02, 8045.46, 8040.79, 8036.11, 8033.15, 8032.13, 8032.13, 8032.13, 8033.22, 8036.35, 8041.29, 8046.18, 8047.81, 8049.44, 8054.32, 8059.05, 8061.93, 8062.91, 8062.91, 8062.91, 8063.15, 8063.99, 8065.55, 8067.38, 8067.98, 8068.39, 8069.6, 8070.93, 8071.82, 8072.16, 8072.16, 8072.16, 8071.58, 8071.45, 8071.03, 8069.53, 8068.88, 8068.88, 8068.88, 8070.09, 8073.45, 8078.52, 8083.29, 8084.88, 8085.88, 8088.91, 8092.53, 8095.71, 8097.88, 8098.47, 8099.19, 8101.34, 8103.39, 8104.62, 8105.03, 8105.03, 8105.03, 8104.52, 8103.37, 8103.05, 8102.77, 8101.41, 8100.18, 8099.77, 8099.41, 8098.35, 8097.18, 8096.39, 8096.09, 8096.09, 8096.09, 8096.54, 8097.78, 8099.61, 8101.3, 8101.86, 8102.7, 8105.23, 8107.9, 8109.66, 8110.3, 8110.3, 8110.3, 8109.68, 8107.85, 8104.8, 8101.63, 8100.56, 8100.69, 8101.36, 8101.36, 8101.36, 8094.8, 8094.8, 8094.05, 8092, 8088.89, 8085.95, 8084.97, 8084.01, 8081.13, 8078.12, 8076.14, 8075.44, 8075.44, 8075.44, 8076.13, 8078.1, 8081.17, 8084.17, 8085.17, 8086.12, 8088.97, 8092.03, 8094.06, 8094.8, 8094.8, 8094.8, 8056.27, 8056.27, 8055.66, 8053.93, 8051.15, 8048.35, 8047.42, 8046.52, 8043.83, 8041.07, 8039.3, 8038.67, 8038.67, 8038.67, 8039.27, 8041, 8043.75, 8046.5, 8047.42, 8048.34, 8051.1, 8053.89, 8055.65, 8056.27, 8056.27, 8056.27),
  id = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
  section = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L)
)

one_letter %>%
  st_as_sf(coords = c("x", "y")) %>%
  group_by(section) %>%
  summarise(do_union = FALSE) %>%
  st_cast("POLYGON") %>%
  mutate(hole = section > 1) %>%
  group_by(hole) %>%
  summarise(do_union = FALSE) %>%
  st_intersection() %>%
  filter(origins == "1") %>%
  ggplot() +
  geom_sf()

reprex package(v0.2.1)于2019-03-04创建