---
title: "Converting between GeoJSON and sf"
author: "D Cooley"
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    fig_caption: yes
    toc: true
vignette: >
  %\VignetteIndexEntry{Converting between GeoJSON and sf}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```


## What it does

Quickly converts between GeoJSON and `sf` objects

## What it doesn't do

As per GeoJSON ([RFC 7946 specification)](https://tools.ietf.org/html/rfc7946#page-11), foreign members are ignored, and nested objects and arrays inside the `properties` object are converted to string/characters. 


```{r}
library(geojsonsf)
# library(sf)
```

You would also typically load `library(sf)` to take advantange of its `plot` methods. 

## GeoJSON

### Geometry 

```{r}
p <- '{"type":"Point","coordinates":[0,0]}'
sf <- geojson_sf(p)
head(sf)
```

### Geometry Collection

```{r}
gc <- '{
  "type": "GeometryCollection",
  "geometries": [
    {"type": "Point", "coordinates": [100.0, 0.0]},
    {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]},
    {"type" : "MultiPoint", "coordinates" : [[0,0], [1,1], [2,2]]}
  ]
}'
sf <- geojson_sf(gc)
head(sf)
```

Some web-plotting libraries (such as `googleway`) can't plot GeometryCollections directly. Therefore, you can set `expand_geometries` to `TRUE` and it will extract each geometry from a GeometryCollection and create a row for each one


```{r}
gc <- '{
  "type": "GeometryCollection",
  "geometries": [
    {"type": "Point", "coordinates": [100.0, 0.0]},
    {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]},
    {"type" : "MultiPoint", "coordinates" : [[0,0], [1,1], [2,2]]}
  ]
}'
sf <- geojson_sf(gc, expand_geometries = T)
head(sf)
```


### Feature

```{r}
f <- '{
	"type": "Feature",
	"properties": {"id":1,"value":100,"text":"the quick brown fox"},
	"geometry": {
	  "type": "LineString", 
	  "coordinates": [[101.0, 0.0], [102.0, 1.0]]
	  }
	}'
sf <- geojson_sf(f)
head(sf)
```


### Feature Collection

```{r}
fc <- '{
  "type": "FeatureCollection",
  "features": [
  {
    "type": "Feature",
    "properties": {"foo" : "feature 1.1", "bar" : "feature 1.2"},
    "geometry": {"type": "Point", "coordinates": [100.0, 0.0]}
  },
  {
    "type": "Feature",
    "properties": null,
    "geometry": {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}
  },
  {
    "type": "Feature",
	    "properties": {"foo" : "feature 3.1", "bar" : "feature 3.2"},
	    "geometry": {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}
	}
 ]
}'
sf <- geojson_sf(fc)
head(sf)

```


## Vectors of GeoJSON

```{r}
geo <- c(p, gc, f, fc)
sf <- geojson_sf(geo)
head(sf)
```


## JSON Arrays of GeoJSON


```{r}

js <- '[
{
  "type": "FeatureCollection",
  "features": [
  {
    "type": "Feature",
    "properties": null,
    "geometry": {"type": "Point", "coordinates": [100.0, 0.0]}
  },
  {
    "type": "Feature",
    "properties": null,
    "geometry": {"type": "LineString", "coordinates": [[201.0, 0.0], [102.0, 1.0]]}
  },
  {
    "type": "Feature",
	    "properties": null,
	    "geometry": {"type": "LineString", "coordinates": [[301.0, 0.0], [102.0, 1.0]]}
	}
 ]
},
{
  "type": "FeatureCollection",
	"features": [
	{
	  "type": "Feature",
	  "properties": null,
	  "geometry": {"type": "Point", "coordinates": [100.0, 0.0]}
	},
	{
	  "type": "Feature",
	  "properties": null,
	  "geometry": {"type": "LineString", "coordinates": [[501.0, 0.0], [102.0, 1.0]]}
	},
	{
	  "type": "Feature",
	  "properties": null,
	  "geometry": {"type": "LineString", "coordinates": [[601.0, 0.0], [102.0, 1.0]]}
	}
  ]
}
]'

sf <- geojson_sf(js)
head(sf)
```


## Reading from URL

```r
url <- "http://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_050_00_500k.json"
sf <- geojson_sf(url)
#head(sf)
```

## Reading from file

```{r}
sf <- geojson_sf(system.file("examples", "geo_melbourne.geojson", package = "geojsonsf"))
head(sf)
```

## sf to GeoJSON

```{r}
geo <- sf_geojson(sf)
substr(geo, 1, 80)
```

### Atomising

Sometimes it's useful to convert each row of an `sf` object into it's own GeoJSON object, for example when you want to keep each geometry separate in a database. Set `atomise = TRUE` to return a vector of GeoJSON

```{r}
geo <- sf_geojson(sf, atomise = T)
```

now `geo` is a vector of GeoJSON

```{r}
substr(geo[1], 1, 80)
substr(geo[2], 1, 80)
```

## Well-known Text

It also converts GeoJSON to Well-Known Text and returns a `data.frame`


```{r}
fc <- '{
  "type": "FeatureCollection",
  "features": [
  {
    "type": "Feature",
    "properties": {"foo" : "feature 1.1", "bar" : "feature 1.2"},
    "geometry": {"type": "Point", "coordinates": [100.0, 0.0]}
  },
  {
    "type": "Feature",
    "properties": null,
    "geometry": {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}
  },
  {
    "type": "Feature",
	    "properties": {"foo" : "feature 3.1", "bar" : "feature 3.2"},
	    "geometry": {"type": "LineString", "coordinates": [[101.0, 0.0], [102.0, 1.0]]}
	}
 ]
}'
df <- geojson_wkt(fc)
head(df)
```


