【问题标题】:How to find which polygon a point belong to via sf如何通过sf找到一个点属于哪个多边形
【发布时间】:2017-09-13 08:51:20
【问题描述】:

我有一个sf 对象,其中包含通过.shp 文件获得的都市区的多边形信息(区域)。对于给定的纬度/经度对,我想确定它属于哪个区域。我想我可以使用sf::st_contains(),但无法以正确的格式获取纬度/经度。

【问题讨论】:

  • 我在使用sp::point.in.polygon 时找到了好运(虽然只是使用sp,而不是使用sf)。
  • 如果您提供一些示例数据会更容易为您提供帮助
  • 另外,在两个 sf 对象上使用 sf::st_join()。您可以将join 函数指定为st_within 以获取多边形中的点,它也会返回一个sf 对象。

标签: r gis sp tidyverse sf


【解决方案1】:

如果您有坐标的 data.frame (mydf),请将它们转换为 sf 对象,然后与多边形的 sf map 相交:

mydf_sf <- sf::st_as_sf(mydf, coords=c("lon","lat"), crs=4326)
int <- sf::st_intersects(mydf_sf , map)
mydf$country <- map$country_name[unlist(int)]

https://gis.stackexchange.com/a/318629/36710 有一个完整的工作示例

【讨论】:

    【解决方案2】:

    这可以“矢量化”。这是一个例子:

    library(sf)
    library(tidyverse)
    

    新加坡形状文件:

    singapore <- st_read("~/data/master-plan-2014-subzone-boundary-no-sea-shp/MP14_SUBZONE_NO_SEA_PL.shp", quiet=TRUE, stringsAsFactors=FALSE)
    singapore <- st_transform(singapore, 4326)
    

    回收中心的CSV:

    centers <- read_csv("~/data/recycl.csv")
    glimpse(centers)
    ## Observations: 407
    ## Variables: 10
    ## $ lng             <dbl> 104.0055, 103.7677, 103.7456, 103.7361, 103.8106, 103.962...
    ## $ lat             <dbl> 1.316764, 1.296245, 1.319204, 1.380412, 1.286512, 1.33355...
    ## $ inc_crc         <chr> "F8907D68D7EB64A1", "ED1F74DC805CEC8B", "F48D575631DCFECB...
    ## $ name            <chr> "RENEW (Recycling Nation's Electronic Waste)", "RENEW (Re...
    ## $ block_house_num <chr> "10", "84", "698", "3", "2", "1", "1", "1", "357", "50", ...
    ## $ bldg_name       <chr> "Changi Water Reclamation Plant", "Clementi Woods", "Comm...
    ## $ floor           <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
    ## $ post_code       <int> 498785, 126811, 608784, 689814, 159047, 486036, 39393, 55...
    ## $ street          <chr> "Changi East Close", "West Coast Road , Clementi Woods Co...
    ## $ unit            <chr> "(Lobby)", "#B1-01 (Management Office)", "(School foyer)"...
    

    把^^变成一个简单的特征对象:

    map2(centers$lng, centers$lat, ~st_point(c(.x, .y))) %>% 
      st_sfc(crs = 4326) %>% 
      st_sf(centers[,-(1:2)], .) -> centers_sf
    

    这可能比逐行操作更快,但我会让其他人享受基准测试的乐趣:

    bind_cols(
      centers,
      singapore[as.numeric(st_within(centers_sf, singapore)),]
    ) %>% 
      select(lng, lat, inc_crc, subzone_name=SUBZONE_N) %>% 
      mutate(subzone_name = str_to_title(subzone_name))
    ## # A tibble: 407 x 4
    ##         lng      lat          inc_crc               subzone_name
    ##       <dbl>    <dbl>            <chr>                      <chr>
    ##  1 104.0055 1.316764 F8907D68D7EB64A1             Changi Airport
    ##  2 103.7677 1.296245 ED1F74DC805CEC8B             Clementi Woods
    ##  3 103.7456 1.319204 F48D575631DCFECB              Teban Gardens
    ##  4 103.7361 1.380412 1F910E0086FD4798                 Peng Siang
    ##  5 103.8106 1.286512 55A0B9E7CBD34AFE             Alexandra Hill
    ##  6 103.9624 1.333555 C664D09D9CD5325F                      Xilin
    ##  7 103.8542 1.292778 411F79EAAECFE609                  City Hall
    ##  8 103.8712 1.375876 F4516742CFD4228E Serangoon North Ind Estate
    ##  9 103.8175 1.293319 B05B32DF52D922E7            Alexandra North
    ## 10 103.9199 1.335878 58E9EAF06206C772            Bedok Reservoir
    ## # ... with 397 more rows
    

    【讨论】:

      【解决方案3】:

      回复晚了,自己在找答案。

      这样结束了:

      library(sf)
      library(tidyverse)
      
      nc = st_read(system.file("shape/nc.shp", package="sf"),
                   stringsAsFactors = FALSE)
      d <-
        data_frame(lon = runif(1e3, -84.5, -75.5),
                   lat = runif(1e3,  34,  36.6),
                   somevariable = rnorm(1e3, 1000, 100))
      
      geo_inside <- function(lon, lat, map, variable) {
      
        variable <- enquo(variable)
        # slow if lots of lons and lats or big sf - needs improvement
        pt <-
          tibble::data_frame(x = lon,
                             y = lat) %>%
          st_as_sf(coords = c("x", "y"), crs = st_crs(map))
        pt %>% st_join(map) %>% pull(!!variable)
      
      }
      
      d <-
        d %>%
        mutate(county = geo_inside(lon, lat, nc, NAME))
      
      glimpse(d)
      Observations: 1,000
      Variables: 4
      $ lon          <dbl> -79.68728, -79.06104, -83.92082, -76.36866, -75.8635...
      $ lat          <dbl> 36.11349, 35.67239, 35.08802, 35.78083, 36.55786, 34...
      $ somevariable <dbl> 910.9803, 1010.6816, 919.3937, 924.0845, 1154.0975, ...
      $ county       <chr> "Guilford", "Chatham", "Cherokee", "Tyrrell", NA, NA...
      
      d %>%
        ggplot() +
        geom_sf(data = nc) +
        geom_point(aes(lon, lat, colour = county)) +
        theme(legend.position = "none")
      

      虽然对速度不满意,但似乎可以完成这项工作。

      埃纳尔

      【讨论】:

        【解决方案4】:

        在 lon/lat 上使用 st_point() 然后它可以与其他 sf 函数一起使用。

        例子:

        find_precinct <- function(precincts, point) {
          precincts %>%
            filter(st_contains(geometry, point) == 1) %>%
            `[[`("WARDS_PREC")
        }
        
        
        ggmap::geocode("nicollet mall, st paul") %>%
          rowwise() %>%
          mutate(point = c(lon, lat) %>%
                   st_point() %>%
                   list(),
                 precinct = find_precinct(msvc_precincts, point)
                 )
        

        【讨论】:

        • 以矢量化方式执行此操作的任何方式,即不是rowwise?
        猜你喜欢
        • 2017-08-30
        • 2012-06-02
        • 1970-01-01
        • 2021-07-03
        • 1970-01-01
        • 2011-12-04
        • 1970-01-01
        • 2012-01-14
        • 2020-12-03
        相关资源
        最近更新 更多