[Chartjs]-Can individual bubbles in a chartjs bubble chart have labels?

3๐Ÿ‘

I was looking for the same thing and figured out how to do it.

  1. add in the datasets the title:"dataTitle3" you want to show.

  2. use the data labeling plugin.

  3. simple code manipulation achieves what you want using
    dataset.title

I have made a sample but I think you could find out how and represent the data you want if you play with: external link

new Chart(document.getElementById("bubble-chart"), {
  type: 'bubble',
  data: {
    labels: "Africa",
    datasets: [{
      label: ["China"],
      backgroundColor: "rgba(255,221,50,0.2)",
      borderColor: "rgba(255,221,50,1)",
      title: "dataTitle1", //adding the title you want to show
      data: [{
        x: 21269017,
        y: 5.245,
        r: 15
      }]
    }, {
      label: ["Denmark"],
      backgroundColor: "rgba(60,186,159,0.2)",
      borderColor: "rgba(60,186,159,1)",
      title: "dataTitle2",
      data: [{
        x: 258702,
        y: 7.526,
        r: 10
      }]
    }, {
      label: ["Germany"],
      backgroundColor: "rgba(0,0,0,0.2)",
      borderColor: "#000",
      title: "dataTitle3", //adding the title you want to show
      data: [{
        x: 3979083,
        y: 6.994,
        r: 15
      }]
    }, {
      label: ["Japan"],
      backgroundColor: "rgba(193,46,12,0.2)",
      borderColor: "rgba(193,46,12,1)",
      title: "dataTitle4", //adding the title you want to show
      data: [{
        x: 4931877,
        y: 5.921,
        r: 15
      }]
    }]
  },
  options: {
    title: {
      display: true,
      text: 'Predicted world population (millions) in 2050'
    },
    scales: {
      yAxes: [{
        scaleLabel: {
          display: true,
          labelString: "Happiness"
        }
      }],
      xAxes: [{
        scaleLabel: {
          display: true,
          labelString: "GDP (PPP)"
        }
      }]
    }
  }
});

Chart.plugins.register({
  afterDatasetsDraw: function(chart, easing) {
    var ctx = chart.ctx;

    chart.data.datasets.forEach(function(dataset, i) {
      var meta = chart.getDatasetMeta(i);
      if (meta.type == "bubble") { //exclude scatter
        meta.data.forEach(function(element, index) {
          // Draw the text in black, with the specified font
          ctx.fillStyle = 'rgb(0, 0, 0)';
          var fontSize = 13;
          var fontStyle = 'normal';
          var fontFamily = 'Helvetica Neue';
          ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

          // Just naively convert to string for now
          var dataString = dataset.data[index].toString();
          // Make sure alignment settings are correct
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';

          var padding = 15;
          var position = element.tooltipPosition();
          ctx.fillText(dataset.title, position.x, position.y - (fontSize / 2) - padding);
        });
      } //if
    });
  }
});
<canvas id="bubble-chart" width="800" height="800"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

2๐Ÿ‘

ChartJs has a plugin now for this.

https://github.com/chartjs/chartjs-plugin-datalabels

Just install it using nuget or bower and add the reference of it. It wil automatically set z as label

0๐Ÿ‘

The sytax has changed with chart.js V3 in a few places so I thought Iโ€™d share my variation on the chosen answer.

Chart.register({
   id: 'permanentLabel',
   afterDatasetsDraw: function (chart, args, options) {
     var ctx = chart.ctx

     chart.data.datasets.forEach(function (dataset, i) {
       var meta = chart.getDatasetMeta(i)
       if (meta.type == 'bubble') {
         meta.data.forEach(function (element, index) {
           ctx.textAlign = 'center'
           ctx.textBaseline = 'middle'
           var position = element.tooltipPosition()
           ctx.fillText(dataset.data[index].label.toString(), position.x, position.y - dataset.data[index].r - Chart.defaults.font.size)
         })
       }
     })
   },
 })

