I have a data frame like below:
df <- data.frame(child = c('item3-1-1','item3-1-2','item3-2','item3-1','item2-1','item2-2','item1'),parent = c('item3-1','item3-1','item3','item3','item2','item2',''))
I want to convert this dataframe in below format:
choices <-
list(
list(id = 1, title = "item1"),
list(id = 2, title = "item2",
subs = list(
list(id = 21, title = "item2-1"),
list(id = 22, title = "item2-2")
)
),
list(id = 3, title = "item3",
subs = list(
list(id = 31, title = "item3-1", isSelectable = FALSE,
subs = list(
list(id = 311, title = "item3-1-1"),
list(id = 312, title = "item3-1-2")
)
),
list(id = 32, title = "item3-2")
)
)
)
I need the nested list with option of 'subs' to traverse the tree drop-down list.
Is there any function or method by which I can achieve this as I have huge dataset.
Here is a function which generates the nested list. The id are not the same but anyway we do not use them in ComboTree (but they are required).
dat <- data.frame(
item = c("item1", "item2", "item2-1", "item2-2", "item3", "item3-1",
"item3-1-1", "item3-1-2", "item3-2"),
parent = c("root", "root", "item2", "item2", "root", "item3",
"item3-1", "item3-1", "item3"),
stringsAsFactors = FALSE
)
makeChoices <- function(dat){
f <- function(parent, id = "id"){
i <- match(parent, dat$item)
title <- dat$item[i]
subs <- dat$item[dat$parent==title]
if(length(subs)){
list(
title = title,
id = paste0(id,"-",i),
subs = lapply(subs, f, id = paste0(id,"-",i))
)
}else{
list(title = title, id = paste0(id,"-",i))
}
}
lapply(dat$item[dat$parent == "root"], f)
}
choices <- makeChoices(dat)
> jsonlite::toJSON(choices, auto_unbox = TRUE, pretty = TRUE)
[
{
"title": "item1",
"id": "id-1"
},
{
"title": "item2",
"id": "id-2",
"subs": [
{
"title": "item2-1",
"id": "id-2-3"
},
{
"title": "item2-2",
"id": "id-2-4"
}
]
},
{
"title": "item3",
"id": "id-5",
"subs": [
{
"title": "item3-1",
"id": "id-5-6",
"subs": [
{
"title": "item3-1-1",
"id": "id-5-6-7"
},
{
"title": "item3-1-2",
"id": "id-5-6-8"
}
]
},
{
"title": "item3-2",
"id": "id-5-9"
}
]
}
]
Related
I am putting some results together in a nested list (with arrays). The expected results must be EXACTLY as follows:
{
"item1": "TEXT",
"item2": "MORE TEXT",
"item3": [
"STILL TEXT"
],
"item4": [
"TEXT AGAIN"
],
"values": [
{
"start": 0,
"end": 99
}
]
}
I put all my results together like this:
listToJson <- c(list(item1 = "TEXT",
item2 = "MORE TEXT",
item3 = "STILL TEXT",
item4 = "TEXT AGAIN",
values = list(start = 99,
end = 0)))
write_json(listToJson, path = "test.json", auto_unbox = TRUE , null = "null")
The problem is that the results doesn't have array elements (see below). item3 and item4 should be arrays. How can I change my code to get the expected results in that exact format?
{
"item1":"TEXT",
"item2":"MORE TEXT",
"item3":"STILL TEXT",
"item4":"TEXT AGAIN",
"values":{
"start":99,
"end":0}
}
You can just use as.array for those specific items.
library(jsonlite)
listToJson <- c(
list(
item1 = "TEXT",
item2 = "MORE TEXT",
item3 = as.array("STILL TEXT"),
item4 = as.array("TEXT AGAIN"),
values = as.array(list(start = 99,
end = 0))
)
)
write_json(listToJson, path = "test.json", auto_unbox = TRUE , null = "null")
Output
{
"item1":"TEXT",
"item2":"MORE TEXT",
"item3":[
"STILL TEXT"
],
"item4":[
"TEXT AGAIN"
],
"values":[
{
"start":0,
"end":99
}
]
}
I want to get from a data.table like this
temp <- data.table(data = list(data.table(a = 1:2,b=1:2)), type = "A")
data
type
<data.table[2x2]>
A
to a JSON like this
{
"group":
{
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "A"
}
}
The Problem is I always end up with an additional array "[" for group.
What I have tried is tidyr::nest and
temp2 <- temp[, list(group=list(.SD))]
jsonlite::toJSON(temp2,pretty = TRUE, auto_unbox = TRUE)
temp3 <- temp[, (list(group=list(as.list(.SD))))]
jsonlite::toJSON(temp3,pretty = TRUE, auto_unbox = TRUE)
Is there an "easy" solution for my problem?
Thanks
edit more complex example
temp <-
data.table(
id1 = 1:6,
id2 = c(rep("A", 2), rep("B", 2), rep("C", 2)),
data = rep(list(data.table(
a = 1:2, b = 1:2
)), 6),
type = "test"
)
nest1 <- temp[, list(list(.SD)),by=.(id1,id2)] %>% setnames("V1","group")
nest1[, type:="B"]
nest2 <- nest1[, list(list(.SD)),by=.(id2)] %>% setnames("V1","data")
nest2[, type:="C"]
nest3 <- nest2[, list(list(.SD)),by=.(id2)] %>% setnames("V1","group")
jsonlite::toJSON(nest3, pretty = TRUE)
desired output (shortend):
Group should only contain objects and no arrays
[
{
"id2": "A",
"group": {
"data": [
{
"id1": 1,
"group": {
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
},
"type": "B"
},
{
"id1": 2,
"group": {
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
},
"type": "B"
}
],
"type": "C"
}
},
{
"id2": "B",
"group": {
"data": [],
"type": "C"
}
}
]
We could use jq to do the unboxing as a post-processing step, since jsonlite doesn't seem to allow for this specific use case:
jsonlite::toJSON(nest3, pretty = TRUE) %>%
jqr::jq('walk(if type=="array" and length==1 then .[0] else . end)')
The jq bit is taken from jq ~ is there a better way to collapse single object arrays?
I have the following data frame:
fakedat<-data.frame(name=c("Holdingcompany","Holdingcompany","company1","company1","company2","company2"),children=c("company1","company2","company4","company3","company5","company6"),info=c("text1","text2","text3","text5","othertext","other_text"),percentage=c("100%","100%","60%","75%","80%","70%"))
The output I am hoping is the following:
{"name": "Holdingcompany",
"children": [
{
"name": "company1",
"tooltip": "text1",
"percentage": "100%",
"children": [
{
"name": "company4",
"tooltip": "text3",
"percentage": "60%"
},
{
"name": "company3",
"tooltip": "text5",
"percentage": "75%"
}
]
},
{
"name": "company2",
"tooltip": "text2",
"percentage": "100%",
"children": [
{
"name": "company5",
"tooltip": "othertext",
"percentage": "80%"
},
{
"name": "company6",
"tooltip": "other_text",
"percentage": "70%"
}
]
}
]
}
I have attempted a couple different methods of parsing including:
How to write to json with children from R
But unfortunately I wasn't able to apply the above code to this situation properly to the the children in lists the way I was hoping.
Attempting to apply some of the solution from the below mentioned possible duplicate, I'm running into a recursion error: "C stack usage too close to limit" as the function appears to call itself.
##Adding in IDs
fakedat<-data.frame(id=c(1,2,3,4,5,6),name=c("Holdingcompany","Holdingcompany","company1","company1","company2","company2"),
children=c("company1","company2","company4","company3","company5","company6"),
info=c("text1","text2","text3","text5","othertext","other text"),
percentage=c("100%","50%","60%","75%","80%","70%"))
get_node <- function(df, id) {
node <- as.list(df[df$id == id, c("name", "info",
"percentage","id")])
names(node) = c("name", "info", "percentage","id")
id1<-df[df$id==id,]$children
if (!is.na(id1)){
child1 <- get_node(df, id)
if(child1$name == node$name){
node$children <- list(child1)}
node
}
}
jsonlite::toJSON(get_node(fakedat,6), pretty = TRUE, auto_unbox =
TRUE)`
Error: C stack usage 7972496 is too close to the limit
Consider preparing the relationships of parent to child with merge, then walk down each level of root / parent / child to build nested lists with nested lapply:
Data Preparation
### MERGE DATA
merge_df <- merge(fakedat, fakedat, by.x="children", by.y="name")
merge_df
# children name info.x percentage.x children.y info.y percentage.y
# 1 company1 Holdingcompany text1 100% company4 text3 60%
# 2 company1 Holdingcompany text1 100% company3 text5 75%
# 3 company2 Holdingcompany text2 100% company5 othertext 80%
# 4 company2 Holdingcompany text2 100% company6 other_text 70%
nested_df <- unique(merge_df[c("children", "name", "info.x", "percentage.x")])
nested_df
# children name info.x percentage.x
# 1 company1 Holdingcompany text1 100%
# 3 company2 Holdingcompany text2 100%
top_level_val <- unique(merge_df$name)
top_level_val
# [1] "Holdingcompany"
JSON Build
output <- lapply(top_level_val, function(root) {
root_lst <- list(
name = root
)
root_lst$children <- lapply(1:nrow(nested_df), function(i) {
chld_mrg <- merge(nested_df[nested_df$children == nested_df$children[i],], merge_df)
parent_lst <- list(
name = nested_df$children[i][1],
tooltip = nested_df$info.x[i][1],
percentage = nested_df$percentage.x[i][1]
)
parent_lst$children <- lapply(1:nrow(chld_mrg), function(j)
list(
name = merge_df$children.y[j][1],
tooltip = merge_df$info.y[j][1],
percentage = merge_df$percentage.y[j][1]
)
)
return(parent_lst)
})
return(root_lst)
})
# CONVERT TO JSON STRING
jdata <- toJSON(output[[1]], pretty=TRUE, auto_unbox=TRUE)
# WRITE TO DISK
fileConn <- file("NestParentChildJSON.json")
writeLines(jdata, fileConn)
close(fileConn)
Output
{
"name": "Holdingcompany",
"children": [
{
"name": "company1",
"tooltip": "text1",
"percentage": "100%",
"children": [
{
"name": "company4",
"tooltip": "text3",
"percentage": "60%"
},
{
"name": "company3",
"tooltip": "text5",
"percentage": "75%"
}
]
},
{
"name": "company2",
"tooltip": "text2",
"percentage": "100%",
"children": [
{
"name": "company4",
"tooltip": "text3",
"percentage": "60%"
},
{
"name": "company3",
"tooltip": "text5",
"percentage": "75%"
}
]
}
]
}
I am trying to flatten a nested JSON file from within R,
Here is my current code
library(jsonlite)
json_file <- "json file"
json_data = fromJSON(json_file, flatten = FALSE)
flat_data = as.data.frame(json_data)
However i am getting the below error
flat_data = as.data.frame(json_data)
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, :
arguments imply differing number of rows: 1, 13, 3201
Here is a sample of my JSON structure
{
"RIDE":{
"STARTTIME":"2020\/01\/05 22:27:49 UTC ",
"RECINTSECS":1,
"DEVICETYPE":"Garmin FR735XT ",
"IDENTIFIER":" ",
"TAGS":{
"Aerobic Training Effect":"3.8 ",
"Athlete":"Chuck Finley",
"Data":" ",
"Device":"Garmin",
"Device Info":"HR Garmin 2327",
"File Format":" ",
"Filename":"2020_01_06_06_27_49.json ",
"Month":"January ",
"Performance Condition":"-5 ",
"Recovery Time":" ",
"Source Filename":"A1662750_2020_01_06_06_27_49.gz ",
"Sport":"Run ",
"SubSport":" ",
"VO2max detected":"61.7 ",
"Weekday":"Mon ",
"Workout Code":" ",
"Year":"2020 "
},
"INTERVALS":[
{ "NAME":"Lap 1 ", "START": 0, "STOP": 249, "COLOR":"#000000", "PTEST":"false" },
{ "NAME":"Lap 2 ", "START": 250, "STOP": 504, "COLOR":"#000000", "PTEST":"false" }
],
"SAMPLES":[
{ "SECS":0, "KM":0, "KPH":0, "HR":104, "ALT":14, "LAT":-40.402758436, "LON":175.0371112, "SLOPE":0, "LRBALANCE":0, "RCAD":109.5, "RVERT":0.47, "RCON":273 },
{ "SECS":1, "KM":0.00056, "KPH":0, "HR":104, "ALT":14, "LAT":-40.402758436, "LON":175.0371112, "SLOPE":0, "LRBALANCE":24.87, "RCAD":109.5, "RVERT":0.47, "RCON":273 }
],
"XDATA":[
{
"NAME" : "EXTRA",
"VALUES" : [ "STANCETIMEPERCENT", "VERTICALRATIO", "STEPLENGTH", "FIELD_88", "ACTIVITYTYPE", "PERFORMANCECONDITION" ],
"UNITS" : [ "", "", "", "", "", "" ],
"SAMPLES" : [
{ "SECS":1, "KM":0, "VALUES":[ 48.5, 0, 0, 300, 1, 0 ] },
{ "SECS":2, "KM":0, "VALUES":[ 48.5, 4.96, 891, 300, 1, 0 ] }
]
}
]
}
}
I am quite new to R, so any advise would be appreciated.
Just change the file name. Json file should be .json
json_file <- "json file.json"
I'm fairly new to handling spatial data and leaflet in general. I'm having difficulty creating a popup for my map. Basically what I want in the popup is the coordinates of my polygon and one of the properties (the type of class). Below is an test example of my geoJSON file:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"class": "blah"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-81.7987060546875,
32.74570253945518
],
[
-81.6229248046875,
32.16631295696736
],
[
-80.958251953125,
32.4263401615464
],
[
-81.2713623046875,
32.791892438123696
],
[
-81.7437744140625,
32.97180377635759
],
[
-81.7987060546875,
32.74570253945518
]
]
]
}
},
{
"type": "Feature",
"properties": {"class": "blah2"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-82.056884765625,
33.55512901742288
],
[
-81.4471435546875,
33.247875947924385
],
[
-81.40869140625,
33.80653802509606
],
[
-82.078857421875,
33.88865750124075
],
[
-82.40295410156249,
33.58716733904656
],
[
-82.056884765625,
33.55512901742288
]
]
]
}
},
{
"type": "Feature",
"properties": {"class": "blahh3"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-83.485107421875,
32.930318199070534
],
[
-83.07861328125,
31.863562548378965
],
[
-82.21618652343749,
32.11049589629439
],
[
-82.97973632812499,
33.22030778968541
],
[
-83.726806640625,
33.211116472416855
],
[
-83.485107421875,
32.930318199070534
]
]
]
}
}
]
}
Here is the code I have so far to create my map, but I'm struggling/don't even know where to start on creating a popup that includes my coordinates and property:
blahTest <- geojson_read("/file/path/...", what = "sp")
fpal <- colorFactor("viridis", blahTest$class)
leaflet(blahTest) %>%
addTiles() %>%
addPolygons(stroke = FALSE, smoothFactor = 0.3, fillOpacity = 1,
color = ~fpal(class)) %>%
addLegend(colors = ~fpal, opacity = 1.0, labels = ~fpal) %>%
addPopups()
Thanks in advance!
Overview
Using #patL's suggestion, I used the popup parameter within leaflet::addPolygon() function to add label both the class and coordinates that define each polygon within blahTest.
I saved your sample data as .gejson file and imported it using sf::read_sf() and produced the HTML table within the popup using the htmlTable package after reading How to add an html table to leaflet popup.
# load necessary package
library( htmlTable )
library( leaflet )
library( sf )
# load necessary data
blahTest <-
read_sf(
dsn = "test.geojson"
, layer = "OGRGeoJSON"
)
# map data values to colors
fpal <- colorFactor( palette = "viridis", domain = blahTest$class)
# create map
my.map <-
leaflet( data = blahTest ) %>%
addTiles() %>%
addPolygons( stroke = FALSE
, smoothFactor = 0.3
, fillOpacity = 1
, color = ~fpal( class )
, popup = paste0(
"<b>Class: </b>"
, blahTest$class
, "<br>"
, "<b>Coordinates: </b>"
, "<br>"
, lapply(
X = blahTest$geometry
, FUN = function( i )
htmlTable(
x = i[[1]]
, header = c( "Longitude", "Latitude" )
)
)
) ) %>%
addLegend( pal = fpal
, values = ~class
, labels = ~class
, title = "Legend"
, position = "topright"
, opacity = 1.0 )
# view map
my.map
# end of script #