constructing json in R with jsonlite - too many brackets - r

Not a json expert, but I need what I think is referred to as "nested objects" and I am getting instead what I think is referred to as "nested arrays". In other words, some extra brackets. I'm trying to convert a dataframe into json data using jsonlite in R. Reproducible code and results below. Can anyone point me to how to get the data in the proper format (rows as nested objects)?
library(jsonlite)
testdat <- data.frame(locationColumn = c("US", "US"),
nameColumn = c("General Motors", "Walmart"),
zipColumn = c(19890, 72712) )
jsl <- jsonlite::toJSON(
list(
config = list(
item1 = list("country",
"city"),
item2 = "true",
item3 = "false",
item4 = 3
),
rows = split(testdat, 1:nrow(testdat))
),
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "rows",
simplifyDataFrame = TRUE
)
jsl
Output:
{
"config": {
"item1": [
"country",
"city"
],
"item2": "true",
"item3": "false",
"item4": 3
},
"rows": {
"1": [
{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
}
],
"2": [
{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
]
}
}
What I need: (EDIT: I added some more complexity to the json. I need to keep the brackets in 'config', but not have brackets in 'rows'.
{
"config": {
"item1": [
"country",
"city"
],
"item2": "true",
"item3": "false",
"item4": 3
},
"rows": {
"1":
{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
},
"2":
{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
}
}

Here is a possible solution:
library(jsonlite)
testdat <- data.frame(locationColumn = c("US", "US"),
nameColumn = c("General Motors", "Walmart"),
zipColumn = c(19890, 72712) )
jsl <- jsonlite::toJSON(
list(
rows = split(testdat, 1:nrow(testdat))
),
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "columns", #change from rows (moves brackets from row level to value level)
simplifyDataFrame = TRUE
)
#removed the backets if desired
#jsl<-gsub("\\[|\\]", "", jsl)
all.equal(testcase, fromJSON(jsl))
testcase<-fromJSON('{
"rows": {
"1":{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
},
"2":{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
}
}')
all.equal(testcase, fromJSON(jsl))
#[1] TRUE
EDIT Here is an approved version that manually edits the list of list in order to obtain the correct format.
#create a list of the data
top<-list(
config = list(
item1 = list("country",
"city"),
item2 = "true",
item3 = "false",
item4 = 3
),
rows = split(testdat, 1:nrow(testdat))
)
#edit the data frames store as part of rows
#lapply - lapply loops will parse each column in each row to create a new list
rows<-lapply(top$rows, function(x){
tempdf<-x
#collist<-lapply(names(tempdf), function(y){print(tempdf[ , y, drop=T])})
collist<-lapply(names(tempdf), function(y){tempdf[, y, drop=T]})
names(collist)<-names(tempdf)
collist
})
#update the list with the list of list
top$rows<-rows
#make the JSON
jsl <- jsonlite::toJSON(
top,
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "columns",
simplifyDataFrame = TRUE
)

Related

R Plumber, How to create nested JSON

Need Help, I just create API with R Plumber, I just would like the Result Json will be like this
Instead of like this
below are my R Plumber script
library(plumber)
library(jsonlite)
#* #get /nested_json
#* #serializer unboxedJSON
function() {
main_info <- data.frame(
Name = "John",
Address = "Stret No. 1",
Point = "600"
)
reason_info <- data.frame(code = c('AAA', 'BBB', 'CCC', NA, 'EEE'),
descriptiom = c('low value of point A', 'low value of point B', 'low value of point C', NA, 'low value of point D') )
main_info[1, "reason"][[1]] <- list(reason_info)
final_output <- as.list(main_info)
final_output
}
Thanks a lot for any kind of suggestion
UPDATE
The alternative solution from #deschen just solve the problem, my teammates that created the Web Application could use this solution.
the alternative solution are like below :
{
"Name": "John",
"Address": "Stret No. 1",
"Point": "600",
"reason": [
{
"code": "AAA",
"description": "low value of point A"
},
{
"code": "BBB",
"description": "low value of point B"
},
{
"code": "CCC",
"description": "low value of point C"
},
{
"code": null,
"description": null
},
{
"code": "EEE",
"description": "low value of point D"
}
]
}
library(tidyverse)
library(jsonlite)
reason_info <- data.frame(code = c('AAA', 'BBB', 'CCC', NA, 'EEE'),
description = c('low value of point A',
'low value of point B',
'low value of point C',
NA,
'low value of point D'))
reason_info_new <- reason_info %>%
mutate(new = apply(across(everything()), 1, as.list)) %>%
pull(new)
full <- list(Name = "John",
Address = "Stret No. 1",
Point = "600",
reason = reason_info_new)
myJSON <- toJSON(full, pretty = TRUE, auto_unbox = TRUE)
myJSON
which gives:
{
"Name": "John",
"Address": "Stret No. 1",
"Point": "600",
"reason": [
{
"code": "AAA",
"description": "low value of point A"
},
{
"code": "BBB",
"description": "low value of point B"
},
{
"code": "CCC",
"description": "low value of point C"
},
{
"code": null,
"description": null
},
{
"code": "EEE",
"description": "low value of point D"
}
]
}

Use your own csv file instead of json

I would like to run locally this repository
However I have my own csv file with data which I would like to use instead of the json example.
How is it possible to make it?
Here and example of data
data = data.frame(id = c(1,1,2,2), col = c("before", "after", "before", "after"), text = c("text 3 sentiment","I feel good","Happy","It is a nice day and I feel glad"))
I'm not sure... but based off your data...
> read.csv2("file.csv") %>% jsonlite::toJSON(auto_unbox = TRUE, pretty = TRUE)
[
{
"id": 1,
"col": "before",
"text": "text 3 sentiment"
},
{
"id": 1,
"col": "after",
"text": "I feel good"
},
{
"id": 2,
"col": "before",
"text": "Happy"
},
{
"id": 2,
"col": "after",
"text": "It is a nice day and I feel glad"
}
]

Calling geojson_list in R

I have a csv file with the locations of bicicle stations in four columns: "long", "lat", "nro_est", "nombre". I want to create a geojson fil from this csv file doing this:
as.json(geojson_list(estaciones, lat = 'lat', long = 'long'), pretty = TRUE)
the example from ?geojson_list with data "states" is very similar but instead of creating points it creates polygons:
geojson_list(states[1:351,], geometry="polygon", group='group')
My problem with my adaption brings this error. It takes "nro_est" and "nombre" as coordinates and also it shows "long" as propertie. There is an NA that i dont understand. What am i doing wrong?
"geometry": {
"type": "Point",
"coordinates": [-58.40436, -34.58819, 200, "NA"]
},
"properties": {
"long": "-58.40436",
"nro_est": "200",
"nombre": "Austria y French"
}
You can use library(geojsonsf) to convert a data.frame of lon/lat columns into geojson (with POINT geometries)
In the absence of your data I'm creating a dummy example to show you how it works.
library(geojsonsf)
estaciones <- data.frame(
lat = rnorm(3)
, long = rnorm(3)
, nombre = sample(letters, size = 3)
, nro_est = 1:3
)
geojson <- df_geojson( df = estaciones, lat = "lat", lon = "long" )
jsonify::pretty_json( geojson )
# {
# "type": "FeatureCollection",
# "features": [
# {
# "type": "Feature",
# "properties": {
# "nombre": "q",
# "nro_est": 1
# },
# "geometry": {
# "type": "Point",
# "coordinates": [
# 0.6266271502100352,
# -0.3347400043557775
# ]
# }
# },
# {
# "type": "Feature",
# "properties": {
# "nombre": "a",
# "nro_est": 2
# },
# "geometry": {
# "type": "Point",
# "coordinates": [
# 1.1169599023314834,
# 2.593126207650351
# ]
# }
# },
# {
# "type": "Feature",
# "properties": {
# "nombre": "y",
# "nro_est": 3
# },
# "geometry": {
# "type": "Point",
# "coordinates": [
# 0.18108997460569566,
# 0.4805016218807452
# ]
# }
# }
# ]
# }

How to specify detailed layout inside renderPlotly (Shiny r)

Trying to render a Plotly graph in a shiny app. The basic graph is getting generated but unable to format the axes. Able to get the desired graph options in the Plotly Web Application with the layout as given below.
"layout": {
"autosize": true,
"height": 831.625,
"hovermode": "x",
"width": 1480,
"xaxis": {
"autorange": true,
"hoverformat": "%Y-%m",
"range": [
1356978600000,
1391193000000
],
"rangeselector": {
"buttons": [
{
"label": "reset",
"step": "all"
},
{
"label": "#1",
"step": "month"
}
]
},
"tickformat": "%Y-%m",
"tickmode": "auto",
"tickprefix": "",
"title": "B",
"type": "date"
},
"yaxis": {
"autorange": true,
"range": [
-19.888888888888893,
397.8888888888889
],
"title": "A",
"type": "linear"
}
}
Facing issue in specifying this layout within the shiny code. For simple objects like title, it works (as shown below).
output$plot <- renderPlotly({
new_plot <- plot_ly(plot_data, x = plot_data$FY_Month, y = plot_data$Booking_Amount , name = "Test Data (Actual)")
new_plot <- layout(new_plot,title = "Random Title")
new_plot
})
How do I give the complex xaxis and yaxis layouts?
Found an answer to the question myself. Both xaxis and yaxis layouts can be specified as shown below:
x_axis <- list(
title = "Fiscal Year / Month",
autorange = "true",
hoverformat = "%Y-%m",
tickformat = "%Y-%m",
tickmode = "auto",
type = "date"
)
y_axis <- list(
title = "A",
type ="linear"
)
output$plot <- renderPlotly({
new_plot <- plot_ly(plot_data, x = plot_data$FY_Month, y = plot_data$Booking_Amount , name = "Test Data (Actual)")
new_plot <- layout(new_plot,title = "Random Title")
new_plot <- layout(new_plot, xaxis=x_axis, yaxis = y_axis)
new_plot
})
Similarly, other such formats can be specified. Used the following reference.Plotly R API reference doc for Axes Labels

How to read a geojson file containing feature collections to leaflet-shiny directly

My question is how to read a geojson file containing feature collections to leaflet-shiny. I have seen joe's github https://github.com/jcheng5/leaflet-shiny/blob/master/inst/examples/geojson/server.R but he did not use an external dataset but created the geojson manually. i am confused whether
Is that possible to read geojson file to leaflet-shiny directly?
If not, what does the structure of feature collections look like in shiny (in Joe's post it is multi-polygon) and how to create that in a faster and easier way?
You're probably looking to be able to manipulate the GeoJSON file directly in R-Shiny and R as opposed to reading a static file.
As previously mentioned, you can feed a string containing the GeoJSON to leaflet-shiny such as this GeoJSON FeatureCollection:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"party": "Republican"},
"id": "North Dakota",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-104.05, 48.99],
[-97.22, 48.98],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]]
}
},
{
"type": "Feature",
"properties": {"party": "Democrat"},
"id": "Colorado",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}
]
}
Then you can use RJSONIO::fromJSON to read this object in the format provided in the example and manipulate it in R such as this (Note: it appears that you have to add styles after reading the GeoJSON file as opposed to reading a GeoJSON FeatureCollection file that already has styles):
geojson <- RJSONIO::fromJSON(fileLocation)
geojson[[2]][[1]]$properties$style <- list(color = "red",fillColor = "red")
geojson[[2]][[2]]$properties$style <- list(color = "blue",fillColor = "blue")
geojson$style <- list(weight = 5,stroke = "true",fill = "true",opacity = 1,fillOpacity = 0.4)
This will give you the same R object if you had just entered this:
geojson <- list(
type = "FeatureCollection",
features = list(
list(
type = "Feature",
geometry = list(type = "MultiPolygon",
coordinates = list(
list(
list(
c(-109.05, 41.00),
c(-102.06, 40.99),
c(-102.03, 36.99),
c(-109.04, 36.99),
c(-109.05, 41.00)
)
)
)
),
properties = list(
party = "Democrat",
style = list(
fillColor = "blue",
color = "blue"
)
),
id = "Colorado"
),
list(
type = "Feature",
geometry = list(type = "MultiPolygon",
coordinates = list(
list(
list(
c(-104.05, 48.99),
c(-97.22, 48.98),
c(-96.58, 45.94),
c(-104.03, 45.94),
c(-104.05, 48.99)
)
)
)
),
properties = list(
party = "Republican",
style = list(
fillColor = "red",
color = "red"
)
),
id = "North Dakota"
)
),
style = list(
weight = 5,
stroke = "true",
fill = "true",
fillOpacity = 0.4
opacity = 1
))
For question 1, refering to the API doc, you can provide instead directly a geojson string instead of a list like in the example.
The provided example also mentionned it with
You can also use a GeoJSON string value instead of a structured
GeoJSON object like this one
You can use this recipe to read your GeoJSON file
For question 2, as question 1 is Ok, no issue.

Resources