example image of labels

0๐Ÿ‘

enter image description hereI have an some extra code, to avoid overlapping of labels.

var labelPlugin = {

        myTimeout: null,
        getNewYPostion:function(item, alreadyUsed, fontSize){
            for(let i of alreadyUsed){
                
                if((item.y_from >= i.y_from && item.y_from <= i.y_to) || (item.y_to>= i.y_from && item.y_to <= i.y_to)){
                    if((item.x_from >= i.x_from && item.x_from <= i.x_to) || (item.x_to>= i.x_from && item.x_to <= i.x_to)){
                        item.y_from=i.y_to+(fontSize*0.1);
                        item.y_to=item.y_from+fontSize;
                        return this.getNewYPostion(item, alreadyUsed, fontSize);
                    }
                }
            }
            return item;
        },
        afterDatasetsDraw: function (chart, args, options) {
            var ctx = chart.ctx;
            var that=this;

            clearTimeout(this.myTimeout);

            this.myTimeout = setTimeout(function () {

                var alreadyUsed = [];

                chart.data.datasets.forEach(function (dataset, i) {

                    var txt = dataset.label;
                    var txtSize = ctx.measureText(txt).width;

                    var meta = chart.getDatasetMeta(i);
                    if (meta.type === "bubble") { //exclude scatter

                        var fontSize = 10;
                        var fontStyle = 'normal';
                        var fontFamily = 'Helvetica Neue';
                        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
                        ctx.fillStyle = 'rgb(0, 0, 0)';
                        ctx.textAlign = 'left';
                        ctx.textBaseline = 'middle';
                        var padding, position, x_from, x_to, y, y_from, y_to;

                        meta.data.forEach(function (element, index) {

                            padding = element.options.radius;
                            position = element.tooltipPosition();
                            x_from = position.x + padding + 5; // left
                            x_to = x_from + txtSize; // left
                            y = position.y; // top
                            y_from = y - (fontSize * 0.5);
                            y_to = y + (fontSize * 0.5);

                            var item={
                                'y_from': y_from,
                                'y_to': y_to,
                                'x_from': x_from,
                                'x_to': x_to,
                            };

                            item=that.getNewYPostion(item, alreadyUsed, fontSize);
                            alreadyUsed.push(item);
                            ctx.fillText(txt, item.x_from, item.y_from+(0.5*fontSize));
                        });
                    } 
                });
            }, 500);
        }
    };

0๐Ÿ‘

In 2022 the current version is 3.9.1 here is a working snippet:

const $canvas = document.getElementById('chart')

const popData = {
  datasets: [{
    label: ['Deer Population'],
    data: [{
      x: 100,
      y: 0,
      r: 25,
      label: 'Russia',
    }, {
      x: 60,
      y: 30,
      r: 20,
      label: 'China',
    }, {
      x: 40,
      y: 60,
      r: 25,
      label: 'Canada',
    }, {
      x: 80,
      y: 80,
      r: 40,
      label: 'US',
    }, {
      x: 20,
      y: 30,
      r: 25,
      label: 'Africa',
    }, {
      x: 0,
      y: 100,
      r: 5,
      label: 'Europe',
    }],
    backgroundColor: "#FF9966"
  }]
};

const bubbleChart = new Chart($canvas, {
  type: 'bubble',
  data: popData
});

const fontSize = Chart.defaults.font.size
Chart.register({
  id: 'permanentLabel',
  afterDatasetsDraw: (chart, args, options) => {
    const ctx = chart.ctx
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'

    chart.data.datasets.forEach((dataset, i) => {
      const meta = chart.getDatasetMeta(i)
      if (meta.type !== 'bubble') return

      meta.data.forEach((element, index) => {
        const item = dataset.data[index]
        const position = element.tooltipPosition()
        ctx.fillText(item.label.toString(), position.x, position.y - item.r - fontSize)
      })
    })
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="chart" width="600" height="180"></canvas>

Leave a comment