Converting nested JSON to data frame - r

I am trying to convert a heavily nested json into a proper data frame (proper by tidy standards). An MWE of the json is copied at the end of the question, as I wanted to make sure it captured every element of the json.
I've tried:
library(jsonlite)
library(tidyverse)
dat <- jsonlite::fromJSON('data_toy.json') %>% pluck(1) %>% imap_dfr(~mutate(.x, department = .y))
but this returns:
Error: Columns `time_spent`, `school_breakdown`, `reason_for_taking_course`, `student_years`, `interest_before` must be 1d atomic vectors or lists
I've also tried:
dat <- jsonlite::fromJSON('data_toy.json', simplifyVector = FALSE,
simplifyDataFrame = FALSE, flatten=FALSE)
dat.df <- map_df(dat, ~{
flatten_df(.x[[1]]) %>%
dplyr::mutate(department = names(.x)[1])
})
but this returns:
Error in bind_rows_(x, .id) : Argument 3 must be length 1, not 0
How can I convert this to a data frame?
Data file (data_toy.json):
{
"department": {
"BME": [
{
"course_name": "BMD_ENG_250-0_20: Thermodynamics",
"instructor": "Neha Kamat",
"time_spent": {},
"school_breakdown": {
"Education & SP": 0,
"Communication": 0,
"Graduate School": 0,
"KGSM": 0
},
"reason_for_taking_course": {
"Distribution requirement": 0,
"Major/Minor requirement": 53
},
"student_years": {
"Freshman": 5,
"Sophomore": 37
},
"interest_before": {
"1-Not interested at all": 1,
"2": 5
},
"comments": [
"is amazing and you will love her!",
"Prof. is so nice"
],
"instructor_gender": "F"
},
{
"course_name": "BMD_ENG_250-0_20: Thermodynamics",
"instructor": "Neha Kamat",
"time_spent": {},
"school_breakdown": {
"Education & SP": 0,
"Communication": 0,
"Graduate School": 0,
"KGSM": 0
},
"reason_for_taking_course": {
"Distribution requirement": 0,
"Major/Minor requirement": 53
},
"student_years": {
"Freshman": 5,
"Sophomore": 37
},
"interest_before": {
"1-Not interested at all": 1,
"2": 5
},
"comments": [
"is amazing and you will love her!",
"Prof. is so nice"
],
"instructor_gender": "F"
}
],
"LING": [
{
"course_name": "BMD_ENG_250-0_20: Thermodynamics",
"instructor": "Neha Kamat",
"time_spent": {},
"school_breakdown": {
"Education & SP": 0,
"Communication": 0,
"Graduate School": 0,
"KGSM": 0
},
"reason_for_taking_course": {
"Distribution requirement": 0,
"Major/Minor requirement": 53
},
"student_years": {
"Freshman": 5,
"Sophomore": 37
},
"interest_before": {
"1-Not interested at all": 1,
"2": 5
},
"comments": [
"is amazing and you will love her!",
"Prof. is so nice"
],
"instructor_gender": "F"
},
{
"course_name": "BMD_ENG_250-0_20: Thermodynamics",
"instructor": "Neha Kamat",
"time_spent": {},
"school_breakdown": {
"Education & SP": 0,
"Communication": 0,
"Graduate School": 0,
"KGSM": 0
},
"reason_for_taking_course": {
"Distribution requirement": 0,
"Major/Minor requirement": 53
},
"student_years": {
"Freshman": 5,
"Sophomore": 37
},
"interest_before": {
"1-Not interested at all": 1,
"2": 5
},
"comments": [
"is amazing and you will love her!",
"Prof. is so nice"
],
"instructor_gender": "F"
}
]
}
}

Using flatten = TRUE seems to be the key here:
dat <- jsonlite::fromJSON('data_toy.json', flatten = TRUE)[[1]]
dat %>% bind_rows() %>% mutate(department = rep(names(dat), map_dbl(dat, nrow)))

Related

Plotly x axis range plot

