Reputation: 2617
The goal here is to adapt a d3 v3 radial tree chart to v5 using the new .linkHorizontal()
function that was introduced in more recent versions of d3. Here is the snipped with hard-coded data:
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
var root = {"name" : "Araneae", "children" : [
{"name" : "Agelenidae", "children" : [
{"name" : "Hobo Spider"},
{"name" : "Giant House Spider"},
{"name" : "Domestic House Spider"},
{"name" : "Dust Spider"}
] },
{"name" : "Araneidae", "children" : [
{"name" : "Grass Spider"},
{"name" : "Cross Orb Weaver"},
{"name" : "Banded Garden Spider"},
{"name" : "Golden Orb Weaver Spider"},
{"name" : "Long-Jawed Orb Weaver Spider"}
] },
{"name" : "Ctenidae", "children" : [
{"name" : "Brazilian Wandering Spider"},
{"name" : "Fishing Spider"}
] },
{"name" : "Desidae", "children" : [
{"name" : "Black House Spider"},
{"name" : "Brown House Spider"},
{"name" : "Hollow Twig Spider"}
] },
{"name" : "Filistatidae", "children" : [
{"name" : "Southern House Spider"},
{"name" : "Arizona Black Hole Spider"}
] },
{"name" : "Lycosidae", "children" : [
{"name" : "Carolina Wolf Spider"},
{"name" : "Brown Wolf Spider"},
{"name" : "Texas Wolf Spider"}
] },
{"name" : "Pholcidae", "children": [
{"name" : "Cellar Spider"},
{"name" : "Yellow Sac Spider"},
{"name" : "Ground Spider"},
{"name" : "Banded Garden Spider"}
] },
{"name" : "Salticidae", "children": [
{"name" : "Bold Jumping Spider"},
{"name" : "Zebra Jumping Spider"},
{"name" : "Gray Wall Jumping Spider"}
] },
{"name" : "Sicariidae", "children": [
{"name" : "Brown Spider"},
{"name" : "Brown Recluse Spider"}
] },
{"name" : "Theraphosidae", "children": [
{"name" : "King Baboon Spider"},
{"name" : "Bird Eating Spider"},
{"name" : "Pinktoe Tarantula Spider"},
{"name" : "Indian Ornamental Tree Spider"}
] },
{"name" : "Theridiidae", "children": [
{"name" : "Black Widow Spider"},
{"name" : "Brown Widow Spider"},
{"name" : "Red Widow Spider"}
] }
]};
var diameter = 760;
var tree = d3.tree()
.size([360, diameter / 2 - 190])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var diagonal = function link(d) {
return "M" + d.source.y + "," + d.source.x
+ "C" + (d.source.y + d.target.y) / 2 + "," + d.source.x
+ " " + (d.source.y + d.target.y) / 2 + "," + d.target.x
+ " " + d.target.y + "," + d.target.x;
};
const treeRoot = d3.hierarchy(root)
d3.tree(treeRoot)
const nodes = treeRoot.descendants()
const links = treeRoot.links()
var link = graphGroup.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = graphGroup.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
node.append("circle")
.attr("r", 5);
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
d3.select(self.frameElement).style("height", diameter - 150 + "px");
<script src="https://d3js.org/d3.v5.min.js"></script>
This gives me the error:
Error: path attribute d: expected number, "Mundefined,undefin..."
Original v3 version here:
http://bl.ocks.org/nlinc1905/66ea5dd294ed28385b7f
As you can see there is no issue with the v3 version, however, I can't get it working for v5 -- even after making changes as per d3js tree.nodes() is not a function. Namely:
var tree = d3.tree()
.size([360, diameter / 2 - 190])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var diagonal = function link(d) {
return "M" + d.source.y + "," + d.source.x
+ "C" + (d.source.y + d.target.y) / 2 + "," + d.source.x
+ " " + (d.source.y + d.target.y) / 2 + "," + d.target.x
+ " " + d.target.y + "," + d.target.x;
};
const treeRoot = d3.hierarchy(root)
d3.tree(treeRoot)
const nodes = treeRoot.descendants()
const links = treeRoot.links()
Also tried (per comments):
var treeRoot = d3.hierarchy(root);
treeRoot = d3.tree(treeRoot);
What is the issue with my v5 radial tree syntax and how might I resolve it?
Upvotes: 1
Views: 779
Reputation: 565
Mm, this was not answered because it had several issues (hierarchy, radial projection, styling lines). Solved below, I guess this is what it was meant to be (probably needs adjusting labels):
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+(width/2-margins.left)+","+(height/2-margins.top)+")");
var root = {"name" : "Araneae", "children" : [
{"name" : "Agelenidae", "children" : [
{"name" : "Hobo Spider"},
{"name" : "Giant House Spider"},
{"name" : "Domestic House Spider"},
{"name" : "Dust Spider"}
] },
{"name" : "Araneidae", "children" : [
{"name" : "Grass Spider"},
{"name" : "Cross Orb Weaver"},
{"name" : "Banded Garden Spider"},
{"name" : "Golden Orb Weaver Spider"},
{"name" : "Long-Jawed Orb Weaver Spider"}
] },
{"name" : "Ctenidae", "children" : [
{"name" : "Brazilian Wandering Spider"},
{"name" : "Fishing Spider"}
] },
{"name" : "Desidae", "children" : [
{"name" : "Black House Spider"},
{"name" : "Brown House Spider"},
{"name" : "Hollow Twig Spider"}
] },
{"name" : "Filistatidae", "children" : [
{"name" : "Southern House Spider"},
{"name" : "Arizona Black Hole Spider"}
] },
{"name" : "Lycosidae", "children" : [
{"name" : "Carolina Wolf Spider"},
{"name" : "Brown Wolf Spider"},
{"name" : "Texas Wolf Spider"}
] },
{"name" : "Pholcidae", "children": [
{"name" : "Cellar Spider"},
{"name" : "Yellow Sac Spider"},
{"name" : "Ground Spider"},
{"name" : "Banded Garden Spider"}
] },
{"name" : "Salticidae", "children": [
{"name" : "Bold Jumping Spider"},
{"name" : "Zebra Jumping Spider"},
{"name" : "Gray Wall Jumping Spider"}
] },
{"name" : "Sicariidae", "children": [
{"name" : "Brown Spider"},
{"name" : "Brown Recluse Spider"}
] },
{"name" : "Theraphosidae", "children": [
{"name" : "King Baboon Spider"},
{"name" : "Bird Eating Spider"},
{"name" : "Pinktoe Tarantula Spider"},
{"name" : "Indian Ornamental Tree Spider"}
] },
{"name" : "Theridiidae", "children": [
{"name" : "Black Widow Spider"},
{"name" : "Brown Widow Spider"},
{"name" : "Red Widow Spider"}
] }
]};
function radialPoint(x, y) { // returns radial projections of a point coordinates
return [parseFloat((y = +y) * Math.cos(x -= Math.PI / 2)).toFixed(4), parseFloat(y * Math.sin(x)).toFixed(4)];
}
var diameter = 760;
var hierTree = d3.tree()
.size([360, diameter / 2 - 190])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var diagonal = function link(d) {
return "M" + d.x + "," + d.y
+ "C" + (d.x + d.parent.x) / 2 + "," + d.y
+ " " + (d.x + d.parent.x) / 2 + "," + d.parent.y
+ " " + d.parent.x + "," + d.parent.y;
};
var treeRoot = d3.hierarchy(root, function(d) { // creates a hierarchy from data read
return d.children;
});
var treeData = hierTree(treeRoot);
// var treeData = d3.tree(treeRoot)
var nodes = treeData.descendants();
var links = nodes.slice(1);
var link = graphGroup.selectAll(".link")
.data(links)
.enter().append("line")
.attr("class", "link")
.attr("x1", function(d) { return radialPoint(d.x,d.y)[0]; })
.attr("y1", function(d) { return radialPoint(d.x,d.y)[1]; })
.attr("x2", function(d) { return radialPoint(d.parent.x,d.parent.y)[0]; })
.attr("y2", function(d) { return radialPoint(d.parent.x,d.parent.y)[1]; })
var node = graphGroup.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + radialPoint(d.x, d.y) + ")" });
node.append("circle")
.attr("r", 5);
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return (d.x > 0 && d.x < 180) ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "translate(-8)"; })
.text(function(d) { return d.data.name; });
d3.select(self.frameElement).style("height", diameter - 150 + "px");
.link {
fill: none;
stroke: #365CB7;
stroke-width: 0.8px;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
I have left the diagonal function to reuse after getting know of script working.
Upvotes: 1