Suppose I have a data.frame
object that has a column called geojson
with GeoJSON strings in each row.
How can I transform this data.frame
into an sf object that would allow me to perform geospatial operations on it?
Here's a quick example:
library(tidyverse)
library(dplyr)
library(sf)
library(geojsonsf)
df = data.frame(row_id = c(1,2,3),
categories = c('Cat1','Cat1','Cat2'),
geojson = c('{"type": "FeatureCollection","features": [{"type": "Feature","properties": {},"geometry": {"coordinates": [[0,0],[1,0]],"type": "LineString"}}]}',
'{"type": "FeatureCollection","features": [{"type": "Feature","properties": {},"geometry": {"coordinates": [[0,1],[1,1]],"type": "LineString"}}]}',
'{"type": "FeatureCollection","features": [{"type": "Feature","properties": {},"geometry": {"coordinates": [[0,2],[1,2]],"type": "LineString"}},
{"type": "Feature","properties": {},"geometry": {"coordinates": [[0,3],[1,3]],"type": "LineString"}}]}'))
And here is my (very dirty and not fully functional) solution so far:
# Trying to create one geometry for every row in the original dataset
for (i in 1:nrow(df)){
this_geom = df$geojson[i] %>% # First, we access the GeoJSON text
geojson_sf() %>% # Then we use the use the GeoJSON text and create a whole sf dataframe
group_by() %>% # Then we need to dissolve/unite everything into one single geometry
summarize(geometry = st_union(geometry)) %>%
.$geometry[1] # Finally, I try to retrieve only the actual geometry from the result above
df$geometry[i] = this_geom # and store it into the original dataframe in a column called `geometry`
}
# Creating an sf-aware object
gdf = df %>%
st_as_sf(sf_column_name = "geometry")
The first chunk of the code above (the for-loop) doesn't throw any errors, but the second bit (creating the gdf
object) does. I get the following error:
Error in st_sf(x, ..., agr = agr, sf_column_name = sf_column_name) :
no simple features geometry column present
I think I'm messing up in the creation of the geometry
column. Because when I print it out, this is what it looks like:
> print(df$geometry)
[[1]]
Geometry set for 1 feature
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 0 ymin: 0 xmax: 1 ymax: 0
Geodetic CRS: WGS 84
LINESTRING (0 0, 1 0)
[[2]]
Geometry set for 1 feature
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 0 ymin: 1 xmax: 1 ymax: 1
Geodetic CRS: WGS 84
LINESTRING (0 1, 1 1)
[[3]]
Geometry set for 1 feature
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 0 ymin: 2 xmax: 1 ymax: 2
Geodetic CRS: WGS 84
LINESTRING (0 2, 1 2)
It looks like it's not actually creating a proper column of data, but instead a list of items.
Is there a way that I can change this to make sf
recognize the new geometries I'm creating so it'll allow me to make the gdf
object?
gdf = st_as_sf(data.frame(df, geojson_sf(df$geojson)))
does the business. Can you provide more complex data with multiple features in each row?Error in data.frame(df, geojson_sf(df$geojson)) : arguments imply differing number of rows: 3, 4