How to convert to D3's JSON format?

26,509

Solution 1

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:

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:

Solution 2

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" ;)

Share:
26,509
Legend
Author by

Legend

Just a simple guy :)

Updated on June 16, 2020

Comments

  • Legend
    Legend almost 4 years

    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?