4

In R I'm trying to create points using st_point() from package sf.

My input is a data.frame with one column being x-coordinate and another column y-coordinate:

    # Code to generate input
    library(sf)
    N <- 10
    df <- data.frame(x=rnorm(N),y=rnorm(N))

what I want to do is simply

    # Code to generate examplar output
    L <- list()
    for (i in 1:N)
        {
            L[[i]] <- st_point(c(df$x[i],df$y[i]))
        }
    st_sfc(L)

But insted of looping I am trying to do it with mapply(.)

    mapply(function(x,y) sum(c(x,y)),df$x,df$y)
    mapply(function(x,y) st_point(c(x,y)),df$x,df$y)

which works for adding the columns but not for making spatial points.

My question is two fold: (1) Why does this use of mapply fail? (2) And what would be the efficient way to do it?

2 Answers2

2

If you read the documentation for ?mapply you will see that by default it simplifies the results and returns a matrix in this case. You can tell it not to simplify.

# Code to generate input
library(sf)
N <- 10
df <- data.frame(x=rnorm(N),y=rnorm(N))

test <- mapply(function(x,y) st_point(c(x,y)),df$x,df$y)
str(test)
# num [1:2, 1:10] -1.42485 0.00776 -0.78035 -0.03221 0.30925 ...

test <- mapply(function(x,y) st_point(c(x,y)),df$x,df$y,SIMPLIFY = FALSE)
str(test)
# List of 10
# $ : 'XY' num [1:2] -1.42485 0.00776
# $ : 'XY' num [1:2] -0.7804 -0.0322
# $ : 'XY' num [1:2] 0.309 -0.541
# $ : 'XY' num [1:2] 0.459 -0.614
# $ : 'XY' num [1:2] -2.919 -0.169
# $ : 'XY' num [1:2] 0.689 0.168
# $ : 'XY' num [1:2] -1.066 0.711
# $ : 'XY' num [1:2] 1.09 0.925
# $ : 'XY' num [1:2] 0.756 0.81
# $ : 'XY' num [1:2] -1.17 -2.13

If you are going to be storing things in the dataframe anyway, you may consider the dplyr method of doing this. You will need to wrap the points in a list() in order for a dplyr mutate to work however.

library(dplyr)
test <- df %>%
  rowwise() %>%
  mutate(point = list(st_point(c(x,y))))
str(test$point)
# List of 10
# $ : 'XY' num [1:2] -1.42485 0.00776
# $ : 'XY' num [1:2] -0.7804 -0.0322
# $ : 'XY' num [1:2] 0.309 -0.541
# $ : 'XY' num [1:2] 0.459 -0.614
# $ : 'XY' num [1:2] -2.919 -0.169
# $ : 'XY' num [1:2] 0.689 0.168
# $ : 'XY' num [1:2] -1.066 0.711
# $ : 'XY' num [1:2] 1.09 0.925
# $ : 'XY' num [1:2] 0.756 0.81
# $ : 'XY' num [1:2] -1.17 -2.13
Adam Sampson
  • 1,971
  • 1
  • 7
  • 15
1

Regarding question 2 (what would be the efficient way to do it?), this is a solution based exclusively on sf package functions

library(sf)
N <- 10
df <- data.frame(x=rnorm(N),y=rnorm(N))

df |> 
  as.matrix() |> 
  st_multipoint() |> 
  st_sfc() |> 
  st_cast('POINT')
#> Geometry set for 10 features 
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -0.612779 ymin: -1.136853 xmax: 2.212084 ymax: 2.042055
#> CRS:           NA
#> First 5 geometries:
#> POINT (0.8364834 -0.3604207)
#> POINT (-0.5956698 -0.4816545)
#> POINT (0.1144735 -0.9178366)
#> POINT (2.212084 1.311319)
#> POINT (-0.04635354 1.423213)

Created on 2021-07-05 by the reprex package (v2.0.0)

josep maria porrà
  • 1,198
  • 10
  • 18
  • 1
    see [my comment](https://stackoverflow.com/questions/68247417/r-how-to-create-points-using-st-point-applied-to-columns-of-data-frame?noredirect=1#comment120622034_68247417) for a simpler way – SymbolixAU Jul 05 '21 at 22:24
  • @SymbolixAU, I read your comment and voted it. Really synthetic way. I wanted to show a solution that went step by step from simple feature geometry object (st_point or st_multipoint) to simple feature column (st_sfc). – josep maria porrà Jul 06 '21 at 06:17