[Chartjs]-How to get a Packed circle chart in react chartjs?

2👍

just a vanilla JS, Chart.JS and D3 solution…

uses the D3 layout.pack algorithm (which seems to have been deprecated, so this is only a stop-gap) but … it calls the D3 packing routine to calculate x,y and scaled radius for each point and then extracts that into a data structure the ChartJS bubble chart can consume.

var w = document.getElementById("c").offsetWidth,
  h = document.getElementById("c").offsetHeight;

// build random set of circles for the d3 packing
var data = {
  "name": "root",
  "children": []
}
for (var i = 1; i <= 15; i++) {
  data["children"].push({
    "name": i,
    "size": Math.floor((Math.random() * 200) + 1)
  })
}

// use D3 to pack into the canvas size, with a little bit of padding
var nodes = d3.layout.pack()
  .value(function(d) {
    return d.size;
  })
  .size([w, h])
  .padding(4)
  .nodes(data);

// Get rid of root node
nodes.shift();

// take the packed nodes data, and push to format ChartJS expects for bubbles
nodedata = [];
for (i = 0; i < nodes.length; i++) {
  node = nodes[i]
  nodedata.push({
    "x": node.x,
    "y": node.y,
    "r": node.r
  })
}

// create a bubble chart with no labels, border lines etc
var bubbleChart = new Chart(document.getElementById("cc"), {
  type: 'bubble',
  data: {
    datasets: [{
      data: nodedata,
      backgroundColor: "rgba(212,121,212,1)"
    }]
  },
  options: {
    scales: {
      x: {
        ticks: {
          display: false,
        },
        grid: {
          display: false
        },
        border: {
          display: false
        }
      },
      y: {
        display: false,
        ticks: {
          display: false,
        },
        grid: {
          display: false,
        },
        border: {
          display: false
        }
      }
    },
    maintainAspectRatio: false,
    plugins: {
      legend: {
        display: false
      },
    }
  }
});
#c {
  border: 1px solid black;
  width: 380px;
  height: 280px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<div id="c"><canvas id="cc"></canvas></div>

Issues:

  • sometimes we get circles slightly overlapping
  • the packing is optimized to fill a circle, not efficiently use the full rectangle
  • no center of gravity to improve the clustering
  • as mentioned, relies on older D3 version

I suspect most of these issues could be addressed via a more sophisticated D3 force model application (allow it to run for a few ticks until the circles are positioned and then pass to the chart)

credit for the above D3 part of the solution to seliopou.
opened a new question based on this answer to see if anyone has a clever solution using forceSimulation features of D3.js

Leave a comment