In plotly, how to plot a bar graph with x axis range dates
I want
in xaxis - startDate, endDate and
in yaxis - requestCount
[
{
"startDate": 1666255095626,
"endDate": 1666341495626,
"requestCount": 3
},
{
"startDate": 1666168695626,
"endDate": 1666255095626,
"requestCount": 5
},
{
"startDate": 1666082295626,
"endDate": 1666168695626,
"requestCount": 2
},
{
"startDate": 1665995895626,
"endDate": 1666082295626,
"requestCount": 5
},
{
"startDate": 1665909495626,
"endDate": 1665995895626,
"requestCount": 1
}
]
This is the plotly graph json below
You can see I have used a xAxis as string value with start date and end date.
but is it possible to keep the xAxis as date format and still plot the same graph? This will allow the user to zoom the graph by keeping the date x axis format
[
{
"x": [
"1666255095626-1666341495626",
"1666168695626-1666255095626",
"1666082295626-1666168695626",
"1665995895626-1666082295626",
"1665909495626-1665995895626"
],
"y": [
3,
5,
2,
5,
1
],
"type": "bar",
"marker": {
"color": "",
"colorscale": null,
"size": "",
"line": {
"color": ""
}
},
"name": "",
"line": {
"shape": "linear"
},
"hoverinfo": "",
"transforms": []
}
]

R: Nested data.table to JSON

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?

Flatten nested JSON to dataframe in R

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"

Can't get amCharts WordPress dataloader to work

I am trying to use Data Loader from amCharts in WordPress, but I have no success. I am starting with an default Stock Chart and replacing the JS dataset structure with the one from the github site. Then I change the corresponding field values but I always get an empty site. I am using a CSV file on the same server to make sure it is not an access to external sources problem.
Does someone maybe have a complete code?
Here is my not working code so far:
var chart = AmCharts.makeChart("chartdiv", {
"type": "stock",
"color": "#fff",
"dataSets": [{
"title": "MSFT",
"fieldMappings": [{
"fromField": "Open",
"toField": "open"
}, {
"fromField": "High",
"toField": "high"
}, {
"fromField": "Low",
"toField": "low"
}, {
"fromField": "Close",
"toField": "close"
}, {
"fromField": "Volume",
"toField": "volume"
}],
"compared": false,
"categoryField": "Date",
/**
* data loader for data set data
*/
"dataLoader": {
"url": "uploads/2015/12/table.csv",
"format": "csv",
"showCurtain": true,
"showErrors": true,
"async": true,
"reverse": true,
"delimiter": ",",
"useColumnNames": true
},
}],
//"dataDateFormat": "YYYY-MM-DD",
"panels": [{
"title": "Value",
"percentHeight": 70,
"stockGraphs": [{
"type": "candlestick",
"id": "g1",
"openField": "open",
"closeField": "close",
"highField": "high",
"lowField": "low",
"valueField": "close",
"lineColor": "#fff",
"fillColors": "#fff",
"negativeLineColor": "#db4c3c",
"negativeFillColors": "#db4c3c",
"fillAlphas": 1,
"comparedGraphLineThickness": 2,
"columnWidth": 0.7,
"useDataSetColors": false,
"comparable": true,
"compareField": "close",
"showBalloon": false,
"proCandlesticks": true
}],
"stockLegend": {
"valueTextRegular": undefined,
"periodValueTextComparing": "[[percents.value.close]]%"
}
},
{
"title": "Volume",
"percentHeight": 30,
"marginTop": 1,
"columnWidth": 0.6,
"showCategoryAxis": false,
"stockGraphs": [{
"valueField": "volume",
"openField": "open",
"type": "column",
"showBalloon": false,
"fillAlphas": 1,
"lineColor": "#fff",
"fillColors": "#fff",
"negativeLineColor": "#db4c3c",
"negativeFillColors": "#db4c3c",
"useDataSetColors": false
}],
"stockLegend": {
"markerType": "none",
"markerSize": 0,
"labelText": "",
"periodValueTextRegular": "[[value.close]]"
},
"valueAxes": [{
"usePrefixes": true
}]
}
],
panelsSettings: {
color: "#fff",
plotAreaFillColors: "#333",
plotAreaFillAlphas: 1,
marginLeft: 60,
marginTop: 5,
marginBottom: 5
},
chartScrollbarSettings: {
graph: "g1",
graphType: "line",
usePeriod: "WW",
backgroundColor: "#333",
graphFillColor: "#666",
graphFillAlpha: 0.5,
gridColor: "#555",
gridAlpha: 1,
selectedBackgroundColor: "#444",
selectedGraphFillAlpha: 1
},
categoryAxesSettings: {
equalSpacing: true,
gridColor: "#555",
gridAlpha: 1
},
valueAxesSettings: {
gridColor: "#555",
gridAlpha: 1,
inside: false,
showLastLabel: true
},
chartCursorSettings: {
pan: true,
valueLineEnabled: true,
valueLineBalloonEnabled: true
},
legendSettings: {
color: "#fff"
},
stockEventsSettings: {
showAt: "high",
type: "pin"
},
balloon: {
textAlign: "left",
offsetY: 10
},
periodSelector: {
position: "bottom",
periods: [{
period: "DD",
count: 10,
label: "10D"
}, {
period: "MM",
count: 1,
label: "1M"
}, {
period: "MM",
count: 6,
label: "6M"
}, {
period: "YYYY",
count: 1,
label: "1Y"
}, {
period: "YYYY",
count: 2,
selected: true,
label: "2Y"
}, {
period: "YTD",
label: "YTD"
}, {
period: "MAX",
label: "MAX"
}]
}
});
}

