Skip to content

Instantly share code, notes, and snippets.

@bellerbrock
Last active December 27, 2019 04:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellerbrock/437279e9f6e04102a1b5f9d8d6abd7c2 to your computer and use it in GitHub Desktop.
Save bellerbrock/437279e9f6e04102a1b5f9d8d6abd7c2 to your computer and use it in GitHub Desktop.
license: gpl-3.0

sankey_traceability

A repo to host example sankey traceability visualizations for breeding data.

Inspired by a desire for big-picture visualizations of complex breeding program processes. Encouraged by similar ideas discussed here. Will use d3-sankey-diagram along with fake breeding data.

{
"links": [
{"source":"17Cross1","target":"17SeedlotX1","value":"260"},
{"source":"17Cross2","target":"17SeedlotX2","value":"260"},
{"source":"17Cross3","target":"17SeedlotX3","value":"260"},
{"source":"17Cross4","target":"17SeedlotX4","value":"260"},
{"source":"17Cross5","target":"17SeedlotX5","value":"260"},
{"source":"17Cross6","target":"17SeedlotS6","value":"260"},
{"source":"17Cross7","target":"17SeedlotS7","value":"260"},
{"source":"17Cross8","target":"17SeedlotS8","value":"260"},
{"source":"17Cross9","target":"17SeedlotS9","value":"260"},
{"source":"17Cross10","target":"17SeedlotS10","value":"260"},
{"source":"17SeedlotX1","target":"18Trial1-1","value":"40"},
{"source":"17SeedlotX2","target":"18Trial1-2","value":"40"},
{"source":"17SeedlotX3","target":"18Trial1-3","value":"40"},
{"source":"17SeedlotX4","target":"18Trial1-4","value":"40"},
{"source":"17SeedlotX5","target":"18Trial1-5","value":"40"},
{"source":"17SeedlotX1","target":"18Trial1-6","value":"40"},
{"source":"17SeedlotX2","target":"18Trial1-7","value":"40"},
{"source":"17SeedlotX3","target":"18Trial1-8","value":"40"},
{"source":"17SeedlotX4","target":"18Trial1-9","value":"40"},
{"source":"17SeedlotX5","target":"18Trial1-10","value":"40"},
{"source":"17SeedlotX1","target":"18Trial2-1","value":"40"},
{"source":"17SeedlotX2","target":"18Trial2-2","value":"40"},
{"source":"17SeedlotX3","target":"18Trial2-3","value":"40"},
{"source":"17SeedlotX4","target":"18Trial2-4","value":"40"},
{"source":"17SeedlotX5","target":"18Trial2-5","value":"40"},
{"source":"17SeedlotX1","target":"18Trial2-6","value":"40"},
{"source":"17SeedlotX2","target":"18Trial2-7","value":"40"},
{"source":"17SeedlotX3","target":"18Trial2-8","value":"40"},
{"source":"17SeedlotX4","target":"18Trial2-9","value":"40"},
{"source":"17SeedlotX5","target":"18Trial2-10","value":"40"},
{"source":"17SeedlotX1","target":"18Trial3-1","value":"40"},
{"source":"17SeedlotX2","target":"18Trial3-2","value":"40"},
{"source":"17SeedlotX3","target":"18Trial3-3","value":"40"},
{"source":"17SeedlotX4","target":"18Trial3-4","value":"40"},
{"source":"17SeedlotX5","target":"18Trial3-5","value":"40"},
{"source":"17SeedlotX1","target":"18Trial3-6","value":"40"},
{"source":"17SeedlotX2","target":"18Trial3-7","value":"40"},
{"source":"17SeedlotX3","target":"18Trial3-8","value":"40"},
{"source":"17SeedlotX4","target":"18Trial3-9","value":"40"},
{"source":"17SeedlotX5","target":"18Trial3-10","value":"40"},
{"source":"17SeedlotS6","target":"18Nursery-1","value":"20"},
{"source":"17SeedlotS7","target":"18Nursery-2","value":"20"},
{"source":"17SeedlotS8","target":"18Nursery-3","value":"20"},
{"source":"17SeedlotS9","target":"18Nursery-4","value":"20"},
{"source":"17SeedlotS10","target":"18Nursery-5","value":"20"},
{"source":"18Nursery-1","target":"18Cross1"},
{"source":"18Nursery-1","target":"18Cross2"},
{"source":"18Nursery-2","target":"18Cross3"},
{"source":"18Nursery-2","target":"18Cross4"},
{"source":"18Nursery-3","target":"18Cross5"},
{"source":"18Nursery-3","target":"18Cross6"},
{"source":"18Nursery-4","target":"18Cross7"},
{"source":"18Nursery-4","target":"18Cross8"},
{"source":"18Nursery-5","target":"18Cross9"},
{"source":"18Nursery-5","target":"18Cross10"},
{"source":"18Cross1","target":"18SeedlotX1","value":"260"},
{"source":"18Cross2","target":"18SeedlotX2","value":"260"},
{"source":"18Cross3","target":"18SeedlotX3","value":"260"},
{"source":"18Cross4","target":"18SeedlotX4","value":"260"},
{"source":"18Cross5","target":"18SeedlotX5","value":"260"},
{"source":"18Cross6","target":"18SeedlotS6","value":"260"},
{"source":"18Cross7","target":"18SeedlotS7","value":"260"},
{"source":"18Cross8","target":"18SeedlotS8","value":"260"},
{"source":"18Cross9","target":"18SeedlotS9","value":"260"},
{"source":"18Cross10","target":"18SeedlotS10","value":"260"},
{"source":"18SeedlotX1","target":"19Trial1-1","value":"40"},
{"source":"18SeedlotX2","target":"19Trial1-2","value":"40"},
{"source":"18SeedlotX3","target":"19Trial1-3","value":"40"},
{"source":"18SeedlotX4","target":"19Trial1-4","value":"40"},
{"source":"18SeedlotX5","target":"19Trial1-5","value":"40"},
{"source":"18SeedlotX1","target":"19Trial1-6","value":"40"},
{"source":"18SeedlotX2","target":"19Trial1-7","value":"40"},
{"source":"18SeedlotX3","target":"19Trial1-8","value":"40"},
{"source":"18SeedlotX4","target":"19Trial1-9","value":"40"},
{"source":"18SeedlotX5","target":"19Trial1-10","value":"40"},
{"source":"18SeedlotX1","target":"19Trial2-1","value":"40"},
{"source":"18SeedlotX2","target":"19Trial2-2","value":"40"},
{"source":"18SeedlotX3","target":"19Trial2-3","value":"40"},
{"source":"18SeedlotX4","target":"19Trial2-4","value":"40"},
{"source":"18SeedlotX5","target":"19Trial2-5","value":"40"},
{"source":"18SeedlotX1","target":"19Trial2-6","value":"40"},
{"source":"18SeedlotX2","target":"19Trial2-7","value":"40"},
{"source":"18SeedlotX3","target":"19Trial2-8","value":"40"},
{"source":"18SeedlotX4","target":"19Trial2-9","value":"40"},
{"source":"18SeedlotX5","target":"19Trial2-10","value":"40"},
{"source":"18SeedlotX1","target":"19Trial3-1","value":"40"},
{"source":"18SeedlotX2","target":"19Trial3-2","value":"40"},
{"source":"18SeedlotX3","target":"19Trial3-3","value":"40"},
{"source":"18SeedlotX4","target":"19Trial3-4","value":"40"},
{"source":"18SeedlotX5","target":"19Trial3-5","value":"40"},
{"source":"18SeedlotX1","target":"19Trial3-6","value":"40"},
{"source":"18SeedlotX2","target":"19Trial3-7","value":"40"},
{"source":"18SeedlotX3","target":"19Trial3-8","value":"40"},
{"source":"18SeedlotX4","target":"19Trial3-9","value":"40"},
{"source":"18SeedlotX5","target":"19Trial3-10","value":"40"}
],
"nodes": [
{"name":"17Cross1"},
{"name":"17Cross2"},
{"name":"17Cross3"},
{"name":"17Cross4"},
{"name":"17Cross5"},
{"name":"17Cross6"},
{"name":"17Cross7"},
{"name":"17Cross8"},
{"name":"17Cross9"},
{"name":"17Cross10"},
{"name":"17SeedlotX1"},
{"name":"17SeedlotX2"},
{"name":"17SeedlotX3"},
{"name":"17SeedlotX4"},
{"name":"17SeedlotX5"},
{"name":"17SeedlotS6"},
{"name":"17SeedlotS7"},
{"name":"17SeedlotS8"},
{"name":"17SeedlotS9"},
{"name":"17SeedlotS10"},
{"name":"18Trial1-1"},
{"name":"18Trial1-2"},
{"name":"18Trial1-3"},
{"name":"18Trial1-4"},
{"name":"18Trial1-5"},
{"name":"18Trial1-6"},
{"name":"18Trial1-7"},
{"name":"18Trial1-8"},
{"name":"18Trial1-9"},
{"name":"18Trial1-10"},
{"name":"18Trial2-1"},
{"name":"18Trial2-2"},
{"name":"18Trial2-3"},
{"name":"18Trial2-4"},
{"name":"18Trial2-5"},
{"name":"18Trial2-6"},
{"name":"18Trial2-7"},
{"name":"18Trial2-8"},
{"name":"18Trial2-9"},
{"name":"18Trial2-10"},
{"name":"18Trial3-1"},
{"name":"18Trial3-2"},
{"name":"18Trial3-3"},
{"name":"18Trial3-4"},
{"name":"18Trial3-5"},
{"name":"18Trial3-6"},
{"name":"18Trial3-7"},
{"name":"18Trial3-8"},
{"name":"18Trial3-9"},
{"name":"18Trial3-10"},
{"name":"18Nursery-1"},
{"name":"18Nursery-2"},
{"name":"18Nursery-3"},
{"name":"18Nursery-4"},
{"name":"18Nursery-5"},
{"name":"18Cross1"},
{"name":"18Cross2"},
{"name":"18Cross3"},
{"name":"18Cross4"},
{"name":"18Cross5"},
{"name":"18Cross6"},
{"name":"18Cross7"},
{"name":"18Cross8"},
{"name":"18Cross9"},
{"name":"18Cross10"},
{"name":"18SeedlotX1"},
{"name":"18SeedlotX2"},
{"name":"18SeedlotX3"},
{"name":"18SeedlotX4"},
{"name":"18SeedlotX5"},
{"name":"18SeedlotS6"},
{"name":"18SeedlotS7"},
{"name":"18SeedlotS8"},
{"name":"18SeedlotS9"},
{"name":"18SeedlotS10"},
{"name":"19Trial1-1"},
{"name":"19Trial1-2"},
{"name":"19Trial1-3"},
{"name":"19Trial1-4"},
{"name":"19Trial1-5"},
{"name":"19Trial1-6"},
{"name":"19Trial1-7"},
{"name":"19Trial1-8"},
{"name":"19Trial1-9"},
{"name":"19Trial1-10"},
{"name":"19Trial2-1"},
{"name":"19Trial2-2"},
{"name":"19Trial2-3"},
{"name":"19Trial2-4"},
{"name":"19Trial2-5"},
{"name":"19Trial2-6"},
{"name":"19Trial2-7"},
{"name":"19Trial2-8"},
{"name":"19Trial2-9"},
{"name":"19Trial2-10"},
{"name":"19Trial3-1"},
{"name":"19Trial3-2"},
{"name":"19Trial3-3"},
{"name":"19Trial3-4"},
{"name":"19Trial3-5"},
{"name":"19Trial3-6"},
{"name":"19Trial3-7"},
{"name":"19Trial3-8"},
{"name":"19Trial3-9"},
{"name":"19Trial3-10"}
],
"groups": [
{ "title": "17Nursery",
"nodes": ["17Cross1", "17Cross2", "17Cross3", "17Cross4", "17Cross5", "17Cross6", "17Cross7", "17Cross8", "17Cross9", "17Cross10"]
},
{ "title": "18Trial1",
"nodes": ["18Trial1-1","18Trial1-2","18Trial1-3","18Trial1-4","18Trial1-5","18Trial1-6","18Trial1-7","18Trial1-8","18Trial1-9","18Trial1-10"]
},
{ "title": "18Trial2",
"nodes": ["18Trial2-1","18Trial2-2","18Trial2-3","18Trial2-4","18Trial2-5","18Trial2-6","18Trial2-7","18Trial2-8","18Trial2-9","18Trial2-10"]
},
{ "title": "18Trial3",
"nodes": ["18Trial3-1","18Trial3-2","18Trial3-3","18Trial3-4","18Trial3-5","18Trial3-6","18Trial3-7","18Trial3-8","18Trial3-9","18Trial3-10"]
},
{ "title": "18Nursery",
"nodes": ["18Nursery-1","18Nursery-2","18Nursery-3","18Nursery-4","18Nursery-5"]
},
{ "title": "19Trial1",
"nodes": ["19Trial1-1","19Trial1-2","19Trial1-3","19Trial1-4","19Trial1-5","19Trial1-6","19Trial1-7","19Trial1-8","19Trial1-9","19Trial1-10"]
},
{ "title": "19Trial2",
"nodes": ["19Trial2-1","19Trial2-2","19Trial2-3","19Trial2-4","19Trial2-5","19Trial2-6","19Trial2-7","19Trial2-8","19Trial2-9","19Trial2-10"]
},
{ "title": "19Trial3",
"nodes": ["19Trial3-1","19Trial3-2","19Trial3-3","19Trial3-4","19Trial3-5","19Trial3-6","19Trial3-7","19Trial3-8","19Trial3-9","19Trial3-10"]
}
]
}
<!DOCTYPE html>
<meta charset="utf-8">
<title>SANKEY Example</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<p id="chart">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<!-- <script src="d3-sankey-diagram.js" charset="utf-8"></script> -->
<script src="https://cdn.jsdelivr.net/gh/holtzy/D3-graph-gallery@master/LIB/sankey.js"></script>
<script>
var units = "Widgets";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1200 - margin.left - margin.right,
height = 740 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
// append the svg canvas to the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data
d3.json("breeding_relationships.json", function(error, graph) {
var nodeMap = {};
graph.nodes.forEach(function(x) { nodeMap[x.name] = x; });
graph.links = graph.links.map(function(x) {
return {
source: nodeMap[x.source],
target: nodeMap[x.target],
value: x.value
};
});
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove));
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value); });
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment