admin管理员组文章数量:1425654
Looking through the documentation on d3.cluster() I did not see anything that the developer can use to set the type of connecting line. It seems that there is only a curved spline kind of connection, but this is not the most conventional styling for dendrograms -- at least for my situation. What I'm after is a vertically oriented, 90 degree angle joined nodes:
Question
Judging by the documentation, there is no direct built-in solution, but is there anything that d3.cluster()
can offer to achieve the above result? Or am I better off coding everything from scratch?
Looking through the documentation on d3.cluster() I did not see anything that the developer can use to set the type of connecting line. It seems that there is only a curved spline kind of connection, but this is not the most conventional styling for dendrograms -- at least for my situation. What I'm after is a vertically oriented, 90 degree angle joined nodes:
Question
Judging by the documentation, there is no direct built-in solution, but is there anything that d3.cluster()
can offer to achieve the above result? Or am I better off coding everything from scratch?
3 Answers
Reset to default 3This issue has been asked before in "d3js Tree square". However, I do not really consider this a duplicate as that old question was using D3 v3 and, as it turns out, is not easily adapted to v5. Furthermore, you are explicitly asking for a vertical layout.
Nonetheless, the basic approach stays the same: just use a custom path generator. Building upon the old v3 Block this could be done as follows:
svg.selectAll(".link")
.data(root.links())
.enter().append("path")
.attr("d", elbow); // Appended paths use the custom path generator.
// Custom path generator
function elbow(d) {
return "M" + d.source.x + "," + d.source.y + "H" + d.target.x + "V" + d.target.y;
}
With some minor modifications to work with the v5 API Mike Bostock's demo can be rewritten as a Vertical "Elbow" Dendrogram.
Note, that this is the same approach Mike Bostock used in his Tree of Life notebook where he used multiple custom path generators to create radial layouts.
just had a similar need for creating an R-style dendrogram in d3 (→ JS).
The dendrogram
function (bottom of this answer) produces dendrograms in the following style given the result of a call to ml-hclust
dendrogram(hclust_result, { h: 2.5 })
(Here's an an acpanying notebook discussing hierarchical clustering in JS https://observablehq./@chrispahm/hierarchical-clustering)
function dendrogram(data, options = {}) {
const {
width: width = 420,
height: height = 320,
hideLabels: hideLabels = false,
paddingBottom: paddingBottom = hideLabels ? 20 : 80,
innerHeight = height - paddingBottom,
innerWidth = width - 10,
paddingLeft = 30,
h: cutHeight = undefined,
yLabel: yLabel = "↑ Height",
colors: colors = d3.schemeTableau10,
fontFamily: fontFamily = "Inter, sans-serif",
linkColor: linkColor = "grey",
fontSize: fontSize = 10,
strokeWidth: strokeWidth = 1
} = options;
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, innerHeight])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");
var clusterLayout = d3.cluster().size([width - paddingLeft * 2, innerHeight]);
const root = d3.hierarchy(data);
const maxHeight = root.data.height;
const yScaleLinear = d3
.scaleLinear()
.domain([0, maxHeight])
.range([hideLabels ? innerHeight - 35 : innerHeight, 0]);
const yAxisLinear = d3.axisLeft(yScaleLinear).tickSize(5);
function transformY(data) {
const height = hideLabels ? innerHeight - 15 : innerHeight;
return height - (data.data.height / maxHeight) * height;
}
// traverse through first order children and assign colors
if (cutHeight) {
let curIndex = -1;
root.each((child) => {
if (
child.data.height <= cutHeight &&
child.data.height > 0 &&
child.parent &&
!child.parent.color
) {
curIndex++;
child.color = colors[curIndex];
} else if (child.parent && child.parent.color) {
child.color = child.parent.color;
}
});
}
clusterLayout(root);
// y-axis
svg
.append("g")
.attr("transform", `translate(0, ${hideLabels ? 20 : 0})`)
.append("g")
.attr("class", "axis")
.attr("transform", `translate(${paddingLeft},${hideLabels ? 20 : 0})`)
.call(yAxisLinear)
.call((g) => g.select(".domain").remove())
.call((g) =>
g
.append("text")
.attr("x", -paddingLeft)
.attr("y", -20)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.style("font-family", fontFamily)
.text(yLabel)
)
.selectAll(".tick")
.classed("baseline", (d) => d == 0)
.style("font-size", `${fontSize}px`)
.style("font-family", fontFamily);
// Links
root.links().forEach((link) => {
svg
.append("path")
.attr("class", "link")
.attr("stroke", link.source.color || linkColor)
.attr("stroke-width", `${strokeWidth}px`)
.attr("fill", "none")
.attr("transform", `translate(${paddingLeft}, ${hideLabels ? 20 : 0})`)
.attr("d", elbow(link));
});
// Nodes
root.descendants().forEach((desc) => {
/*
svg
.append("circle")
.classed("node", true)
.attr("fill", desc.color)
.attr("cx", desc.x)
.attr("cy", transformY(desc))
.attr("transform", `translate(${paddingLeft})`);
.attr("r", 4);
*/
if (desc.data.isLeaf && !hideLabels) {
svg
.append("text")
//.attr("x", desc.x)
.attr("dx", -5)
.attr("dy", 3)
.attr("text-anchor", "end")
.style("font-size", `${fontSize}px`)
.style("font-family", fontFamily)
.attr(
"transform",
`translate(${desc.x + paddingLeft},${transformY(desc)}) rotate(270)`
)
.text(desc.name || desc.data.index);
}
});
// Custom path generator
function elbow(d) {
return (
"M" +
d.source.x +
"," +
transformY(d.source) +
"H" +
d.target.x +
"V" +
transformY(d.target)
);
}
return svg.node();
}
What worked for me take "Most basic dendrogram in d3.js" https://d3-graph-gallery./graph/dendrogram_basic.html
adjust curve parameters to smth like
.attr("d", function(d) {
return "M" + d.y + "," + d.x
+ "L" + (d.parent.y + 0) + "," + d.x
+ " " + d.parent.y + "," + d.parent.x;
})
本文标签: javascriptD3 dendrogram straight edgesStack Overflow
版权声明:本文标题:javascript - D3 dendrogram straight edges - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745422062a2657943.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论