Retrieving data from ASP.net sql database into amchart

i am facing quite a problem which is to create the nice graph from http://www.amcharts.com/ but i need to retrieve data from my sql database. But i don't know how to place inside. Please guide me. Below is the way how the graph displayed, but i wanted to work with data from database. Thank you.
<script type="text/javascript">
var chartData = generateChartData();
function generateChartData() {
var chartData = [];
var firstDate = new Date(2012, 0, 1);
firstDate.setDate(firstDate.getDate() - 500);
firstDate.setHours(0, 0, 0, 0);
for (var i = 0; i < 500; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
var value = Math.round(Math.random() * (40 + i)) + 100 + i;
chartData.push({
date: newDate,
value: value
});
}
return chartData;
}
AmCharts.makeChart("chartdiv", {
type: "stock",
pathToImages: "../amcharts/images/",
dataSets: [{
color: "#b0de09",
fieldMappings: [{
fromField: "value",
toField: "value"
}],
dataProvider: chartData,
categoryField: "date"
}],
panels: [{
showCategoryAxis: true,
title: "Value",
eraseAll: false,
labels: [{
x: 0,
y: 100,
text: "Click on the pencil icon on top-right to start drawing",
align: "center",
size: 16
}],
stockGraphs: [{
id: "g1",
valueField: "value",
bullet: "round",
bulletColor: "#FFFFFF",
bulletBorderColor: "#00BBCC",
bulletBorderAlpha: 1,
bulletBorderThickness: 2,
bulletSize: 7,
lineThickness: 2,
lineColor: "#00BBCC",
useDataSetColors: false
}],
stockLegend: {
valueTextRegular: " ",
markerType: "none"
},
drawingIconsEnabled: true
}],
chartScrollbarSettings: {
graph: "g1"
},
chartCursorSettings: {
valueBalloonsEnabled: true
},
periodSelector: {
position: "bottom",
periods: [{
period: "DD",
count: 10,
label: "10 days"
}, {
period: "MM",
count: 1,
label: "1 month"
}, {
period: "YYYY",
count: 1,
label: "1 year"
}, {
period: "YTD",
label: "YTD"
}, {
period: "MAX",
label: "MAX"
}]
}
});
</script>
Can you generate this script in your code behind ( using a string builder for example ) then use this
ScriptManager.RegisterStartupScript(this, this.GetType(), "", "'" + YourStringBuild.toString() + "'", true);

Resources