6 Non-rectangular data
working with raw data from online services (JSON)
This chapter gives an example for processing deeply nested lists and converting them to data frames.
6.1 Traversing
Click here to show setup code.
library(tidyverse)
library(here)
We are now working with the results from downloading geolocation data from photon.komoot.de.
This is stored in the file here("data/komoot-berlin.rds")
and we can read it with readRDS()
:
berlin <- readRDS(here("data/komoot-berlin.rds"))
berlin
## $features
## $features[[1]]
## $features[[1]]$geometry
## $features[[1]]$geometry$coordinates
## $features[[1]]$geometry$coordinates[[1]]
## [1] 13.38886
##
## $features[[1]]$geometry$coordinates[[2]]
## [1] 52.51704
##
##
## $features[[1]]$geometry$type
## [1] "Point"
##
##
## $features[[1]]$type
## [1] "Feature"
##
## $features[[1]]$properties
## $features[[1]]$properties$osm_id
## [1] 240109189
##
## $features[[1]]$properties$osm_type
## [1] "N"
##
## $features[[1]]$properties$country
## [1] "Germany"
##
## $features[[1]]$properties$osm_key
## [1] "place"
##
## $features[[1]]$properties$city
## [1] "Berlin"
##
## $features[[1]]$properties$osm_value
## [1] "city"
##
## $features[[1]]$properties$postcode
## [1] "10117"
##
## $features[[1]]$properties$name
## [1] "Berlin"
##
##
##
##
## $type
## [1] "FeatureCollection"
str(berlin)
## List of 2
## $ features:List of 1
## ..$ :List of 3
## .. ..$ geometry :List of 2
## .. .. ..$ coordinates:List of 2
## .. .. .. ..$ : num 13.4
## .. .. .. ..$ : num 52.5
## .. .. ..$ type : chr "Point"
## .. ..$ type : chr "Feature"
## .. ..$ properties:List of 8
## .. .. ..$ osm_id : int 240109189
## .. .. ..$ osm_type : chr "N"
## .. .. ..$ country : chr "Germany"
## .. .. ..$ osm_key : chr "place"
## .. .. ..$ city : chr "Berlin"
## .. .. ..$ osm_value: chr "city"
## .. .. ..$ postcode : chr "10117"
## .. .. ..$ name : chr "Berlin"
## $ type : chr "FeatureCollection"
As you can see it is a somewhat complex list structure. We know from “Indexing” that we can access it’s components in the following way:
berlin$type
## [1] "FeatureCollection"
berlin$features
## [[1]]
## [[1]]$geometry
## [[1]]$geometry$coordinates
## [[1]]$geometry$coordinates[[1]]
## [1] 13.38886
##
## [[1]]$geometry$coordinates[[2]]
## [1] 52.51704
##
##
## [[1]]$geometry$type
## [1] "Point"
##
##
## [[1]]$type
## [1] "Feature"
##
## [[1]]$properties
## [[1]]$properties$osm_id
## [1] 240109189
##
## [[1]]$properties$osm_type
## [1] "N"
##
## [[1]]$properties$country
## [1] "Germany"
##
## [[1]]$properties$osm_key
## [1] "place"
##
## [[1]]$properties$city
## [1] "Berlin"
##
## [[1]]$properties$osm_value
## [1] "city"
##
## [[1]]$properties$postcode
## [1] "10117"
##
## [[1]]$properties$name
## [1] "Berlin"
berlin$features[[1]]
## $geometry
## $geometry$coordinates
## $geometry$coordinates[[1]]
## [1] 13.38886
##
## $geometry$coordinates[[2]]
## [1] 52.51704
##
##
## $geometry$type
## [1] "Point"
##
##
## $type
## [1] "Feature"
##
## $properties
## $properties$osm_id
## [1] 240109189
##
## $properties$osm_type
## [1] "N"
##
## $properties$country
## [1] "Germany"
##
## $properties$osm_key
## [1] "place"
##
## $properties$city
## [1] "Berlin"
##
## $properties$osm_value
## [1] "city"
##
## $properties$postcode
## [1] "10117"
##
## $properties$name
## [1] "Berlin"
With the function purrr::pluck()
, there is however a more universal tool available for accessing elements of more complex lists:
berlin %>%
pluck("type")
## [1] "FeatureCollection"
berlin[["type"]]
## [1] "FeatureCollection"
berlin %>%
pluck("features")
## [[1]]
## [[1]]$geometry
## [[1]]$geometry$coordinates
## [[1]]$geometry$coordinates[[1]]
## [1] 13.38886
##
## [[1]]$geometry$coordinates[[2]]
## [1] 52.51704
##
##
## [[1]]$geometry$type
## [1] "Point"
##
##
## [[1]]$type
## [1] "Feature"
##
## [[1]]$properties
## [[1]]$properties$osm_id
## [1] 240109189
##
## [[1]]$properties$osm_type
## [1] "N"
##
## [[1]]$properties$country
## [1] "Germany"
##
## [[1]]$properties$osm_key
## [1] "place"
##
## [[1]]$properties$city
## [1] "Berlin"
##
## [[1]]$properties$osm_value
## [1] "city"
##
## [[1]]$properties$postcode
## [1] "10117"
##
## [[1]]$properties$name
## [1] "Berlin"
berlin %>%
pluck("features", 1)
## $geometry
## $geometry$coordinates
## $geometry$coordinates[[1]]
## [1] 13.38886
##
## $geometry$coordinates[[2]]
## [1] 52.51704
##
##
## $geometry$type
## [1] "Point"
##
##
## $type
## [1] "Feature"
##
## $properties
## $properties$osm_id
## [1] 240109189
##
## $properties$osm_type
## [1] "N"
##
## $properties$country
## [1] "Germany"
##
## $properties$osm_key
## [1] "place"
##
## $properties$city
## [1] "Berlin"
##
## $properties$osm_value
## [1] "city"
##
## $properties$postcode
## [1] "10117"
##
## $properties$name
## [1] "Berlin"
berlin[["features"]][[1]]
## $geometry
## $geometry$coordinates
## $geometry$coordinates[[1]]
## [1] 13.38886
##
## $geometry$coordinates[[2]]
## [1] 52.51704
##
##
## $geometry$type
## [1] "Point"
##
##
## $type
## [1] "Feature"
##
## $properties
## $properties$osm_id
## [1] 240109189
##
## $properties$osm_type
## [1] "N"
##
## $properties$country
## [1] "Germany"
##
## $properties$osm_key
## [1] "place"
##
## $properties$city
## [1] "Berlin"
##
## $properties$osm_value
## [1] "city"
##
## $properties$postcode
## [1] "10117"
##
## $properties$name
## [1] "Berlin"
berlin %>%
pluck("features", 1, "geometry")
## $coordinates
## $coordinates[[1]]
## [1] 13.38886
##
## $coordinates[[2]]
## [1] 52.51704
##
##
## $type
## [1] "Point"
berlin[["features"]][[1]][["geometry"]]
## $coordinates
## $coordinates[[1]]
## [1] 13.38886
##
## $coordinates[[2]]
## [1] 52.51704
##
##
## $type
## [1] "Point"
berlin %>%
pluck("features", 1, "geometry", "coordinates")
## [[1]]
## [1] 13.38886
##
## [[2]]
## [1] 52.51704
Similarly:
berlin %>%
pluck("features", 1, "properties", "country")
## [1] "Germany"
And as one more important characteristic of a tidyverse
-function, pluck()
is pipe-able:
berlin %>%
pluck("features", 1) %>%
pluck("properties", "country")
## [1] "Germany"
6.1.1 Exercises
Introduce a variable for the first feature. Collect the coordinates, the country and the postal code.
first_feature <- berlin %>% ___(_____) first_feature %>% ___(_____) first_feature %>% ___(_____) first_feature %>% ___(_____)
## NULL
## [1] "Germany"
## [1] "10117"
6.2 Iterating and traversing
Click here to show setup code.
library(tidyverse)
library(here)
Now we are not only working with the geolocation data for Berlin, but we are adding data for our usual suspects:
komoot <- readRDS(here("data/komoot.rds"))
komoot
## # A tibble: 4 x 6
## name url_name url res status content
## <chr> <chr> <chr> <list> <list> <list>
## 1 Berlin Berlin https://photon.komoot.de/api/… <respo… <NULL> <list […
## 2 Toronto Toronto https://photon.komoot.de/api/… <respo… <NULL> <list […
## 3 Tel Av… Tel%20Aviv https://photon.komoot.de/api/… <respo… <NULL> <list […
## 4 Zürich Z%C3%BCri… https://photon.komoot.de/api/… <respo… <NULL> <list […
It looks slightly different from the list berlin
from section “Traversing”.
That is because we have the list-of-2 stored for each city in the column content
.
By using pull()
on content
, we can produce a list containing the information for all cities:
komoot_content <-
komoot %>%
pull(content)
berlin <-
komoot_content %>%
pluck(1)
berlin %>%
pluck("features", 1, "geometry", "coordinates")
## [[1]]
## [1] 13.38886
##
## [[2]]
## [1] 52.51704
toronto <-
komoot_content %>%
pluck(2)
toronto %>%
pluck("features", 1, "geometry", "coordinates")
## [[1]]
## [1] -79.38721
##
## [[2]]
## [1] 43.65396
With map()
we can access the same element of the respective list for each city:
komoot_content %>%
map(~ pluck(., "features", 1, "geometry", "coordinates"))
## [[1]]
## [[1]][[1]]
## [1] 13.38886
##
## [[1]][[2]]
## [1] 52.51704
##
##
## [[2]]
## [[2]][[1]]
## [1] -79.38721
##
## [[2]][[2]]
## [1] 43.65396
##
##
## [[3]]
## [[3]][[1]]
## [1] 34.78053
##
## [[3]][[2]]
## [1] 32.08048
##
##
## [[4]]
## [[4]][[1]]
## [1] 8.542322
##
## [[4]][[2]]
## [1] 47.3724
With map()
we can also use a shorthand notation for this, without the need to use pluck()
.
We can just give it a list of the arguments which we would normally use as arguments for pluck()
:
komoot_content %>%
map(list("features", 1, "geometry", "coordinates"))
## [[1]]
## [[1]][[1]]
## [1] 13.38886
##
## [[1]][[2]]
## [1] 52.51704
##
##
## [[2]]
## [[2]][[1]]
## [1] -79.38721
##
## [[2]][[2]]
## [1] 43.65396
##
##
## [[3]]
## [[3]][[1]]
## [1] 34.78053
##
## [[3]][[2]]
## [1] 32.08048
##
##
## [[4]]
## [[4]][[1]]
## [1] 8.542322
##
## [[4]][[2]]
## [1] 47.3724
The access path can also be stored in a variable:
accessor <- list("features", 1, "geometry", "coordinates")
coordinates <-
komoot_content %>%
map(accessor)
coordinates
## [[1]]
## [[1]][[1]]
## [1] 13.38886
##
## [[1]][[2]]
## [1] 52.51704
##
##
## [[2]]
## [[2]][[1]]
## [1] -79.38721
##
## [[2]][[2]]
## [1] 43.65396
##
##
## [[3]]
## [[3]][[1]]
## [1] 34.78053
##
## [[3]][[2]]
## [1] 32.08048
##
##
## [[4]]
## [[4]][[1]]
## [1] 8.542322
##
## [[4]][[2]]
## [1] 47.3724
6.2.1 Exercises
Augment
komoot
with a columns containing information on the first feature only.## # A tibble: 4 x 7 ## name url_name url res status content first_feature ## <chr> <chr> <chr> <list> <list> <list> <list> ## 1 Berlin Berlin https://photon.kom… <respo… <NULL> <list … <list [3]> ## 2 Toron… Toronto https://photon.kom… <respo… <NULL> <list … <list [3]> ## 3 Tel A… Tel%20Av… https://photon.kom… <respo… <NULL> <list … <list [3]> ## 4 Zürich Z%C3%BCr… https://photon.kom… <respo… <NULL> <list … <list [3]>
Augment
komoot_first
with columns containing information on coordinates, place and postal code. Use accessors and appropriate types for the columns.acc_coordinates <- _____ acc_country <- _____ komoot_first %>% mutate( coordinates = ___(___, acc_coordinates), country = _____, postcode = map_chr(_____, ~ pluck(___, .default = NA)) )
## # A tibble: 4 x 10 ## name url_name url res status content first_feature coordinates ## <chr> <chr> <chr> <lis> <list> <list> <list> <list> ## 1 Berl… Berlin http… <res… <NULL> <list … <list [3]> <NULL> ## 2 Toro… Toronto http… <res… <NULL> <list … <list [3]> <NULL> ## 3 Tel … Tel%20A… http… <res… <NULL> <list … <list [3]> <NULL> ## 4 Züri… Z%C3%BC… http… <res… <NULL> <list … <list [3]> <NULL> ## # … with 2 more variables: country <chr>, postcode <chr>
6.3 Plucking multiple locations
Click here to show setup code.
library(tidyverse)
library(here)
komoot <- readRDS(here("data/komoot.rds"))
komoot_content <-
komoot %>%
pull(content)
What if we want to access two different pieces of information of each main list point at once?
We are again starting in the setup with the list komoot_content
from “Iterating and traversing”.
Let’s define the two locations of the city-lists we would like to access:
accessor_coords <- list("features", 1, "geometry", "coordinates")
komoot_content %>%
map(accessor_coords)
## [[1]]
## [[1]][[1]]
## [1] 13.38886
##
## [[1]][[2]]
## [1] 52.51704
##
##
## [[2]]
## [[2]][[1]]
## [1] -79.38721
##
## [[2]][[2]]
## [1] 43.65396
##
##
## [[3]]
## [[3]][[1]]
## [1] 34.78053
##
## [[3]][[2]]
## [1] 32.08048
##
##
## [[4]]
## [[4]][[1]]
## [1] 8.542322
##
## [[4]][[2]]
## [1] 47.3724
accessor_country <- list("features", 1, "properties", "country")
komoot_content %>%
map(accessor_country)
## [[1]]
## [1] "Germany"
##
## [[2]]
## [1] "Canada"
##
## [[3]]
## [1] "Israel"
##
## [[4]]
## [1] "Switzerland"
Combine them as a list of lists and hand it over to a map()
inside a map()
:
accessors <- list(coords = accessor_coords, country = accessor_country)
accessors %>%
map(~ map(komoot_content, .))
## $coords
## $coords[[1]]
## $coords[[1]][[1]]
## [1] 13.38886
##
## $coords[[1]][[2]]
## [1] 52.51704
##
##
## $coords[[2]]
## $coords[[2]][[1]]
## [1] -79.38721
##
## $coords[[2]][[2]]
## [1] 43.65396
##
##
## $coords[[3]]
## $coords[[3]][[1]]
## [1] 34.78053
##
## $coords[[3]][[2]]
## [1] 32.08048
##
##
## $coords[[4]]
## $coords[[4]][[1]]
## [1] 8.542322
##
## $coords[[4]][[2]]
## [1] 47.3724
##
##
##
## $country
## $country[[1]]
## [1] "Germany"
##
## $country[[2]]
## [1] "Canada"
##
## $country[[3]]
## [1] "Israel"
##
## $country[[4]]
## [1] "Switzerland"
6.4 Flattening
Click here to show setup code.
library(tidyverse)
library(here)
komoot <- readRDS(here("data/komoot.rds"))
komoot_content <-
komoot %>%
pull(content)
coordinates <-
komoot_content %>%
map(list("features", 1, "geometry", "coordinates"))
It can occur that we end up with lists which are unnecessarily deep and we would like to make them flatter to make it easier to handle them.
We are starting in our setup with komoot_content
and coordinates
from section “Iterating and traversing”.
An example for an list that seems a bit too deep is given here:
coordinates %>%
pluck(1)
## [[1]]
## [1] 13.38886
##
## [[2]]
## [1] 52.51704
We can chop off a layer of a list and end up with a vector with one of the functions purrr::flatten_*()
.
In the *
we need to specify what class the output will be:
coordinates %>%
pluck(1) %>%
flatten_dbl()
## [1] 13.38886 52.51704
Let’s use map()
to apply this to the entire list of our cities’ coordinates:
coordinates %>%
map(flatten_dbl)
## [[1]]
## [1] 13.38886 52.51704
##
## [[2]]
## [1] -79.38721 43.65396
##
## [[3]]
## [1] 34.78053 32.08048
##
## [[4]]
## [1] 8.542322 47.372396
6.5 Transposing
Click here to show setup code.
library(tidyverse)
library(here)
komoot <- readRDS(here("data/komoot.rds"))
komoot_content <-
komoot %>%
pull(content)
coordinates <-
komoot_content %>%
map(list("features", 1, "geometry", "coordinates"))
You might know the mathematical concept of transposition from your linear algebra courses.
A similar concept is available in R
when we are dealing with lists.
We are starting in our setup with komoot_content
and coordinates
from section “Iterating and traversing”.
Let’s apply purrr::transpose()
to our list coordinates
:
coordinates %>%
transpose()
## [[1]]
## [[1]][[1]]
## [1] 13.38886
##
## [[1]][[2]]
## [1] -79.38721
##
## [[1]][[3]]
## [1] 34.78053
##
## [[1]][[4]]
## [1] 8.542322
##
##
## [[2]]
## [[2]][[1]]
## [1] 52.51704
##
## [[2]][[2]]
## [1] 43.65396
##
## [[2]][[3]]
## [1] 32.08048
##
## [[2]][[4]]
## [1] 47.3724
What was originally a list with 4 elements of which each one was a list of 2 elements has become a list of 2 elements of which each one is a list of 4 elements.
With flatten_dbl()
we can simplify the structure, so that we end up with a list of 2, where each element consists of a vector of 4.
The first vector contains the longitude and the second the latitude of our cities:
coordinates_transposed <-
coordinates %>%
transpose() %>%
map(~ flatten_dbl(.))
coordinates_transposed
## [[1]]
## [1] 13.388860 -79.387207 34.780527 8.542322
##
## [[2]]
## [1] 52.51704 43.65396 32.08048 47.37240
6.5.1 Exercises
Explain what happens if you transpose a tibble:
komoot %>% transpose()
6.6 Rectangling
Click here to show setup code.
library(tidyverse)
library(here)
komoot <- readRDS(here("data/komoot.rds"))
komoot_content <-
komoot %>%
pull(content)
coordinates_transposed <-
komoot_content %>%
map(list("features", 1, "geometry", "coordinates")) %>%
transpose() %>%
map(~ flatten_dbl(.))
Most of us R
-users feel most at ease when dealing in R
with data frames on which we can use a plethora of well-known (by us) functions with non-startling behaviour.
What if we don’t get our data in such a form?
We are starting in our setup with the list coordinates_transposed
from section “Transposing”.
A tibble is internally a list of named vectors of equal length.
In two easy steps we can therefore make a tibble out of the unnamed list coordinates_transposed
:
coordinates_transposed %>%
rlang::set_names(c("lon", "lat"))
## $lon
## [1] 13.388860 -79.387207 34.780527 8.542322
##
## $lat
## [1] 52.51704 43.65396 32.08048 47.37240
coordinates_transposed %>%
rlang::set_names(c("lon", "lat")) %>%
as_tibble()
## # A tibble: 4 x 2
## lon lat
## <dbl> <dbl>
## 1 13.4 52.5
## 2 -79.4 43.7
## 3 34.8 32.1
## 4 8.54 47.4
If you want to keep the names open for now, but still get a tibble, you can set as_tibble()
’s argument .name_repair = "universal"
:
coordinates_transposed %>%
as_tibble(.name_repair = "universal")
## New names:
## * `` -> ...1
## * `` -> ...2
## # A tibble: 4 x 2
## ...1 ...2
## <dbl> <dbl>
## 1 13.4 52.5
## 2 -79.4 43.7
## 3 34.8 32.1
## 4 8.54 47.4
coordinates_transposed %>%
as_tibble(.name_repair = "universal") %>%
rename(lon = ...1, lat = ...2)
## New names:
## * `` -> ...1
## * `` -> ...2
## # A tibble: 4 x 2
## lon lat
## <dbl> <dbl>
## 1 13.4 52.5
## 2 -79.4 43.7
## 3 34.8 32.1
## 4 8.54 47.4
6.7 Accessing APIs
Click here to show setup code.
library(tidyverse)
library(here)
When dealing with web-APIs, query results come frequently in the JSON (JavaScript Object Notation) format.
How to deal with this in R?
A way to “talk” with APIs is provided by the package {httr}.
The “GET”-query is executed by using httr::GET()
with the URL, containing the query specifics, as an argument:
req <- httr::GET("https://photon.komoot.de/api/?q=Paradeplatz&limit=3")
If you are using this command in a script, you need to wait until the query is finished processing:
httr::stop_for_status(req)
The result of the query can be accessed via httr::content()
:
content <- httr::content(req)
content
## $features
## $features[[1]]
## $features[[1]]$geometry
## $features[[1]]$geometry$coordinates
## $features[[1]]$geometry$coordinates[[1]]
## [1] 8.538948
##
## $features[[1]]$geometry$coordinates[[2]]
## [1] 47.36981
##
##
## $features[[1]]$geometry$type
## [1] "Point"
##
##
## $features[[1]]$type
## [1] "Feature"
##
## $features[[1]]$properties
## $features[[1]]$properties$osm_id
## [1] 905841
##
## $features[[1]]$properties$osm_type
## [1] "R"
##
## $features[[1]]$properties$extent
## $features[[1]]$properties$extent[[1]]
## [1] 8.538163
##
## $features[[1]]$properties$extent[[2]]
## [1] 47.37027
##
## $features[[1]]$properties$extent[[3]]
## [1] 8.539516
##
## $features[[1]]$properties$extent[[4]]
## [1] 47.36935
##
##
## $features[[1]]$properties$country
## [1] "Switzerland"
##
## $features[[1]]$properties$osm_key
## [1] "highway"
##
## $features[[1]]$properties$city
## [1] "Zurich"
##
## $features[[1]]$properties$osm_value
## [1] "pedestrian"
##
## $features[[1]]$properties$postcode
## [1] "8001"
##
## $features[[1]]$properties$name
## [1] "Paradeplatz"
##
## $features[[1]]$properties$state
## [1] "Zurich"
##
##
##
## $features[[2]]
## $features[[2]]$geometry
## $features[[2]]$geometry$coordinates
## $features[[2]]$geometry$coordinates[[1]]
## [1] 7.108249
##
## $features[[2]]$geometry$coordinates[[2]]
## [1] 50.88602
##
##
## $features[[2]]$geometry$type
## [1] "Point"
##
##
## $features[[2]]$type
## [1] "Feature"
##
## $features[[2]]$properties
## $features[[2]]$properties$osm_id
## [1] 389550464
##
## $features[[2]]$properties$osm_type
## [1] "N"
##
## $features[[2]]$properties$country
## [1] "Germany"
##
## $features[[2]]$properties$osm_key
## [1] "place"
##
## $features[[2]]$properties$city
## [1] "Cologne"
##
## $features[[2]]$properties$osm_value
## [1] "locality"
##
## $features[[2]]$properties$postcode
## [1] "51147"
##
## $features[[2]]$properties$name
## [1] "Paradeplatz"
##
## $features[[2]]$properties$state
## [1] "North Rhine-Westphalia"
##
##
##
## $features[[3]]
## $features[[3]]$geometry
## $features[[3]]$geometry$coordinates
## $features[[3]]$geometry$coordinates[[1]]
## [1] 8.684258
##
## $features[[3]]$geometry$coordinates[[2]]
## [1] 49.38674
##
##
## $features[[3]]$geometry$type
## [1] "Point"
##
##
## $features[[3]]$type
## [1] "Feature"
##
## $features[[3]]$properties
## $features[[3]]$properties$osm_id
## [1] 391678888
##
## $features[[3]]$properties$osm_type
## [1] "W"
##
## $features[[3]]$properties$extent
## $features[[3]]$properties$extent[[1]]
## [1] 8.683635
##
## $features[[3]]$properties$extent[[2]]
## [1] 49.38719
##
## $features[[3]]$properties$extent[[3]]
## [1] 8.68488
##
## $features[[3]]$properties$extent[[4]]
## [1] 49.3863
##
##
## $features[[3]]$properties$country
## [1] "Germany"
##
## $features[[3]]$properties$osm_key
## [1] "place"
##
## $features[[3]]$properties$city
## [1] "Heidelberg"
##
## $features[[3]]$properties$osm_value
## [1] "locality"
##
## $features[[3]]$properties$postcode
## [1] "69120"
##
## $features[[3]]$properties$name
## [1] "Paradeplatz"
##
## $features[[3]]$properties$state
## [1] "Baden-Württemberg"
##
##
##
##
## $type
## [1] "FeatureCollection"
As you can see, the result, as it is displayed in R, is already a nested list at this point. And we know how to deal with these objects.
The object did originally come as a JSON object though, which you can see if you look at the literal result of the query:
text_content <- httr::content(req, as = "text")
cat(text_content)
## {"features":[{"geometry":{"coordinates":[8.538948327037028,47.369806999999994],"type":"Point"},"type":"Feature","properties":{"osm_id":905841,"osm_type":"R","extent":[8.5381631,47.3702704,8.5395156,47.3693475],"country":"Switzerland","osm_key":"highway","city":"Zurich","osm_value":"pedestrian","postcode":"8001","name":"Paradeplatz","state":"Zurich"}},{"geometry":{"coordinates":[7.1082488,50.8860177],"type":"Point"},"type":"Feature","properties":{"osm_id":389550464,"osm_type":"N","country":"Germany","osm_key":"place","city":"Cologne","osm_value":"locality","postcode":"51147","name":"Paradeplatz","state":"North Rhine-Westphalia"}},{"geometry":{"coordinates":[8.684257597277371,49.3867415],"type":"Point"},"type":"Feature","properties":{"osm_id":391678888,"osm_type":"W","extent":[8.6836355,49.3871856,8.6848797,49.3862973],"country":"Germany","osm_key":"place","city":"Heidelberg","osm_value":"locality","postcode":"69120","name":"Paradeplatz","state":"Baden-Württemberg"}}],"type":"FeatureCollection"}
The package {jsonlite} has the function jsonlite::prettify()
to offer, in order to display a one-line JSON-structure in a more clearly laid-out manner:
cat(jsonlite::prettify(text_content))
## {
## "features": [
## {
## "geometry": {
## "coordinates": [
## 8.538948327037028,
## 47.369806999999994
## ],
## "type": "Point"
## },
## "type": "Feature",
## "properties": {
## "osm_id": 905841,
## "osm_type": "R",
## "extent": [
## 8.5381631,
## 47.3702704,
## 8.5395156,
## 47.3693475
## ],
## "country": "Switzerland",
## "osm_key": "highway",
## "city": "Zurich",
## "osm_value": "pedestrian",
## "postcode": "8001",
## "name": "Paradeplatz",
## "state": "Zurich"
## }
## },
## {
## "geometry": {
## "coordinates": [
## 7.1082488,
## 50.8860177
## ],
## "type": "Point"
## },
## "type": "Feature",
## "properties": {
## "osm_id": 389550464,
## "osm_type": "N",
## "country": "Germany",
## "osm_key": "place",
## "city": "Cologne",
## "osm_value": "locality",
## "postcode": "51147",
## "name": "Paradeplatz",
## "state": "North Rhine-Westphalia"
## }
## },
## {
## "geometry": {
## "coordinates": [
## 8.684257597277371,
## 49.3867415
## ],
## "type": "Point"
## },
## "type": "Feature",
## "properties": {
## "osm_id": 391678888,
## "osm_type": "W",
## "extent": [
## 8.6836355,
## 49.3871856,
## 8.6848797,
## 49.3862973
## ],
## "country": "Germany",
## "osm_key": "place",
## "city": "Heidelberg",
## "osm_value": "locality",
## "postcode": "69120",
## "name": "Paradeplatz",
## "state": "Baden-Württemberg"
## }
## }
## ],
## "type": "FeatureCollection"
## }