r - Convert output from sf::st_within to vector

前端 未结 3 1126
不思量自难忘°
不思量自难忘° 2021-01-13 19:34

Im trying to use the sf package in R to see if sf object is within another sf object with the st_within function. My issue is with the output of this function w

相关标签:
3条回答
  • 2021-01-13 19:42

    Here is how you can get a logical vector from sparse geometry binary predicate:

    df$indicator <- st_within(df, box) %>% lengths > 0
    

    or to subset without creating a new variable:

    df <- df[st_within(df, box) %>% lengths > 0,]
    

    I cannot test on your large dataset unfortunately but please let me know if it is faster than matrix approach.

    0 讨论(0)
  • 2021-01-13 20:04

    The result of is_within is in truth a list column, so you can work your way out of this by "unlisting" it. Something like this would work:

    library(dplyr)
    library(sf)
    
    # object 1: I will test if it is inside object 2 - to make this more interesting
    # I added a second not-contained line
    df <- data.frame(lon = c(2.5, 3, 3.5), lat = c(2.5, 3, 3.5), var = 1) %>% 
      st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>%
      summarise(var = sum(var), do_union = F) %>% st_cast("LINESTRING")
    
    df2 <- data.frame(lon = c(4.5, 5, 6), lat = c(4.5, 5, 6), var = 2) %>% 
      st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>%
      summarise(var = sum(var), do_union = F) %>% st_cast("LINESTRING")
    df3 <- rbind(df, df2)
    
    # object 2: I will test if it contains object 1
    box <- data.frame(lon = c(2, 4, 4, 2, 2), lat = c(2, 2, 4, 4,2), var = 1) %>%
      st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% st_set_crs(4326) %>% 
      summarise(var = sum(var), do_union = F) %>% st_cast("POLYGON")
    
    plot(df3) 
    plot(st_geometry(box), add = TRUE)
    

    # see if the lines are within the box and build a data frame with results
    is_within <- st_within(df3$geometry, box$geometry) %>% 
      lapply(FUN = function(x) data.frame(ind = length(x))) %>% 
      bind_rows()
    
    # add the "indicator" to df3
    df3 <- dplyr::mutate(df3, indicator = is_within$ind) 
    df3
    #> Simple feature collection with 2 features and 2 fields
    #> geometry type:  LINESTRING
    #> dimension:      XY
    #> bbox:           xmin: 2.5 ymin: 2.5 xmax: 6 ymax: 6
    #> epsg (SRID):    4326
    #> proj4string:    +proj=longlat +datum=WGS84 +no_defs
    #>   var indicator                       geometry
    #> 1   3         1 LINESTRING (2.5 2.5, 3 3, 3...
    #> 2   6         0 LINESTRING (4.5 4.5, 5 5, 6 6)
    

    HTH

    Created on 2018-03-15 by the reprex package (v0.2.0).

    0 讨论(0)
  • 2021-01-13 20:09

    Instead of using the st_within function directly, try using a spatial join. Check out the following example how st_joins works

    library(sf)
    library(tidyverse)
    
    lines <-
    data.frame(id=gl(3,2), x=c(-3,2,6,11,7,10), y=c(-1,6,-5,-9,10,5)) %>%
      st_as_sf(coords=c("x","y"), remove=F) %>% 
      group_by(id) %>% 
      summarise() %>%
      st_cast("LINESTRING")
    
    yta10 <-
        st_point(c(0, 0)) %>%
        st_buffer(dist = 10) %>%
        st_sfc() %>%
        st_sf(yta = "10m")
    

    With a left join all lines are kept, but you can see which of them that are located inside the polygon

    lines %>% st_join(yta10, left=TRUE)
    

    An inner join (left = FALSE) only keeps the ones inside

    lines %>% st_join(yta10, left=FALSE)
    

    The latter can also be obtained by

    lines[yta10,]
    
    0 讨论(0)
提交回复
热议问题