Getting data from json file for D3 bubble chart - javascript

I'm trying to create a bubble chart based on the example from the d3 wiki. http://bl.ocks.org/mbostock/4063269
Unfortunately I'm still at the beginner level of javascript and don't understand some of the code.
The layout of json is here: http://pastebin.com/QAMBfLjr
I want to create circles and name them after the value and have their size be based on count.
It seems the piece of code I need to modify is this:
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
else classes.push({packageName: name, className: node.name, value: node.size});
}
So I'm substituting instances of children for the path to what I want to iterate over in the json. Then I change the name of the keys I want.
facet_counts.facet_pivot["category_level0,category_level1,category_level2,category_level3"]
So that piece of code looks like:
function recurse(name, node) {
if (node.facet_counts.facet_pivot["category_level0,category_level1,category_level2,category_level3"]) node.facet_counts.facet_pivot["category_level0,category_level1,category_level2,category_level3"].forEach(function(child) { recurse(node.value, child); });
else classes.push({packageName: value, className: node.value, value: node.count});
}
But that's not working. I don't see anything on the page and the console output says:
Uncaught TypeError: Cannot read property 'facet_pivot' of undefined
Can someone help point me in the right direction?
Thanks!
Adding jsfiddle: http://jsfiddle.net/jwhite/4o6tbe0w/

So I figured this out. I didn't see that the json file I'm using is in a different format from the one that is supplied with the example.
After playing around a bit in the dev console I figured out I had to edit the processData function to the following:
function processData(data) {
var obj = data.facet_counts.facet_pivot["category_level0,category_level1,category_level2,category_level3"];
var newDataSet = [];
for(var prop in obj) {
newDataSet.push({name: obj[prop].value, className: obj[prop].value.toLowerCase(), size: obj[prop].count});
}
return {children: newDataSet};
}

Related

Javascript: How to call a method from a constructor? My variable returns Undefined

