Cannot bind JSON to d3 - json

I've search far and wide, but cannot bind JSON data to a simple scatterplot for the life of me. I've looked at posts and examples, but I can only manage to bind arrays and not JSON. Below, I've tried to simply display JSON data as text and still can't make it work. Please let me know if you have any idea why!
d3_attempt.js
var data;
d3.json("json_data.json",function(error, dataset) {
if (error) return console.warn(error);
data = dataset;
var myscatter = d3.select("#somediv").append("svg")
.attr("width", 700)
.attr("height", 400);
myscatter.selectAll("text")
.data(data.data)
.enter()
.append("text")
.text(function(d){return d)})
});
json_data.json
{
"data":
{
"john": {"name": "john", "age": "13"},
"matt": {"name": "matt", "age":"14"}
}
}

Yup, you can only bind arrays, so you probably want to convert your data to an array:
myscatter.selectAll("text")
.data(d3.values(data.data));
This will give each of your text nodes the { name, age } object as data. If you need the keys too (looks like it's not required in this case), you could use d3.entries, which gives you an array of objects like { key: "john", value: { name: "John", age: "13" }}.

Related

Parsing JSON error cannot read property 'url' of undefined

I have been trying to parse JSON, which have 3 different set of data where one element have various number of children and sometimes none. I am getting an error when there is no children present or only one present. I declared the JSON as var data.
JSON A
{
"floorplan": [
{
"title": "plan1",
"url": "https://media.plan1.pdf"
},
{
"title": "plan2",
"url": "https://media.plan2.pdf"
}
]
}
JSON B
{"floorplan": []}
JSON C
{
"floorplan": [
{
"title": "plan1",
"url": "https://media.plan1.pdf"
}
]
}
I parsed the JSON like this:
var items = JSON.parse(data);
return {
floorplan1: items.floorplan[0].url;
floorplan2: items.floorplan[1].url;
}
But, it only returned data for the JSON A, for other 2 it gave TypeError: Cannot read property 'url' of undefined.
I modified the code to check if floorplan have at least one child and then parse data.
var items = JSON.parse(data);
var plan = items.floorplan[0];
if(plan){
return {
floorplan1: items.floorplan[0].url;
floorplan2: items.floorplan[1].url;
}
}
The new code returned data for JSON A and B(as empty row), but gave error for C. C have one child still it got the error.
I also tried this code, still got the error for JSON C.
var items = JSON.parse(data);
var plan = items.floorplan[0];
var plan1;
var plan2;
if(plan){
plan1 = items.floorplan[0].url;
plan2 = items.floorplan[1].url;
}
return{
floorplan1 : plan1 ? plan1 : null;
floorplan2 : plan2 ? plan2 : null;
}
Is there any method I can try to get data returned for all 3 types of JSON?
let data = `
[{"floorplan": [{
"title": "plan1",
"url": "https://media.plan1.pdf"
}, {
"title": "plan2",
"url": "https://media.plan2.pdf"
}]},
{"floorplan": []},
{"floorplan": [{
"title": "plan1",
"url": "https://media.plan1.pdf"
}]}]`;
let json = JSON.parse(data);
//console.log(json);
json.forEach(items=>{
//console.log(items);
let o = {
floorplan1: items.floorplan.length > 0 ? items.floorplan[0].url : '',
floorplan2: items.floorplan.length > 1 ? items.floorplan[1].url : ''
};
console.log(o);
o = {
floorplan1: (items.floorplan[0] || {'url':''}).url,
floorplan2: (items.floorplan[1] || {'url':''}).url
};
console.log(o);
o = {
floorplan1: items.floorplan[0]?.url,
floorplan2: items.floorplan[1]?.url
};
console.log(o);
const {floorplan: [one = {url:''}, two = {url:''}]} = items;
o = {
floorplan1: one.url,
floorplan2: two.url
};
console.log(o);
});
Sure. A few ways, and more than I have here. I have put all the raw data into one string, parsed it into json and then iterated through that. In each loop my variable items will correspond to one of the json variables you created and referenced in your question as items.
In the first example, I check to make sure that items.floorplan has at least enough elements to contain the url I'm trying to reference, then use the ternary operator ? to output that URL if it exists or an empty string if it doesn't.
In the second example, I use the || (OR) operator to return the first object that evaluates to true. If items.floorplan[x] exists, then it will be that node, and if it doesn't I provide a default object with an empty url property on the right hand side, and then just use the url from the resulting object.
In the third, I use the optional chaining operator that was introduced in 2020. This method will return undefined if the url doesn't exist.
In the fourth example, I use destructuring to pull values out of the items variable, and make sure that there is a default value for url in case the items variable doesn't have a corresponding value.
But there are many more ways to go about it. These are just a few, and you can't necessarily say which approach is better. It's dependent on your intent and environment. With the exception of optional chaining (which shows undefined if the property doesn't exist), you can see these produce the same results.
DOCS for optional chaining: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
DOCS for destructuring: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
An article on destructuring: https://javascript.info/destructuring-assignment

How to access data inside a complex JSON object in Dart?

I use a WebSocket to communicate to a server in my Flutter app. Let's say I receive a JSON object trough the WebSocket :
{
"action": "getProduct",
"cbackid": 1521474231306,
"datas": {
"product": {
"Actif": 1,
"AfficheQte": 0,
"Article": "6"
},
"result": "success"
},
"deviceID": "4340a8fdc126bb59"
}
I have no idea what the content of datas will be until I read the action, and even then, it's not guaranteed to be the same every time. One example of a changing action/datas is when the product doesn't exist.
I can parse it in a Map<String, Object>, but then, how do I access what's inside the Object?
What's the correct way to read this data?
Not sure what the question is about, but you can check the type of the values and then continue accordingly
if(json['action'] == 'getProduct') {
var datas = json['datas'];
if(datas is List) {
var items = datas as List;
for(var item in items) {
print('list item: $item');
}
} else if (datas is Map) {
var items = datas as Map;
for(var key in items.keys) {
print('map item: $key, ${items[key]}');
}
} else if(datas is String) {
print('datas: $datas');
} // ... similar for all other possible types like `int`, `double`, `bool`, ...
}
You also can make that recursive to check list or map values if they are String, ...

Parsing nested arrays in JSON data swift

I'm currently working with trying to extract bits of information from a complicated json based database. After NSJSONSerialization.JSONObjectWithData I get output like follows (some returns added for clarity)
[
"title": Recorder Suite In A Minor - Viola Concerto - Tafelmusik,
"estimated_weight": 85,
"year": 0,
"thumb": ,
"identifiers": <__NSArrayI 0x600000089970>(
{
description = Text;
type = Barcode;
value = 4891030501560;
},
{
description = Printed;
type = Barcode;
value = "4 891030 501560";
},
{
type = ASIN;
value = B0000013L9;
},
{
type = "Mould SID Code";
value = "ifpi 8412";
},
{
type = "Matrix / Runout";
value = "CD PLANT AB 8550156 CDM01";
},
{
description = "SPARS Code";
type = Other;
value = DDD;
},
{
type = "Label Code";
value = "LC 9158";
}
),
"id": 885370,
"date_changed": 2014-06-17T03:53:03-07:00,
"master_url": https://api.discogs.com/masters/495830,
etc … ]
In particular, I need to know how to get the information out of the nested array. Note that the array is not (obviously) a nested dictionary - given the equal signs and the repeated keys. Any help with how to parse this would be appreciated.
I would use a Pod like SwiftyJSON.
First, you need to install CocoaPods, and then go for SwiftyJSON.
I would parse nested arrays in the following manner:
let json = JSON(data: dataFromNetworking)
if let items = json["items"].array {
for item in items {
if let title = item["title"].string {
println(title)
}
}
}
Check out the documentation and Usage section of SwiftyJSON for more info.
Cheers...

Collapsible Tree Hierarchy d3

It was stated that d3 does not take any specific data fromat whether it be json or csv. But I have noticed some odd behavoirs.
In this example http://bl.ocks.org/mbostock/4339083, the input file is json so
d3.json("/d/4063550/flare.json", function(error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse); //?
update(root);
});
In this example, it is a csv file that is loaded
d3.csv("FederalBudget_2013_a.csv", function(csv) {
var data=[];
//Remove all zero values nodes
csv.forEach(function (d) {
var t=0;
for (var i=0; i < sumFields.length; i++) {
t+= Number(d[sumFields[i]]);
}
if (t > 0) {
data.push(d);
}
})
var nest = d3.nest()
.key(function(d) { return d.Level1; })
.key(function(d) { return d.Level2; })
.key(function(d) { return d.Level3; })
.entries(data);
root={};
root.values=nest;
root.x0 = h / 2;
root.y0 = 0;
var nodes = tree.nodes(root).reverse(); //?
tree.children(function (d){ return d.children;}); //?
update(root);
});
Please clarify as to why there are different approaches where I placed a quesiton mark. I tried to see in the second example the children but that returned nothing.
Thank you.
It's true that d3 can use a wide range of data formats, but the examples you provide are attempting to do something different because of the way that each of the data types provided are configured.
The json file in the first example is configured in a hierarchy that represents the type of data that a tree diagram can use straight away, but the csv data is 'flat' in the sense that it hasn't been formed into an arrangement of parent / child relationships in a tree form.
For instance, the following is a 'flat' data structure where a range of named nodes each has a parent.
name,parent
"Level 2: A","Top Level"
"Top Level", "null"
"Son of A","Level 2: A"
"Daughter of A","Level 2: A"
"Level 2: B","Top Level"
The following is the same data encoded with the relationships expressed in a hierarchy (as the json equivalent).
[
{
"name": "Top Level",
"parent": "null",
"children": [
{
"name": "Level 2: A",
"parent": "Top Level",
"children": [
{
"name": "Son of A",
"parent": "Level 2: A"
},
{
"name": "Daughter of A",
"parent": "Level 2: A"
}
]
},
{
"name": "Level 2: B",
"parent": "Top Level"
}
]
}
]
The graphical equivalent is as follows;
It may be useful to have a look over this blog post that explains both type of input and a few other implementations
To clarify in the BrightPoint example, using the d3.nest() function takes the flat CSV data and creates a hierarchy based on the .key values (in this case column names in the flat CSV data.) This is where the children are created.
Ideally your back end service can create JSON formatted data, but often times you have to manipulate the data client side to get it into a digestible format.

NVD3 multi bar chart with json?

I'm trying to load json into NVD3's multi bar chart, but can't get it to render the values that I'm including. I'm not sure what "stream_layers" is doing, either.
It is similar to this (http://nvd3.org/ghpages/multiBar.html), but should render a series of "mini" graphs next to each other, rather than one large graph of all the combined values. NVD3 calls this multiBarChart.html in their example files. I can get a blank graph to show up, but I can't get it to pull the values.
var test_data = [{
"key" : "MT_ATTEMPTED",
//"bar": true,
"values" : [4505891, 20130620, 6636631]
}, {
"key" : "MT_SUCCESS",
"values" : [4505891, 20130620, 6636631]
}, {
"key" : "MO_ATTEMPTED",
"values" : [4505891, 20130620, 6636631]
}].map(function(series) {
series.values = series.values.map(function(d) {
return {
x : stream_layers(3, 3, .1),
y : d[1]
}
});
return series;
});
Need to have key/value pairs within a top level key.
Also:
.map(function(series) {
series.values = series.values.map(function(d) { return {x: d.label, y: d.value } });
return series;