Skip to content

Instantly share code, notes, and snippets.

@micahstubbs
Last active April 12, 2016 01:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micahstubbs/5e07b8b42f4fb826a7145e800dc23ec2 to your computer and use it in GitHub Desktop.
Save micahstubbs/5e07b8b42f4fb826a7145e800dc23ec2 to your computer and use it in GitHub Desktop.
Bounded Force Layout - Columns by Depth
license: gpl-3.0
border: no

This example takes bjtucker's block: Bounded Force Layout - force rank by group and swaps out the dataset, showing energy flows from source to use.

This example also adds a Simple D3 tooltip. Hat tip to biovisualize for that bl.ock.

See another view of this energy flow data at the bl.ock Sankey Particles - Transparent Links


README.md from the original bl.ock


This D3 example shows how to constrain the position of nodes within the rectangular bounds of the containing SVG element. As a side-effect of updating the node's cx and cy attributes, we update the node positions to be within the range [radius, width - radius] for x, [radius, height - radius] for y. If you prefer, you could use the each operator to do this as a separate step, rather than as a side-effect of setting attributes.

Wrote the each operator step described above, but used tick to settle groups into separate ranks. -bjtucker

{
"nodes":[
{
"name":"Agricultural 'waste'",
"depth": 0
},
{
"name":"Bio-conversion",
"depth": 1
},
{
"name":"Liquid",
"depth": 2
},
{
"name":"Losses",
"depth": 7
},
{
"name":"Solid",
"depth": 2
},
{
"name":"Gas",
"depth": 2
},
{
"name":"Biofuel imports",
"depth": 0
},
{
"name":"Biomass imports",
"depth": 0
},
{
"name":"Coal imports",
"depth": 0
},
{
"name":"Coal",
"depth": 1
},
{
"name":"Coal reserves",
"depth": 0
},
{
"name":"District heating",
"depth": 4
},
{
"name":"Industry",
"depth": 7
},
{
"name":"Heating and cooling - commercial",
"depth": 7
},
{
"name":"Heating and cooling - homes",
"depth": 7
},
{
"name":"Electricity grid",
"depth": 4
},
{
"name":"Over generation / exports",
"depth": 7
},
{
"name":"H2 conversion",
"depth": 5
},
{
"name":"Road transport",
"depth": 7
},
{
"name":"Agriculture",
"depth": 7
},
{
"name":"Rail transport",
"depth": 7
},
{
"name":"Lighting & appliances - commercial",
"depth": 7
},
{
"name":"Lighting & appliances - homes",
"depth": 7
},
{
"name":"Gas imports",
"depth": 0
},
{
"name":"Ngas",
"depth": 1
},
{
"name":"Gas reserves",
"depth": 0
},
{
"name":"Thermal generation",
"depth": 3
},
{
"name":"Geothermal",
"depth": 0
},
{
"name":"H2",
"depth": 6
},
{
"name":"Hydro",
"depth": 0
},
{
"name":"International shipping",
"depth": 7
},
{
"name":"Domestic aviation",
"depth": 7
},
{
"name":"International aviation",
"depth": 7
},
{
"name":"National navigation",
"depth": 7
},
{
"name":"Marine algae",
"depth": 0
},
{
"name":"Nuclear",
"depth": 0
},
{
"name":"Oil imports",
"depth": 0
},
{
"name":"Oil",
"depth": 1
},
{
"name":"Oil reserves",
"depth": 0
},
{
"name":"Other waste",
"depth": 0
},
{
"name":"Pumped heat",
"depth": 0
},
{
"name":"Solar PV",
"depth": 1
},
{
"name":"Solar Thermal",
"depth": 1
},
{
"name":"Solar",
"depth": 0
},
{
"name":"Tidal",
"depth": 0
},
{
"name":"UK land based bioenergy",
"depth": 0
},
{
"name":"Wave",
"depth": 0
},
{
"name":"Wind",
"depth": 0
}
],
"links":[
{
"source":0,
"target":1,
"value":124.729
},
{
"source":1,
"target":2,
"value":0.597
},
{
"source":1,
"target":3,
"value":26.862
},
{
"source":1,
"target":4,
"value":280.322
},
{
"source":1,
"target":5,
"value":81.144
},
{
"source":6,
"target":2,
"value":35
},
{
"source":7,
"target":4,
"value":35
},
{
"source":8,
"target":9,
"value":11.606
},
{
"source":10,
"target":9,
"value":63.965
},
{
"source":9,
"target":4,
"value":75.571
},
{
"source":11,
"target":12,
"value":10.639
},
{
"source":11,
"target":13,
"value":22.505
},
{
"source":11,
"target":14,
"value":46.184
},
{
"source":15,
"target":16,
"value":104.453
},
{
"source":15,
"target":14,
"value":113.726
},
{
"source":15,
"target":17,
"value":27.14
},
{
"source":15,
"target":12,
"value":342.165
},
{
"source":15,
"target":18,
"value":37.797
},
{
"source":15,
"target":19,
"value":4.412
},
{
"source":15,
"target":13,
"value":40.858
},
{
"source":15,
"target":3,
"value":56.691
},
{
"source":15,
"target":20,
"value":7.863
},
{
"source":15,
"target":21,
"value":90.008
},
{
"source":15,
"target":22,
"value":93.494
},
{
"source":23,
"target":24,
"value":40.719
},
{
"source":25,
"target":24,
"value":82.233
},
{
"source":5,
"target":13,
"value":0.129
},
{
"source":5,
"target":3,
"value":1.401
},
{
"source":5,
"target":26,
"value":151.891
},
{
"source":5,
"target":19,
"value":2.096
},
{
"source":5,
"target":12,
"value":48.58
},
{
"source":27,
"target":15,
"value":7.013
},
{
"source":17,
"target":28,
"value":20.897
},
{
"source":17,
"target":3,
"value":6.242
},
{
"source":28,
"target":18,
"value":20.897
},
{
"source":29,
"target":15,
"value":6.995
},
{
"source":2,
"target":12,
"value":121.066
},
{
"source":2,
"target":30,
"value":128.69
},
{
"source":2,
"target":18,
"value":135.835
},
{
"source":2,
"target":31,
"value":14.458
},
{
"source":2,
"target":32,
"value":206.267
},
{
"source":2,
"target":19,
"value":3.64
},
{
"source":2,
"target":33,
"value":33.218
},
{
"source":2,
"target":20,
"value":4.413
},
{
"source":34,
"target":1,
"value":4.375
},
{
"source":24,
"target":5,
"value":122.952
},
{
"source":35,
"target":26,
"value":839.978
},
{
"source":36,
"target":37,
"value":504.287
},
{
"source":38,
"target":37,
"value":107.703
},
{
"source":37,
"target":2,
"value":611.99
},
{
"source":39,
"target":4,
"value":56.587
},
{
"source":39,
"target":1,
"value":77.81
},
{
"source":40,
"target":14,
"value":193.026
},
{
"source":40,
"target":13,
"value":70.672
},
{
"source":41,
"target":15,
"value":59.901
},
{
"source":42,
"target":14,
"value":19.263
},
{
"source":43,
"target":42,
"value":19.263
},
{
"source":43,
"target":41,
"value":59.901
},
{
"source":4,
"target":19,
"value":0.882
},
{
"source":4,
"target":26,
"value":400.12
},
{
"source":4,
"target":12,
"value":46.477
},
{
"source":26,
"target":15,
"value":525.531
},
{
"source":26,
"target":3,
"value":787.129
},
{
"source":26,
"target":11,
"value":79.329
},
{
"source":44,
"target":15,
"value":9.452
},
{
"source":45,
"target":1,
"value":182.01
},
{
"source":46,
"target":15,
"value":19.013
},
{
"source":47,
"target":15,
"value":289.366
}
]
}
<!DOCTYPE html>
<meta charset="utf-8">
<style>
circle {
stroke-width: 1.5px;
}
line {
stroke: #999;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
radius = 6;
var fill = d3.scale.category20();
var force = d3.layout.force()
.gravity(0.05)
.charge(-50) // -50
.linkDistance(50)
.size([width, height])
.linkStrength(0.005)
.friction(0.9)
.theta(0.8)
.alpha(0.1)
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append('rect')
.attr("width", width)
.attr("height", height)
.style({
fill: 'none',
stroke: 'none',
'stroke-width': 1
});
d3.json("graph.json", function(error, graph) {
if (error) throw error;
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden");
var link = svg.selectAll("line")
.data(graph.links)
.enter().append("line");
var node = svg.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", radius - .75)
.style("fill", function(d) { return fill(d.depth); })
.style("stroke", function(d) { return d3.rgb(fill(d.group)).darker(); })
.call(force.drag);
force
.nodes(graph.nodes)
.links(graph.links)
.on("tick", tick)
.start();
function tick() {
node.each(function(d) { w = 105 * (1 + d.depth); d.x -= (0.2 * (d.x - w)) })
node.attr("cx", function(d) {return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
.attr("cy", function(d) {return d.y = Math.max(radius, Math.min(height - radius, d.y)); });
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
node
.on("mouseover", function(d){
return tooltip
.text(d.name)
.style("visibility", "visible");
})
.on("mousemove", function(){
return tooltip
.style("top", (event.pageY - 10) + "px")
.style("left",(event.pageX + 10) + "px");
})
.on("mouseout", function(){
return tooltip
.style("visibility", "hidden")
});
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment