Problem:
Trying to create the following:
…using this text data:
var inputText = `
- a
- - b_1
- - - c_1
- - - c_2
- b
- - b_2
- - - d_1
- - - d_2
`;
Here is the code:
JS:
function parseHierarchicalText(text) {
var lines = text.split('\n');
function parseNode(index, depth) {
var node = {
name: lines[index].trim().replace(/-/g, '').trim(),
children: []
};
index++;
while(index < lines.length && lines[index].lastIndexOf('-') / 2 > depth) {
var result = parseNode(index, depth + 1);
node.children.push(result.node);
index = result.index;
}
return {
node: node,
index: index
};
}
var flareData = [];
var index = 0;
while(index < lines.length) {
var result = parseNode(index, 0);
flareData.push(result.node);
index = result.index + 1;
}
return {
name: 'Root',
children: flareData
};
}
var inputText = `
- a
- - b_1
- - - c_1
- - - c_2
- b
- - b_2
- - - d_1
- - - d_2
`;
var data = parseHierarchicalText(inputText);
// Set the dimensions and margins of the diagram
var margin = {
top: 20,
right: 90,
bottom: 30,
left: 90
},
width = 800 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Appending svg to the dendrogram div
var svg = d3.select("#dendrogram").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Create a hierarchical cluster layout
var hierarchy = d3.hierarchy(data, function(d) {
return d.children; // specify children accessor
});
var cluster = d3.cluster().size([height, width - 100]);
// Assigns the x and y position for the nodes
var root = cluster(hierarchy);
// Draw links between nodes
svg.selectAll('path').data(root.links()).enter().append('path').attr('class', 'link').attr('d', d3.linkHorizontal().x(function(d) {
return d.y;
}).y(function(d) {
return d.x;
}));
// Draw nodes
var nodes = svg.selectAll('g.node').data(root.descendants()).enter().append('g').attr('class', function(d) {
return 'node' + (d.children ? ' node--internal' : ' node--leaf');
}).attr('transform', function(d) {
return 'translate(' + d.y + ',' + d.x + ')';
});
nodes.append('circle').attr('r', 7);
nodes.append('text').attr('dy', '.35em').attr('x', function(d) {
return d.children ? -13 : 13;
}).style('text-anchor', function(d) {
return d.children ? 'end' : 'start';
}).text(function(d) {
return d.data.name;
});
But instead it produces this:
Here is a codepen.
Solution:
FWIW, here’s a function that appears to parse your input correctly:
function parseHierarchicalText(text) {
let root = {name: 'root', children: []}
let stack = [root]
for (let line of text.trim().split('\n')) {
let parts = line.match(/([- ]+)(.+)/)
let level = parts[1].match(/-/g).length
while (level < stack.length)
stack.pop()
let node = {name: parts[2], children: []}
stack.at(-1).children.push(node)
stack.push(node)
}
return root
}
//
var inputText = `
- a
- - b_1
- - - c_1
- - - c_2
- b
- - b_2
- - - d_1
- - - d_2
`;
r = parseHierarchicalText(inputText)
console.log(JSON.stringify(r, 0, 4))