1

I would like to set to empty the geometries of some features of my sf object given a condition. Here is my code:

my_points %<>% mutate(geometry = if_else(district_x != district_y, st_sfc(rep(st_point(), nrow(.))), geometry))

Basically, my dataframe contains two text columns named district_x and district_y respectively and a POINT geometry (sfc) column named geometry. Everytime the value in district_x is different from the value in district_y, I want to set the geometry of that feature to Empty.

With this code above, I am getting the following error:

Error in `stopifnot()`:
ℹ In argument: `geometry = if_else(...)`.
Caused by error in `vapply()`:
! values must be length 3,
 but FUN(X[[1]]) result is length 1

Any hints?

1
  • You can assign empty geometries by piping NULL into the associated features using ``st_geometry` for example, st_geometry(pts)[which(pts$district_x == pts$district_y)] <- NULL The call to which is simply creating an index, of the resulting query, that references the corresponding row number. Commented May 8, 2023 at 19:43

1 Answer 1

1

I'd set the geometry elements to st_empty() using a logical subselection. Here's a reproducible example that only uses the sf package - you seem to have some other unstated packages attached.

First lets make a sample data set:

d = st_as_sf(
data.frame(
district_x=c(1,2,3,4),district_y=c(1,5,3,2),
x=c(1,2,3,4),y=c(1,2,3,4)),
coords=c("x","y"))

Which is this:

> d
Simple feature collection with 4 features and 2 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 1 ymin: 1 xmax: 4 ymax: 4
CRS:           NA
  district_x district_y    geometry
1          1          1 POINT (1 1)
2          2          5 POINT (2 2)
3          3          3 POINT (3 3)
4          4          2 POINT (4 4)

Which rows are we interested in? Let's compare columns:

> d$district_x == d$district_y
[1]  TRUE FALSE  TRUE FALSE

Change those elements:

d$geometry[d$district_x == d$district_y] = st_point()

And now they are changed:

> d
Simple feature collection with 4 features and 2 fields (with 2 geometries empty)
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 2 ymin: 2 xmax: 4 ymax: 4
CRS:           NA
  district_x district_y    geometry
1          1          1 POINT EMPTY
2          2          5 POINT (2 2)
3          3          3 POINT EMPTY
4          4          2 POINT (4 4)

Actually I'm not sure if I've changed the ones you want or the ones you didn't, but flip the test if so. Like:

> # reset `d`:
> d = st_as_sf(data.frame(district_x=c(1,2,3,4),district_y=c(1,5,3,2),x=c(1,2,3,4),y=c(1,2,3,4)), coords=c("x","y"))
> # test and set
> d$geometry[d$district_x != d$district_y] = st_point()
> # look
> d
Simple feature collection with 4 features and 2 fields (with 2 geometries empty)
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 1 ymin: 1 xmax: 3 ymax: 3
CRS:           NA
  district_x district_y    geometry
1          1          1 POINT (1 1)
2          2          5 POINT EMPTY
3          3          3 POINT (3 3)
4          4          2 POINT EMPTY

The principle is: Create a vector of TRUE/FALSE for each row, set the geometry for the TRUE elements.

Strictly you should probably use st_geometry to get the geometry rather than $geometry since it might not be named that way in another data set:

> st_geometry(d)[d$district_x != d$district_y] = st_point()

Note this doesn't need any other packages which seem to be confusing you. Using simple constructions that can be easily taken apart and inspected will advance your learning.

1
  • Thank you very much. This solves my problem. Now for a follow up question, I would now want to replace these empty geometries I just created with point geometries created from XY coordinates created in columns name X and Y respectively. my_points %<>% mutate(geometry= if_else(st_is_empty(geometry), st_sfc(st_point(c(X, Y))), geometry)). I really don't know why it's not working. I scrolled through half of SO without luck now. Commented May 8, 2023 at 20:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.