Google Charts vertical axis in whole numbers

I am trying to configure a Google column chart to display the vertical axis in whole numbers but when it is displaying a small number such as 1 it displaying 0.25, 0.50 etc as well.

Is there anyway to change this? I have been through the documentation and can't find anything that seems relevant.

Thanks


Solution 1:

Simple answer: yes, but it's complicated.

If you just want numbers to display as whole numbers, then it's easy:

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['x', 'Cats', 'Blanket 1', 'Blanket 2'],
    ['A',   1,       1,           0.5],
    ['B',   2,       0.5,         1],
    ['C',   4,       1,           0.5],
    ['D',   8,       0.5,         1],
    ['E',   7,       1,           0.5],
    ['F',   7,       0.5,         1],
    ['G',   8,       1,           0.5],
    ['H',   4,       0.5,         1],
    ['I',   2,       1,           0.5],
    ['J',   3.5,     0.5,         1],
    ['K',   3,       1,           0.5],
    ['L',   3.5,     0.5,         1],
    ['M',   1,       1,           0.5],
    ['N',   1,       0.5,         1]
  ]);

  // Create and draw the visualization.
  new google.visualization.LineChart(document.getElementById('visualization')).
      draw(data, {curveType: "function",
                  width: 500, height: 400,
                  vAxis: {maxValue: 10, format: '0'}}
          );
}

If you go to google playground you will note that the axis labels are 0, 2.5, 5, 7.5, 10. By adding the format: '0' to the vAxis, it will display only whole numbers, so my labels become 0, 3, 5, 8, 10. But obviously this is not ideal since 8 displays as being halfway between 5 and 10, which it isn't, because the number is actually 7.5 and just being rounded.

Your ability to change the axis scale/labels is restricted. And to do what you're asking would take a special bit of javascript to create an appropriate scale and number of gridlines to prevent breaking things down in to funky numbers.

Basically, you want to make sure that your maximum and minimum values, and number of gridlines, allow for easy division such that you will only get whole numbers. To do that, you need to create some funky new logic. Here is some sample code that will allow you to get an appropriate min/max axis value:

// Take the Max/Min of all data values in all graphs
var totalMax = 345;
var totalMin = -123;

// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));

// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);

// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;

// Determine the range of your values
var range = newMax - newMin;

// Define the number of gridlines (default 5)
var gridlines = 5;

// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);

// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;

// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;

There are a couple issues here (unfortunately). The first is that I am using the number of gridlines to determine the min/max values -- you want to figure out how many gridlines you should have to use nice whole numbers. The easiest way to do this, I think, would be as follows (pseudo-code only):

// Take the Max/Min of all data values in all graphs
var totalMax = 3;
var totalMin = -1;

// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));

// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);

// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;

// Determine the range of your values
var range = newMax - newMin;

// Calculate the best factor for number of gridlines (2-5 gridlines)
// If the range of numbers divided by 2 or 5 is a whole number, use it
for (var i = 2; i <= 5; ++i) {
    if (Math.round(range/i) = range/i) {
        var gridlines = i
    }
}

Then you set the gridlines option (vAxis.gridlines) to the above variable, and your max to newMax, and your min to newMin. That should give you whole number axis labels.

Note: if your numbers are really small then the above function may not work. The function is also not tested so please check it against some examples on your own time and let me know if it doesn't work properly.

Solution 2:

Just to expand on jmac's answer. If you know the maximum value of the chart, the solution is simple providing maxvalue ensures you always use the same height for the chart.

If your content is very dynamic however his solution seems to be the only one.