I saw this list of sparse matrices and thought they could be thrown right into a d3 force layout.
I made a small script to process and host the "MM" formatted matrices to a d3 friendly JSON format.
I'd like to add more matrices from the list, and try to adapt this to webgl.
Built with blockbuilder.org
forked from enjalot's block: sparse matrix zoo: canvas
forked from enjalot's block: sparse matrix zoo: canvas
forked from anonymous's block: sparse matrix zoo: canvas
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body {
margin:0;position:fixed;top:0;right:0;bottom:0;left:0;
background-color: #111;
}
svg {
width: 100%; height: 100%;
position:absolute;
}
canvas {
position:absolute;
}
line {
pointer-events: none;
}
#matrices {
position: absolute;
top: 10px;
left: 10px;
}
</style>
</head>
<body>
<canvas></canvas>
<svg></svg>
<select id="matrices">
</select>
<script>
d3.json("https://enjalot.github.io/sparse-matrix-zoo/json/list.json", function(err, matrices) {
var select = d3.select("#matrices")
select.selectAll("option")
.data(matrices)
.enter().append("option")
.text(function(d) { return d.name })
select.on("change", function() {
var i = this.selectedIndex;
render(matrices[i].url);
})
var width = window.innerWidth || 960;
var height = window.innerHeight || 500;
var canvas = d3.select("canvas").node();
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = "lighter";
render(matrices[0].url)
var force;
function render(url) {
d3.json(url, function(err, data) {
console.log(data);
var numNodes = d3.max([+data.meta.rows, +data.meta.cols]);
console.log("numNodes", numNodes);
var nodes = d3.range(numNodes).map(function(d) { return {i: d, value: 0}});
var links = []
data.data.forEach(function(d) {
if(d.source !== d.target) {
// the matrix is 1-indexed
links.push(d)
} else {
nodes[d.source].value = d.value
}
})
console.log("nodes", nodes)
console.log("links",links)
var linkScale = d3.scale.sqrt()
.domain(d3.extent(links, function(d) { return d.value }))
.range([1, 10])
var nodeScale = d3.scale.sqrt()
.domain(d3.extent(nodes, function(d) { return d.value }))
.range([3, 8])
delete force;
force = d3.layout.force()
.charge(-180)
.linkDistance(40)
.friction(0.8)
.gravity(0.2)
//.linkStrength(0.9)
.linkStrength(function(d) { return linkScale(d.value)/10 })
.size([width, height]);
force
.nodes(nodes)
.links(links)
.start();
function draw() {
ctx.clearRect(0, 0, width, height);
ctx.strokeStyle = "rgba(142, 255, 232, 0.2)";
ctx.lineCap = "round";
links.forEach(function(l) {
ctx.beginPath();
ctx.lineWidth = linkScale(l.value);
ctx.moveTo(l.source.x, l.source.y);
ctx.lineTo(l.target.x, l.target.y);
ctx.stroke();
})
}
var svg = d3.select("svg");
var node = svg.selectAll(".node")
.data(nodes)
node.exit().remove();
node
.enter().append("circle")
.attr("class", "node")
.style("fill", function(d) { return "#8effe8" })
node
//.attr("r", 5)
.attr("r", function(d) { return nodeScale(d.value) })
.call(force.drag);
force.on("tick", function() {
draw();
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
})
}
})
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js