4

I currently have a Force Layout:

http://bl.ocks.org/mbostock/4062045

So my data is simply nodes and links, but I'd like to create this Hierarchical Edge Bundling with the same data:

http://bl.ocks.org/mbostock/7607999

enter image description here

I'm having issues because my data isn't hierarchical. Its just nodes and links. I'm not sure how to make this work, but it must be possible.

VividD
  • 10,456
  • 6
  • 64
  • 111
Chet
  • 18,421
  • 15
  • 69
  • 113
  • Hi Chet, you've included links to Bostock's examples, and state you are having issues. What issues? How is your data different from those examples? – Fiver Mar 22 '14 at 00:34
  • My data isn't hierarchical. Just nodes and undirected links – Chet Mar 23 '14 at 04:38

3 Answers3

2

Hierarchical Edge Bundling requires that there be a hierarchy. It can even be arbitrary but without it there is no way to create the bundling effect. The bundling is determined by the hierarchies (elements with the same parent will bundle the same way).

Jake F.
  • 21
  • 2
2

I believe the best approach would be to modify the data you have before applying bundle layout.

Specifically, you should be able to introduce a fictional root to make your data hierarchical. The root node could be:

a) parent for all nodes in your current data that have at least one child

or

b) parent for all nodes in your current data that do not have a parent.

What is better depends on your case (data/application).

