block by micahstubbs 89522076fa3f862b55b6ade8c69312b9

Dendrogram Small Dataset

Full Screen

an iteration that draws a smaller dataset.

If your tree dataset is small, then this example should be useful for showing how your dataset might look as a dendrogram.

See also the Dendrogram Large Dataset and react-app examples.


D3’s cluster layout produces node-link diagrams with leaf nodes at equal depth. These are less compact than tidy trees, but are useful for dendrograms, hierarchical clustering and phylogenetic trees. See also the radial variant.`


inspired by

index.js

// define some constants
const width = 960
const height = 500
const margin = { top: 40, left: 40, bottom: 0, right: 0 }
const innerWidth = width - margin.left - margin.right
const innerHeight = height - margin.top - margin.bottom
const fontSize = 12
const magicWidthDivisor = 1.35

// load the data
d3.json('analytics.json').then(data => draw(data))

function draw(data) {
  // define the tree layout function
  const tree = data => {
    const root = d3
      .hierarchy(data)
      .sort(
        (a, b) => a.height - b.height || a.data.name.localeCompare(b.data.name)
      )
    console.log('root.height', root.height)
    console.log('root', root)
    root.dx = 10
    root.dy = innerWidth / (root.height + 1)
    return d3.cluster().size([innerHeight, innerWidth / magicWidthDivisor])(root)
  }

  // call the tree layout function on the data
  const root = tree(data)

  // draw the visualization
  let x0 = Infinity
  let x1 = -x0
  root.each(d => {
    if (d.x > x1) x1 = d.x
    if (d.x < x0) x0 = d.x
  })

  const svg = d3
    .select('body')
    .append('svg')
    .attr('width', width)
    .attr('height', height)

  // a gray border for debugging the layout
  // svg
  //   .append('rect')
  //   .attr('width', width)
  //   .attr('height', height)
  //   .style('fill', 'none')
  //   .style('stroke', 'gray')
  //   .style('stroke-width', '1px')

  const magicXTranslateDivisor = 6
  const xTranslate = root.dy / magicXTranslateDivisor + margin.left
  const yTranslate = root.dx - x0 + margin.top
  const g = svg
    .append('g')
    .attr('font-family', 'sans-serif')
    .attr('font-size', fontSize)
    .attr(
      'transform',
      `translate(${xTranslate},${yTranslate})`
    )

  const link = g
    .append('g')
    .attr('fill', 'none')
    .attr('stroke', '#555')
    .attr('stroke-opacity', 0.4)
    .attr('stroke-width', 1.5)
    .selectAll('path')
    .data(root.links())
    .join('path')
    .attr(
      'd',
      d => `
        M${d.target.y},${d.target.x}
        C${d.source.y + root.dy / 2},${d.target.x}
         ${d.source.y + root.dy / 2},${d.source.x}
         ${d.source.y},${d.source.x}
      `
    )

  const node = g
    .append('g')
    .attr('stroke-linejoin', 'round')
    .attr('stroke-width', 3)
    .selectAll('g')
    .data(root.descendants().reverse())
    .join('g')
    .attr('transform', d => `translate(${d.y},${d.x})`)

  node
    .append('circle')
    .attr('fill', d => (d.children ? '#555' : '#999'))
    .attr('r', 2.5)

  node
    .append('text')
    .attr('dy', '0.31em')
    .attr('x', d => (d.children ? -6 : 6))
    .text(d => d.data.name)
    .filter(d => d.children)
    .attr('text-anchor', 'end')
    .clone(true)
    .lower()
    .attr('stroke', 'white')
}

index.html

<html>
  <head>
    <title>Cluster Dendrogram - Large Dataset</title>
    <meta charset="utf-8" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script>
  </head>
  <body>
    <script src="index.js"></script>
  </body>
</html>

analytics.json

{
  "name": "analytics",
  "children": [
    {
      "name": "cluster",
      "children": [
        { "name": "AgglomerativeCluster", "value": 3938 },
        { "name": "CommunityStructure", "value": 3812 },
        { "name": "HierarchicalCluster", "value": 6714 },
        { "name": "MergeEdge", "value": 743 }
      ]
    },
    {
      "name": "graph",
      "children": [
        { "name": "BetweennessCentrality", "value": 3534 },
        { "name": "LinkDistance", "value": 5731 },
        { "name": "MaxFlowMinCut", "value": 7840 },
        { "name": "ShortestPaths", "value": 5914 },
        { "name": "SpanningTree", "value": 3416 }
      ]
    },
    {
      "name": "optimization",
      "children": [{ "name": "AspectRatioBanker", "value": 7074 }]
    }
  ]
}