I have a string that I need to parse into a graph (DAG) data structure using javascript. Included in the data structure are a few attributes I should store, such as the node's id, name, and a label that is given to the link if one exists to another node. So, an example would be
Node1 (id: 1, name: 'first') --('link name')--> Node2 (id:....)
and so forth. Once the data structure is created I do not need to do any more operations on it other than read it (I will later use it to render a visualization with d3). The amount of nodes will not be very many, as several of them are shared.
I am imagining an adjacency list but am not sure how I would encode that in javascript. For instance, I know a json object can have a "field" : "value" structure but can I do that with Object : [list of adjacent Objects]?
you can use lists (arrays) in json. E.g. I could represent a simple directed graph as
{
"NodeA": {"name": "NodeA", "adjacentTo": ["NodeB", "NodeC"]},
"NodeB": {"name": "NodeB", "adjacentTo": ["NodeC", "NodeD"]},
"NodeC": {"name": "NodeC", "adjacentTo": ["NodeA"]},
"NodeD": {"name": "NodeD", "adjacentTo": []}
}
This would be the graph:
C
^^
| \
| \
A -> B -> D
The name field really isn't needed, but you can associate any attributes you want with a node that way.
JavaScript objects must have string keys, but can store any type of value. Of course, the entire point in an id is to allow you to represent a complex type wirh a simple one.
var adjacentTo = {};
adjacentTo[node1.id] = [node2, node3]
Related
I have an array called values. At present, I'm appending new data to this array as such:
values.push(guests);
The result of my array is something like this:
["123456789", "Joe", "Bloggs", "Test Corp", "fiji", true, "guest, guest 2, guest 3", true]
I have now realised that in its present state this data is useless to me as I cannot tell what each element is. In my example above, the first long number is an account number and the second element is a first name but these are liable to change. E.g the company name Test Corp may not always exist in the data. This means I cannot use the numerical key [3] to target it because it may not be present.
Therefore I need to code this data into something that I can assign both a label for the data, and the data value. I'm guessing the best way to do this would be with an JSON object.
How can I create a key->value pair object? I would need to replace my .push() code above to instead add the value of COMPANY NAME -> Test Corp so that it can be deciphered later.
For reference, I am then stringifying this data and using an AJAX request to POST it to a PHP script where it will need to be arranged into variables e.g $company_name = 'Test Corp';
You're talking about a plain JavaScript object. JSON is a transfer format inspired by JavaScript syntax.
To make an object, just initialize a variable:
var values = {};
And add properties:
values.accountNumber = "123456789";
values.firstName = "Joe";
etc. If you know the properties up front and have values available, you can make the object in one step:
var values = {
accountNumber: "12345678",
firstName: "Joe",
// ...
};
I am currently working with the Treemap visualization of D3.js and was hoping to understand how the flare.json used in the example has been organized. Does the format of the json input file need to be in the exact same structure as used in the example. I have an input file from a web crawler with a list of URLs and their respective parent URLs. I tried using something like the following but it won't work and am not sure if it's just the structure that's different or something else.
listURLs.json:
{
"name": "flare",
"children": [
{"children":"http:\/\/a.wholelottanothing.org","name":"http:\/\/buzz.blogger.com"},
{"children":"http:\/\/www.bitworking.org","name":"http:\/\/buzz.blogger.com"},
{"children":"http:\/\/blog.computationalcomplexity.org","name":"http:\/\/buzz.blogger.com"},
{"children":"http:\/\/www.blogactionday.org","name":"http:\/\/buzz.blogger.com"},
{"children":"http:\/\/www.wikipaintings.org","name":"http:\/\/littlegreeniguana.blogspot.com"}
]
}
I know this looks very different from the flare.json used in the example but can this work? Also, the input that I am using doesn't include the 'size' parameter which is also probably why the output is blank. How do I use the size here? Can it be dynamically adjusted later in the code? Any help will be most appreciated, I am a D3 novie!
The hierarchical data format expected by tree, pack and other D3 hierarchical layouts is expecting "children" to be an array of objects, and traverses that hierarchical data in preparation for formatting your objects for display using layouts. So, you don't want to use "children" to store a single link, instead, you want it to store an array of objects formatted just like the parent object (even if there is only one thing in that array). It's a bit hard to grasp what you're trying to display in your dataset, but my guess is all those websites are under buzz.blogger.com, except the last one, in which case properly formatted hierarchical data would look like this (Note that everything is nested in a root node, which you can name whatever you want):
{
"name": "root node",
"children": [
{"name":"http:\/\/buzz.blogger.com", "children": [
{"name": "http:\/\/www.bitworking.org"},
{"name": "http:\/\/blog.computationalcomplexity.org"},
{"name": "http:\/\/www.blogactionday.org"}
]
},
{"name":"http:\/\/littlegreeniguana.blogspot.com", "children": [
{"name": "http:\/\/www.wikipaintings.org"}
]
}
]
}
I am working on a Javascript web application (SPA) with RESTful api on the back-end. In my client-side datacontext I want to add objects to my model graph and then send the whole graph to server at once.
Suppose the following example:
I have a Person object in my model which itself has an array of say PhoneNumbers as a property. Now I load a Person from api for edditing and map it to my model. Suppose I want to add some phone number objects to my PhoneNumbers. For this I add each number e.g. {"id": 0, "number": 6536652226} with an id of zero to my client model and send the whole graph to server when user clicks save. In server I add the objects with the id of zero (new objects) to database with auto-incremented ids.
I am doing my project based on a tutorial. They do something like this to add objects to context:
var items = {},
// returns the model item produced by merging json obj into context
mapJsonToContext = function (json) {
var id = mapper.getJsonId(json);
var existingItem = items[id];
items[id] = mapper.fromDto(json, existingItem); //returns the mapped obj
return items[id];
},
add = function (newObj) {
items[newObj.id()] = newObj;
}
The problem is that if I use this method I wouldn't be able to remove by id the newly-added-not-yet-saved items in client-side 'cause all the ids are zero!
Any suggestions to fix this, or do I need a totally different approach?
First of all, two little misconceptions I've spot:
1) Forget about "associative arrays". Numeric arrays are the only kind arrays you have; the other constructs are just "objects" (this is not PHP).
2) If it's JSON it's a string, not an object.
Other than that, you can of course use an arbitrary value to represent "new" (though I'd probably use null rather than 0) as soon as you don't use such value to uniquely identify the yet-to-add item. E.g., this is just fine:
[
{"id": 0, "number": "6536652226"},
{"id": 0, "number": "9876543210"},
{"id": 0, "number": "0123456789"}
]
This is not:
// WRONG!!!!
{
0: "6536652226",
0: "9876543210",
0: "0123456789"
}
}
And of course you cannot find numbers by ID if they still don't have an ID. You need to choose:
Retrieve the generated ID from DB and update your local data
Delete by number
Create a localId property on newly created client-side objects, and use that as your key when reconciling server returned-data. Obviously the server would have to return this localId to you.
While following numerous D3 examples, data usually gets formatted in the format given in flare.json:
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
:
I have an adjacency list as follows:
A1 A2
A2 A3
A2 A4
which I want to convert to the above format. Currently, I am doing this on the server-side but is there a way to achieve this using d3's functions? I found one here, but the approach seems to require modification of the d3 core library which I am not in favor due to maintainability. Any suggestions?
There's no prescribed format, as you can usually redefine your data through various accessor functions (such as hierarchy.children) and array.map. But the format you quoted is probably the most convenient representation for trees because it works with the default accessors.
The first question is whether you intend to display a graph or a tree. For graphs, the data structure is defined in terms of nodes and links. For trees, the input to the layout is the root node, which may have an array of child nodes, and whose leaf nodes have an associated value.
If you want to display a graph, and all you have is a list of edges, then you'll want to iterate over the edges in order to produce an array of nodes and an array of links. Say you had a file called "graph.csv":
source,target
A1,A2
A2,A3
A2,A4
You could load this file using d3.csv and then produce an array of nodes and links:
d3.csv("graph.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.source);
link.target = nodeByName(link.target);
});
// Extract the array of nodes from the map by name.
var nodes = d3.values(nodeByName);
function nodeByName(name) {
return nodesByName[name] || (nodesByName[name] = {name: name});
}
});
You can then pass these nodes and links to the force layout to visualize the graph:
http://bl.ocks.org/2949937
If you want to produce a tree instead, then you'll need to do a slightly different form of data transformation to accumulate the child nodes for each parent.
d3.csv("graph.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
var parent = link.source = nodeByName(link.source),
child = link.target = nodeByName(link.target);
if (parent.children) parent.children.push(child);
else parent.children = [child];
});
// Extract the root node.
var root = links[0].source;
function nodeByName(name) {
return nodesByName[name] || (nodesByName[name] = {name: name});
}
});
Like so:
http://bl.ocks.org/2949981
D3 doesn't require a specific format. It all depends on your application. You can certainly convert an adjacency list to the format used in flare.json, but this again would be application-specific code. In general, you can't do that as adjacency lists as such don't have "head" or "root" elements you would need to build a tree. In addition, you would need to handle cycles, orphans etc. separately.
Given that you're currently doing the conversion on the server side, I'd be tempted to say that "if it ain't broken, don't fix it" ;)
I receive an object from MongoDB request.
Below is a snippet of it:
{
"Kost": "Kost1",
"Name": "Name1",
"inventar": [
{
"data": "A",
"name": "thefirst",
"ean": "802.0165.813",
},
{
"ean": "802.6725.277",
"name": "thesecond",
"data": "B",
},
{
"ean": "570.6761.483",
"name": "thethird",
"data": "C",
},
{
"ean": "570.6764.519",
"name": "thefourth",
"data": "D",
}
]
}
Later, I will create a table in Jade with this code:
table(border='1', cellspacing='3', cellpadding='4')
tr
th(align='center') ean
th(align='center') name
th(align='center') data
each obj in inventar
tr
each val in obj
td= val
The problem is, that the objects in the Array "inventar" are not sorted. The table has a wrong structure. The current output of the table looks like:
|ean | name | data
--------------------------------------------
|802.0165.813| thefirst | A
|B | thesecond | 802.6725.277
|C | thethird | 570.6761.483
|D | thefourth | 570.6764.519
The first column must be the ean, second the name and third the data. Only the first row is correct. I think its luck.
Its possible to sort the objects in the Array ("inventar") before iterating over it, to get the right structure?
I read somewhere that it is not possible to sort directly in mongoose.
thanks in advance
It appears you are asking about the property order in the object. In ES5 and earlier, properties have NO deterministic order by specification. There are some implementations that will maintain the order the properties were created in, but that was not guaranteed.
In ES6, the spec has been changed to say that properties will remain in the order they are created. But, there is no mechanism for reordering properties on an existing object. If you want to change the order, the work-around would be to create a new object, copy the properties over in the desired order and then replace the original object with the new one.
All that said, normal coding should not care what order the properties are in. You refer to a property on an object as in x.inventar[0].data and it should not matter whether data is the first or last property when you dump the object contents.
Given what you are showing in your sample table, it appears that some piece of code is grabbing the first property and putting it in the first column. That is the wrong way to build the table. Instead, it should grab a specific property name and then the order of the properties on the object simply will not matter. So, I think what you need to do is to fix your jade definition to refer to specific property names, not to just take them in order.
I don't know Jade very well myself, but I think you can do something like this:
table(border='1', cellspacing='3', cellpadding='4')
tr
th(align='center') ean
th(align='center') name
th(align='center') data
each obj in inventar
tr
//edited syntax
td= obj.ean
td= obj.name
td= obj.data