Chet
Chet

Reputation: 19879

Hierarchical Edge Bundling from Force Layout in D3

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.

Upvotes: 4

Views: 2493

Answers (3)

Derek Xiao
Derek Xiao

Reputation: 1

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

Upvotes: 0

VividD
VividD

Reputation: 10536

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"
        ]
      }
    ]

Upvotes: 2

Jake F.
Jake F.

Reputation: 21

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).

Upvotes: 2

Related Questions