This hybrid sankey diagram builds on the example found at http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html .
It modifies the original sankey API found at: https://github.com/d3/d3-plugins/tree/master/sankey .
I imagine using it in a site visit mapping context, superceding the visit mapping found in products from that company in San Jose.
Share of visit traffic (for example, by device type) can be distinguished by link colors.
Types of page can be distinguished by node color, while the exact page name is given in the text.
In real life, you'll generate 10Ks of paths and paths of 100s of distinct node types easily. So you'll need to curate the nodes and links to a manageable set. Some python efforts to do that are in my repo at: https://github.com/mgoold/sankeyhybrid .
xxxxxxxxxx
<meta charset="utf-8">
<title>Modified Sankey for Site Traffic Tracking</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
font: "Arial";
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.path {
fill: none;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<div>
<div id="linklegend" style="float:left"></div>
<div id="chart" style="float:left"></div>
</div>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="hybridsankey.js"></script>
<script>
var pathdata=[{"x":100,"y":100}];
var units = "Visits";
var margin = {top: 10, right: 10, bottom: 10, left: 10};
var linklegwidth=80;
var width = 850 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"),
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
//https://stackoverflow.com/questions/17217766/two-divs-side-by-side-fluid-display
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//.attr("style", "outline: thin solid red;")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var legsvg = d3.select("#linklegend").append("svg")
.attr("width", linklegwidth + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//.attr("style", "outline: thin solid red;")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(40)
.size([width, height]);
var path = sankey.link();
var bouncecolor="#FF0000"
var linkcoldomain=["#0033cc","#ff6600","#0099cc"];
var nodecoldomain=["#CC9900","#99CCFF","#CCFFCC","#9900cc","#cc9900","#00cc99","#993300","#009933","#66ccff","#ff9900","#00ff99","#9900ff","#0066ff"];
// load the data
d3.json("hybridsankey.json", function(error, graph) {
var lta=graph.attributeinfo.attributearray;
var nta=graph.nodeinfo.nodetypearray;
var legpadding=40;
var dlen=lta.length;
var ystart=(height/2)-(((dlen*100)+((dlen-1)*legpadding))/2);
var anylink = function() {
var curvature = .5;
// var iconht=(height-(legpadding*(dlen-1)))/dlen
// console.log('dlen',dlen);
function link(d,i) {
// console.log('d',d,'i',i);
var x0 = linklegwidth/2-50,
x1 = (linklegwidth/2-50)+100,
xi = d3.interpolateNumber(x0, x1),
x2 = xi(curvature),
x3 = xi(1 - curvature),
y0 = ystart+(i*(100+legpadding)),
y1 = ystart+(i*(100+legpadding))+100;
var svginst=
"M" + x0 + "," + y1 + " "
+ "C" + x2 + "," + y1
+ " " + x3 + "," + y0
+ " " + x1 + "," + y0;
// console.log('svginst',svginst)
return svginst;
}
link.curvature = function(_) {
if (!arguments.length) return curvature;
curvature = +_;
return link;
};
return link;
};
var anypath=anylink();
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".path")
.data(graph.links)
.enter().append("path")
.attr("class", "path")
.attr("d", path)
.style("stroke", function (d) { return linkcoldomain[lta.indexOf(d.attrib)]})
.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) {
var nodecol="";
if (d.nodetype=="Hard Bounce") {
nodecol=bouncecolor;
} else {nodecol=nodecoldomain[nta.indexOf(d.nodetype)]; }
return nodecol;
})
.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; });
//LEGEND SECTION
var leglink = legsvg.append("g").selectAll(".anypath")
.data(lta)
.enter().append("path") //this must be "path", because that's the d3 helper for accepting svg coordinates
.attr("d", anypath)
.attr("stroke", function (d) { return linkcoldomain[lta.indexOf(d)]})
.attr("fill","none")
.attr("stroke-opacity", .2)
.attr("stroke-width", 40);
// add in the title for the nodes
legsvg.selectAll("text")
.data(lta)
.enter()
.append("text")
.attr("x",linklegwidth/2-20)
.attr("y",function(d,i) {
var y=ystart+(i*(100+legpadding))+50;
console.log('d',d,'i',i,"y",y);
return y;
})
.text(function(d) {return d});
// 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", link);
}
});
</script>
</body>
</html>
https://d3js.org/d3.v3.min.js