1

I am trying to achieve something like this using chart.js. I wanted to show data of male/female according to each age group:

Here is my chart options:

var options = {
    layout: {
        padding: {
            top: 5,
        }
    },
    scales:
    {
        yAxes: [{
            display: true,
            barPercentage: 0.4,
            ticks: {
                fontSize: 12
            },
            stacked: true,
        }],
        xAxes: [{
            stacked: true,
        }]
    },
    responsive: true,
    maintainAspectRatio: false,
    legend: {
        display: false,
    },
    animation: {
        animateScale: true,
        animateRotate: true
    },
};

var opt = {
    type: "horizontalBar",
    data: {
        labels: ageGroup,
        datasets: [{
            label: 'Male',
            data: maleData,
            backgroundColor: '#2196F3',
            hoverBackgroundColor: '#2196F3'
        },
        {
            label: 'Female',
            data: femaleData,
            backgroundColor: '#E91E63',
            hoverBackgroundColor: '#E91E63'
        }]
    },
    options: options
};

I changed the positive in femaleData array into a negative number to achieve the result above:

for (var i = 0; i < femaleData.length; i++) {
    femaleData[i] = -Math.abs(femaleData[i]);
}

However, the y-axis at 0 is not centralized as it pushed to the right hand side since left hand side got more data. I not even sure if this is the correct way to set the chart in opposite direction. How can I do this correctly?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
QWERTY
  • 2,303
  • 9
  • 44
  • 85
  • Yes this is the correct way and it's an expected behavior! – ɢʀᴜɴᴛ Aug 06 '17 at 10:29
  • But then the x axis for the one growing towards left is showing negative value. Is there any way to make it positive or so? Also, the value when hover over the bar is showing negative as well. Is there any way to override it? Because I can't seem to find any example regarding this, but I saw some with Google chart is able to do so. – QWERTY Aug 06 '17 at 10:51
  • Yes, there is a way! You want something like [this](https://i.stack.imgur.com/1jnvY.png) ? – ɢʀᴜɴᴛ Aug 06 '17 at 12:10
  • Yeap that is what I am trying to achieve. I played a trick by setting the female one to negative values :p – QWERTY Aug 06 '17 at 12:18

1 Answers1

3

as per the requirements mentioned in OP­'s comment section

ꜱʜᴏᴡ ᴘᴏꜱɪᴛɪᴠᴇ ᴠᴀʟᴜᴇꜱ ᴏɴ x-ᴀxɪꜱ

use the following callback function for x-axis ticks :

callback: function(t, i) {
   return t < 0 ? Math.abs(t) : t;
}

ꜱʜᴏᴡ ᴘᴏꜱɪᴛɪᴠᴇ ᴠᴀʟᴜᴇ ᴏɴ ᴛᴏᴏʟᴛɪᴘ

use the following callback function for tooltips :

callbacks: {
   label: function(t, d) {
      var datasetLabel = d.datasets[t.datasetIndex].label;
      var xLabel = Math.abs(t.xLabel);
      return datasetLabel + ': ' + xLabel;
   }
}

ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩

var ageGroup = ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80', '80+'];
var maleData = [30, 0, 0, 0, 10, 0, 0, 0, 0];
var femaleData = [0, 0, 0, -20, -50, -20, 0, 0, 0];

var options = {
   layout: {
      padding: {
         top: 5,
      }
   },
   scales: {
      yAxes: [{
         display: true,
         barPercentage: 0.4,
         ticks: {
            fontSize: 12
         },
         stacked: true,
      }],
      xAxes: [{
         stacked: true,
         ticks: {
            callback: function(t, i) {
               return t < 0 ? Math.abs(t) : t;
            }
         }
      }]
   },
   tooltips: {
      callbacks: {
         label: function(t, d) {
            var datasetLabel = d.datasets[t.datasetIndex].label;
            var xLabel = Math.abs(t.xLabel);
            return datasetLabel + ': ' + xLabel;
         }
      }
   },
   responsive: true,
   //maintainAspectRatio: false,
   legend: {
      display: false,
   },
   animation: {
      animateScale: true,
      animateRotate: true
   },
};

var opt = {
   type: "horizontalBar",
   data: {
      labels: ageGroup,
      datasets: [{
         label: 'Male',
         data: maleData,
         backgroundColor: '#2196F3',
         hoverBackgroundColor: '#2196F3'
      }, {
         label: 'Female',
         data: femaleData,
         backgroundColor: '#E91E63',
         hoverBackgroundColor: '#E91E63'
      }]
   },
   options: options
};

new Chart(ctx, opt);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>
ɢʀᴜɴᴛ
  • 32,025
  • 15
  • 116
  • 110
  • Thanks so much!!!! But then is there any way to centralized the axis for 0? because it seems kinda pushed towards right hand side – QWERTY Aug 06 '17 at 12:35
  • Not sure if it would be appropriate for your case or not, but you could set `min` value for x-axis ticks, like - `min: -2.0` *(tho, it's not recommended, what you're seeing is the correct behavior)* – ɢʀᴜɴᴛ Aug 06 '17 at 12:41
  • I have opened up another thread: https://stackoverflow.com/questions/45630315/chart-js-legend-took-up-too-much-spaces Do you mind to take a look? – QWERTY Aug 11 '17 at 08:23