jsonlite icon indicating copy to clipboard operation
jsonlite copied to clipboard

Missing toJSON function for class 'sfg'

Open zmbc opened this issue 4 years ago • 4 comments

Hi, and thanks for jsonlite!

I was pleasantly surprised when toJSON automatically turned an sf data frame into GeoJSON. However, I have a use case where I want to build the GeoJSON myself, row-by-row. Each row of an 'sfc' (sf column) is of class 'sfg' (sf geometry), but jsonlite doesn't define an toJSON for sfg, only sfc. So (as far as I know) it currently isn't possible to use toJSON to create a single object instead of an array.

zmbc avatar Feb 03 '21 18:02 zmbc

Indeed toJSON() supports 3 options: sf = "dataframe", or sf = "features" or sf = "geojson".

jeroen avatar Feb 03 '21 19:02 jeroen

@jeroen Not sure if I'm understanding correctly--are you saying that one of those options should achieve the desired result of encoding a single sfg-class object into JSON?

Here's what I see:

point <- sf::st_point(1:2)
point_sfc <- sf::st_sfc(point)

# toJSON on sfc: no matter what I do, it's wrapped in a JSON array
jsonlite::toJSON(point_sfc)
# > [{"type":"Point","coordinates":[1,2]}]
jsonlite::toJSON(point_sfc, sf = "dataframe")
# > [{"type":"Point","coordinates":[1,2]}]
jsonlite::toJSON(point_sfc, sf = "features")
# > [{"type":"Point","coordinates":[1,2]}]
jsonlite::toJSON(point_sfc, sf = "geojson")
# > [{"type":"Point","coordinates":[1,2]}]

# toJSON on sfg: does not work
jsonlite::toJSON(point)
# > Error: No method asJSON S3 class: sfg
jsonlite::toJSON(point, sf = "dataframe")
# > Error: No method asJSON S3 class: sfg
jsonlite::toJSON(point, sf = "features")
# > Error: No method asJSON S3 class: sfg
jsonlite::toJSON(point, sf = "geojson")
# > Error: No method asJSON S3 class: sfg

packageVersion('sf')
# > [1] ‘0.9.7’
packageVersion('jsonlite')
# [1] ‘1.7.0’

zmbc avatar Feb 10 '21 01:02 zmbc

@zmbc is this the type of output you're after:

library(sf)
library(geojsonsf)

point1 <- sf::st_point(1:2)
point2 <- sf::st_point(3:4)
point_sfc <- sf::st_sfc(list(point1, point2))

geojsonsf::sf_geojson( sf::st_as_sf( point_sfc ), atomise = TRUE )

# {"type":"Point","coordinates":[1,2]} 
# {"type":"Point","coordinates":[3,4]} 

dcooley avatar Mar 01 '21 23:03 dcooley

Also can be done like this:

library(jsonlite)
library(sf)
#> Linking to GEOS 3.9.1, GDAL 3.4.3, PROJ 7.2.1; sf_use_s2() is TRUE

g <- st_sfc(st_point(1:2), st_point(3:4))
toJSON(g, collapse = FALSE)
#> {"type":"Point","coordinates":[1,2]} {"type":"Point","coordinates":[3,4]}

s <- st_sf(a = 3:4, g)
toJSON(s, collapse = FALSE, sf = "feature")
#> {"type":"Feature","properties":{"a":3},"geometry":{"type":"Point","coordinates":[1,2]}} {"type":"Feature","properties":{"a":4},"geometry":{"type":"Point","coordinates":[3,4]}}

Created on 2022-09-13 with reprex v2.0.2

cphaarmeyer avatar Sep 13 '22 11:09 cphaarmeyer