I am creating a javascript class to handle SVG tags in HTML. (I know that there are plenty of classes that does this already but I did not succeed with transformations via svg.js. Also, I have made all the required functions to work and I just want to implement them as a class for syntactical ease.)
However, not being that familiar with javascript, I have trouble with a variable that is set to Undefined in my constructor:
class SLD {
constructor(container,x=1000, y=1000) {
this.ctn = document.getElementById(container);
this.svgobj = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
// Defining object attributes
var obj = {
'width': "1000",
'height': "1000",
'xmlns':"http://www.w3.org/2000/svg",
'version':"1.1",
'xmlns:xlink':"http://www.w3.org/1999/xlink"
};
// Setting attribute via for loop
for(prop in obj) {
this.svgobj.setAttribute(prop, obj[prop])
}
}
While trying to run it, I am returned the following error code:
How do I define the variable properly? I am using Chrome (version 83.0.4103.116) and the browser supports classes as far as I am noticed.
Let me know if I should provide any other relevant information.
I assume prop hasn't been declared yet so you'll need to use var.
for(var prop in obj) {
this.svgobj.setAttribute(prop, obj[prop])
}
You could try this:
for (const prop in obj) {
this.svgobj.setAttribute(prop, obj[prop]);
}
Variable declaration was your problem.
Your code could be optimized by replacing the for loop with:
Object.entries({
'width': "20",
'height': "20",
'xmlns':"http://www.w3.org/2000/svg",
'version':"1.1",
'xmlns:xlink':"http://www.w3.org/1999/xlink"
}).forEach(([prop,value])=>svgobj.setAttribute(prop, value));

How made a deep copy that can resolve a problem with a table

Im using the table material-table, where the set a new element to my object, called tableData. So that feature create an issues to my code and API because I update using Patch. I implemented a conventional and also custom deep copy of my object to avoid the table add this element to my object.
But for some reason it isnt working. This is an example of the table where you can see how it added the tableData to the example object. https://codesandbox.io/s/lx2v9pn91m Please check the console
Above I showed the real object, and in the element 5 array, appear the tableData after each render. Extra comment, the property of the table I passed to table is: data={MyRealObject.element5}
This is the struct of my real object:
MyRealObject{
element1: boolean,
element2: boolean ,
element3: Array ,
element4: Array ,
Cards: Array ,
}
Card{
Id: number ,
CardNumber : number ,
CardFormat : {CardFormatObject},
//here where appear the tableData after each render
}
CardFormatObject{
Id: number ,
CardNumberLength : number ,
CardFormatLength : number ,
Default:boolean ,
Name: string ,
}
This is the lastest custom deep copy I did and didnt work:
deepcopy(MyRealObject:MyRealObject):MyRealObject{
let salvaCard=[]
for(let i=0;i<user.Cards.length;i++){
salvaCard[i]=this.deepCardCopy(MyRealObject.Cards[i])
}
return{
element1: MyRealObject.element1,
element2: MyRealObject.element2,
element3: [...MyRealObject.element3], //I know here is not deep but isnt important now, and it isnt affected
element4: [...MyRealObject.element4],
Cards: salvaCard,
}as MyRealObject
}
public deepCardCopy(card:Card):Card{
return {
Id:card.Id,
CardNumber:card.CardNumber,
CardFormat:{...card.CardFormat}
} as Card;
}
//////////////////////////////
This are others deep code that I used and dont works, I share to save you time:
--------old solution 1(i dont like it, you can lose element if there are null)------------------------------------------------
// Cards: JSON.parse(JSON.stringify(MyRealObject.Cards)),
---------old solution 2-------------------------------------------
// MyRealObject.Cards.map(card=>{
// const {tableData,...record}=card
// return record
// }),
setState is an async function. That means you won't see the result right after calling it. You have to wait for setState to be finished. There is a callback-Parameter in setState which you can use to get the result of this.state
handleSelectedID = rowData => {
const selectedID = rowData.map(item => item.id);
this.setState({ selectedID }, () => {
// setState is async
// this is the callback
console.log(this.state.selectedID);
});
};
I changed your example-code a bit to give you an example of it: https://codesandbox.io/s/1olz33pmlj
I found a solutions, it is passsing the clone in the moment i passed the object to the table, for example:
data={MyRealObject.map(x => Object.assign({}, x))}
The issues was, that the people that create the table didnt make a clone to the data, the use the same reference, so it will be better do this to avoid problems that some one in the component didnt clone the object.
Kindly, noted, DONT used this way
data={...MyRealObject} or data={Object.assign({}, MyRealObject)}
The CORRECT is:
data={MyRealObject.map(x => Object.assign({}, x))}
Both expression look similiar but it isnot the same.

Iterate over an array of objects with object having multiple properties

I'm trying to iterate over the following:
state = {
products : [
{
x : "sd",
y : "fdg"
}, {
x : "sdx",
y : "fdgx"
}
]
}
I need to iterate over the above products array and inside object to create:
<tr><td>sd</td><td>fdg</td></tr>
I tried using :
{
this.state.products.map(function(prod) {
return <tr><td>{prod.x}</td><td>{prod.y}</td></tr>;
})
}
but get multiple errors and prod being undefined.
It's possible that logic elsewhere in your component is mutating the state, which in turn may be the root cause of the error thrown during rendering.
Be sure to check that the products array is consistently defined in your components state, and that the items in that array are defined.
One solution here might be to take a more defensive approach to rendering your table row elements, by doing the following:
{
Array.isArray(this.state.products) && this.state.products
.filter(product => !!product)
.map(product => {
return <tr><td>{product.x}</td><td>{product.y}</td></tr>;
})
}
Here, the rendering logic asserts that this.state.products is the expected array type via Array.isArray(). Addtionally, the logic ensures any prop being rendered is defined by first filtering out any undefined prop items via this line:
filter(product => !!product)
Hope that helps!
The problem is that the return statement is an HTML code which is causing the problem whereas you can encode the code into a string and the DOM will treat it as HTML code
this.state.products.map(function(prod){ return "<tr><td>"+prod.x+"</td><td>"+prod.y +"</td> </tr>" }).
you need to add that in one variable return as below:
const prod = this.state.products.map(function(prod) {
return <tr><td>{prod.x}</td><td>{prod.y}</td></tr>;
});
Use the variable inside render lifecycle as below.
{prod}
Here is the working code attached in jsFiddle
Hope this helps!

d3 force graph using node names for links

I've been at this for a few days now, and I've seen the questions on stackoverflow and other places, but I am missing something.
Lets say we have the following JSON:
{
"nodes":[
{"name":"node1"},
{"name":"node2"},
{"name":"node3"},
{"name":"node4"}
],
"links":[
{"source":"node1","target":"node2"},
{"source":"node1","target":"node3"},
{"source":"node1","target":"node4"}
]
}
Why do the following two pieces of code yield the same output in the console, but the second gives me an error (Uncaught TypeError: Cannot read property 'push' of undefined)?
links = links.map(function(l) {
var sourceNode = nodes.filter(function(n) { return n.name === l.source; })[0];
var targetNode = nodes.filter(function(n) { return n.name === l.target; })[0];
return {
source: sourceNode,
target: targetNode
};
});
_
links.forEach(function(link) {
link.source = {name: link.source};
link.target = {name: link.target};
});
Console output:
[{"source":{"name":"node1"},"target":{"name":"node2"}},
{"source":{"name":"node1"},"target":{"name":"node3"}},
{"source":{"name":"node1"},"target":{"name":"node4"}}]
There is one significant difference between results of the 2 code snippets.
The first one links source and target nodes by reference. They point to the objects in the nodes array.
The second one creates new objects. They have the same names as those in nodes but they are different objects in memory.
D3 force layout requires that links point to nodes by reference or by index in the array. If you specify indices they will by transformed to references anyway:
Note: the values of the source and target attributes may be initially specified as indexes into the nodes array; these will be replaced by references after the call to start.

JavaScript variable remains undefined

I am struggling with my webpage. The JavaScript isn't doing what it should because a variable[] isn't being populated! Please consider my code:
var datasets = { "DataItem1": {
label: "Idle Count",
dataSeries: [[13, 75.72],[13, 1],[13, 0.17],[13, 55.72],[13, 90.72],[13, 91.06]],
Threshold_0: [[134, 1],[133, 1]],
Threshold_2: [[133, 1],[131, 1]]
}
};
var data = [];
var failedData = [];
data.push(datasets['DataItem1']['dataSeries']);
failedData.push(datasets['DataItem1']['Threshold_0']['Threshold_2']);
});
The issue is with
failedData.push(datasets['DataItem1']['Threshold_0']['Threshold_2']);
Using firebug's watch window, I can see that failedData is undefined when I add a break at this point. So, I hover the mouse over the array items on this line, and Threshold_0 has data, but Threshold_2 does not (Threshold_2 is undefined).
In the watch window, I can see that datasets[] has created all the objects as expected.
I can't see why and I'm very stuck.
Here you are trying to access the property Threshold_2 through Threshold_0, you should get it through DataItem1
failedData.push(datasets['DataItem1']['Threshold_0']['Threshold_2']);
Becomes
failedData.push(datasets['DataItem1']['Threshold_2']);
The following properties do have a value:
datasets['DataItem1']['Threshold_0'][0] == [134, 1]
datasets['DataItem1']['Threshold_0'][1] == [133, 1]
I'm not sure what you actually want to do. Maybe this is what you intend to do?
failedData.push(datasets['DataItem1']['Threshold_0']);
failedData.push(datasets['DataItem1']['Threshold_2']);
Otherwise, please describe what value(s) you want to end up in failedData.
You have a typo at the end. Remove the last });

Categories

Resources