While converting the data, you need to take care of two things on top of that: make sure your original data does not have cycles (that would prevent converting it to hierarchy), and you need to follow data format for bundle layout (for example, see json file http://bl.ocks.org/mbostock/raw/1044242/readme-flare-imports.json).

    [
      {
        "name":"flare.analytics.cluster.AgglomerativeCluster",
        "size":3938,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.data.DataList",
          "flare.util.math.IMatrix",
          "flare.analytics.cluster.MergeEdge",
          "flare.analytics.cluster.HierarchicalCluster",
          "flare.vis.data.Data"
        ]
      },
      {
        "name":"flare.analytics.cluster.CommunityStructure",
        "size":3812,
        "imports":[
          "flare.analytics.cluster.HierarchicalCluster",
          "flare.animate.Transitioner",
          "flare.vis.data.DataList",
          "flare.analytics.cluster.MergeEdge",
          "flare.util.math.IMatrix"
        ]
      },
      {
        "name":"flare.analytics.cluster.HierarchicalCluster",
        "size":6714,
        "imports":[
          "flare.vis.data.EdgeSprite",
          "flare.vis.data.NodeSprite",
          "flare.vis.data.DataList",
          "flare.vis.data.Tree",
          "flare.util.Arrays",
          "flare.analytics.cluster.MergeEdge",
          "flare.util.Sort",
          "flare.vis.operator.Operator",
          "flare.util.Property",
          "flare.vis.data.Data"
        ]
      },
      {
        "name":"flare.analytics.cluster.MergeEdge",
        "size":743,
        "imports":[

        ]
      },
      {
        "name":"flare.analytics.graph.BetweennessCentrality",
        "size":3534,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.data.NodeSprite",
          "flare.vis.data.DataList",
          "flare.util.Arrays",
          "flare.vis.data.Data",
          "flare.util.Property",
          "flare.vis.operator.Operator"
        ]
      },
      {
        "name":"flare.analytics.graph.LinkDistance",
        "size":5731,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.data.NodeSprite",
          "flare.vis.data.EdgeSprite",
          "flare.analytics.graph.ShortestPaths",
          "flare.vis.data.Data",
          "flare.util.Property",
          "flare.vis.operator.Operator"
        ]
      },
      {
        "name":"flare.analytics.graph.MaxFlowMinCut",
        "size":7840,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.data.NodeSprite",
          "flare.vis.data.EdgeSprite",
          "flare.vis.data.Data",
          "flare.util.Property",
          "flare.vis.operator.Operator"
        ]
      },
      {
        "name":"flare.analytics.graph.ShortestPaths",
        "size":5914,
        "imports":[
          "flare.vis.data.EdgeSprite",
          "flare.vis.data.NodeSprite",
          "flare.animate.Transitioner",
          "flare.vis.operator.Operator",
          "flare.util.heap.HeapNode",
          "flare.util.heap.FibonacciHeap",
          "flare.util.Property",
          "flare.vis.data.Data"
        ]
      },
      {
        "name":"flare.analytics.graph.SpanningTree",
        "size":3416,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.data.NodeSprite",
          "flare.vis.operator.IOperator",
          "flare.vis.Visualization",
          "flare.vis.data.TreeBuilder",
          "flare.vis.operator.Operator"
        ]
      },
      {
        "name":"flare.analytics.optimization.AspectRatioBanker",
        "size":7074,
        "imports":[
          "flare.animate.Transitioner",
          "flare.util.Arrays",
          "flare.vis.data.DataSprite",
          "flare.scale.Scale",
          "flare.vis.axis.CartesianAxes",
          "flare.vis.Visualization",
          "flare.util.Property",
          "flare.vis.operator.Operator"
        ]
      },
      {
        "name":"flare.animate.Easing",
        "size":17010,
        "imports":[
          "flare.animate.Transition"
        ]
      },
      {
        "name":"flare.animate.FunctionSequence",
        "size":5842,
        "imports":[
          "flare.util.Maths",
          "flare.animate.Transition",
          "flare.util.Arrays",
          "flare.animate.Sequence",
          "flare.animate.Transitioner"
        ]
      },
      {
        "name":"flare.animate.interpolate.ArrayInterpolator",
        "size":1983,
        "imports":[
          "flare.util.Arrays",
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.ColorInterpolator",
        "size":2047,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.DateInterpolator",
        "size":1375,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.Interpolator",
        "size":8746,
        "imports":[
          "flare.animate.interpolate.NumberInterpolator",
          "flare.animate.interpolate.ColorInterpolator",
          "flare.animate.interpolate.PointInterpolator",
          "flare.animate.interpolate.ObjectInterpolator",
          "flare.animate.interpolate.MatrixInterpolator",
          "flare.animate.interpolate.RectangleInterpolator",
          "flare.animate.interpolate.DateInterpolator",
          "flare.util.Property",
          "flare.animate.interpolate.ArrayInterpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.MatrixInterpolator",
        "size":2202,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.NumberInterpolator",
        "size":1382,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.ObjectInterpolator",
        "size":1629,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.PointInterpolator",
        "size":1675,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.interpolate.RectangleInterpolator",
        "size":2042,
        "imports":[
          "flare.animate.interpolate.Interpolator"
        ]
      },
      {
        "name":"flare.animate.ISchedulable",
        "size":1041,
        "imports":[
          "flare.animate.Scheduler"
        ]
      },
      {
        "name":"flare.animate.Parallel",
        "size":5176,
        "imports":[
          "flare.animate.Easing",
          "flare.animate.Transition",
          "flare.util.Arrays"
        ]
      },
      {
        "name":"flare.animate.Pause",
        "size":449,
        "imports":[
          "flare.animate.Transition"
        ]
      },
      {
        "name":"flare.animate.Scheduler",
        "size":5593,
        "imports":[
          "flare.animate.ISchedulable",
          "flare.animate.Pause",
          "flare.animate.Transition"
        ]
      },
      {
        "name":"flare.animate.Sequence",
        "size":5534,
        "imports":[
          "flare.animate.Easing",
          "flare.util.Maths",
          "flare.animate.Transition",
          "flare.util.Arrays"
        ]
      },
      {
        "name":"flare.animate.Transition",
        "size":9201,
        "imports":[
          "flare.animate.Transitioner",
          "flare.animate.TransitionEvent",
          "flare.animate.Scheduler",
          "flare.animate.Pause",
          "flare.animate.Parallel",
          "flare.animate.Easing",
          "flare.animate.Sequence",
          "flare.animate.ISchedulable",
          "flare.util.Maths",
          "flare.animate.Tween"
        ]
      },
      {
        "name":"flare.animate.Transitioner",
        "size":19975,
        "imports":[
          "flare.util.IValueProxy",
          "flare.animate.Parallel",
          "flare.animate.Easing",
          "flare.animate.Sequence",
          "flare.animate.Transition",
          "flare.animate.Tween",
          "flare.util.Property"
        ]
      },
      {
        "name":"flare.animate.TransitionEvent",
        "size":1116,
        "imports":[
          "flare.animate.Transition"
        ]
      },
      {
        "name":"flare.animate.Tween",
        "size":6006,
        "imports":[
          "flare.animate.Transitioner",
          "flare.animate.Transition",
          "flare.animate.interpolate.Interpolator",
          "flare.util.Property"
        ]
      },
      {
        "name":"flare.data.converters.Converters",
        "size":721,
        "imports":[
          "flare.data.converters.IDataConverter",
          "flare.data.converters.GraphMLConverter",
          "flare.data.converters.JSONConverter",
          "flare.data.converters.DelimitedTextConverter"
        ]
      },
      {
        "name":"flare.data.converters.DelimitedTextConverter",
        "size":4294,
        "imports":[
          "flare.data.DataSet",
          "flare.data.DataUtil",
          "flare.data.DataTable",
          "flare.data.converters.IDataConverter",
          "flare.data.DataSchema",
          "flare.data.DataField"
        ]
      },
      {
        "name":"flare.data.converters.GraphMLConverter",
        "size":9800,
        "imports":[
          "flare.data.DataSet",
          "flare.data.DataUtil",
          "flare.data.DataTable",
          "flare.data.converters.IDataConverter",
          "flare.data.DataSchema",
          "flare.data.DataField"
        ]
      },
      {
        "name":"flare.data.converters.IDataConverter",
        "size":1314,
        "imports":[
          "flare.data.DataSet",
          "flare.data.DataSchema"
        ]
      },
      {
        "name":"flare.data.converters.JSONConverter",
        "size":2220,
        "imports":[
          "flare.data.DataSet",
          "flare.data.DataUtil",
          "flare.data.DataTable",
          "flare.data.converters.IDataConverter",
          "flare.data.DataSchema",
          "flare.data.DataField",
          "flare.util.Property"
        ]
      },
      {
        "name":"flare.data.DataField",
        "size":1759,
        "imports":[
          "flare.data.DataUtil"
        ]
      },
      {
        "name":"flare.data.DataSchema",
        "size":2165,
        "imports":[
          "flare.data.DataField",
          "flare.util.Arrays"
        ]
      },
.
.
.
      {
        "name":"flare.vis.Visualization",
        "size":16540,
        "imports":[
          "flare.animate.Transitioner",
          "flare.vis.operator.IOperator",
          "flare.animate.Scheduler",
          "flare.vis.events.VisualizationEvent",
          "flare.vis.data.Tree",
          "flare.vis.events.DataEvent",
          "flare.vis.axis.Axes",
          "flare.vis.axis.CartesianAxes",
          "flare.util.Displays",
          "flare.vis.operator.OperatorList",
          "flare.vis.controls.ControlList",
          "flare.animate.ISchedulable",
          "flare.vis.data.Data"
        ]
      }
    ]
VividD
  • 10,456
  • 6
  • 64
  • 111
0

Build external parent nodes based on the group attribute of the nodes. The whole graph consists of three levels: root, parent nodes of each group, leaf nodes(real nodes).

Please take a look at function gen_fake_data, which hopefully helps u gain a better understanding.

P.S. the code may not work at jsfiddle, but works at my local environment.

https://jsfiddle.net/6rcc3n2e/

results of my randomly generated data