Convex hull around D3 Force network graphic
Asked Answered
T

1

1

I'm trying to add a hull around the D3 network graph that I've build. My network is based on this JSFiddle (can't share mine because of sensitive data) and basically the end product should be a network with a shade around. I read a lot online and found that a convex hull might be a solution. After trying to implement my data in tutorials like this one http://bl.ocks.org/donaldh/2920551, I must come to the conclusion that my basic D3 knowledge won't be enough to solve this.

Thank you all in advance!

//Constants for the SVG
var width = 500,
height = 500;

//Set up the colour scale
var color = d3.scale.category20();

//Set up the force layout
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);

//Append a SVG to the body of the html page. Assign this SVG as an object to         svg
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

//Read the data from the mis element 
var mis = document.getElementById('mis').innerHTML;
graph = JSON.parse(mis);

//Creates the graph data structure out of the json data
force.nodes(graph.nodes)
.links(graph.links)
.start();

//Create all the line svgs but without locations yet
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function (d) {
return Math.sqrt(d.value);
});

//Do the same with the circles for the nodes - no 
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 8)
.style("fill", function (d) {
return color(d.group);
})
.call(force.drag);


//Now we are giving the SVGs co-ordinates - the force layout is generating the         co-ordinates which this code is using to update the attributes of the SVG elements
force.on("tick", function () {
link.attr("x1", function (d) {
    return d.source.x;
})
    .attr("y1", function (d) {
    return d.source.y;
})
Tobacco answered 7/6, 2017 at 17:7 Comment(0)
S
0

By following the basic example here, you should be able to incorporate the minimum convex hull fairly easily. In the basic example, the hull is created here:

var hull = svg.append("path")
    .attr("class", "hull");

And updated here:

hull.datum(d3.geom.hull(vertices)).attr("d", function(d) { return "M" + d.join("L") + "Z"; });

However, I was unable to get the x and y accessors to access d.x and d.y; in the example block above the hull takes an array of points (documentation here, possible solution here). So I've created an example that creates an intermediate variable that contains all the points:

node.data().forEach(function(d,i) {
    vertices[i] = [d.x,d.y]; 
})

And then updates as in the example above:

hull.datum(d3.geom.hull(vertices)).attr("d", function(d) {  return "M" + d.join("L") + "Z"; });

Here's a block showing it in action based on the example fiddle.

D3v4 doesn't offer much streamlining - there are no accessor functions for d3.polygonHull in v4; I've created a block here for v4.

Socket answered 8/6, 2017 at 4:59 Comment(1)
You are a life saver Andrew! This works perfectly. Thank you so much for your time!Tobacco

© 2022 - 2024 — McMap. All rights reserved.