Skip to content

Instantly share code, notes, and snippets.

@ajschumacher
Forked from mbostock/.block
Last active May 5, 2024 16:11
Show Gist options
  • Save ajschumacher/65eda1df2b0dd2cf616f to your computer and use it in GitHub Desktop.
Save ajschumacher/65eda1df2b0dd2cf616f to your computer and use it in GitHub Desktop.
Interactive D3 view of sklearn decision tree
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 180},
width = 960 - margin.right - margin.left,
height = 480 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("/ajschumacher/raw/65eda1df2b0dd2cf616f/structure.json", function(error, flare) {
if (error) throw error;
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
d3.select(self.frameElement).style("height", "480px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
{
"name": "petal length (cm) > 2.45000004768",
"children": [
{
"name": "petal width (cm) > 1.75",
"children": [
{
"name": "petal length (cm) > 4.85000038147",
"children": [
{
"name": "0 of setosa, 0 of versicolor, 43 of virginica"
},
{
"name": "0 of setosa, 1 of versicolor, 2 of virginica"
}
]
},
{
"name": "petal length (cm) > 4.94999980927",
"children": [
{
"name": "0 of setosa, 2 of versicolor, 4 of virginica"
},
{
"name": "0 of setosa, 47 of versicolor, 1 of virginica"
}
]
}
]
},
{
"name": "50 of setosa, 0 of versicolor, 0 of virginica"
}
]
}
@siddhant250502
Copy link

If i would like to make this tree vertical and not horizontal what changes should i do?
And also is there any way where i can print more info other than just the rules of each node

@ajschumacher
Copy link
Author

If i would like to make this tree vertical and not horizontal what changes should i do? And also is there any way where i can print more info other than just the rules of each node

@siddhant250502 You should be able to swap the Xs and Ys to get a different orientation, and modify the "name" field to see other information displayed (among other methods).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment