Devin Crossman
Devin Crossman

Reputation: 7592

google visualizations align 0 axis with two different y-axes

I'm creating a combochart with google's visualization library. I'm charting a store's traffic and revenue over the course of a day. I have set my draw options to

var options = {
  seriesType: "bars",
  series:{0:{targetAxisIndex:0},1:{targetAxisIndex:1}},
  vAxes:{0:{title: "Revenue"},1:{title: "Traffic"}},
  hAxis: {title: "Time", showTextEvery: 1},
};

which sets up the Revenue on a different Y-axis than the traffic. A sample of the data might look like this:

var data = [
  //   Time       Revenue Traffic
  ['10:00-10:30', '132.57', '33'],
  ['10:30-11:00', '249.23', '42'],
  ['11:00-11:30', '376.84', '37'],
  [... etc ..]
];

the problem I'm having is that Traffic values will always be positive whereas Revenue could be a negative number if there were returns. If that happens my Revenue axis will start at a negative value like -50 while Traffic starts at 0 and the horizontal baselines don't line up. I would like to have it so that even if Revenue has values less than 0 it's 0 axis will line up with the Traffic 0 axis.

Here's an example to show what's happening. See how the Traffic 0 axis is on the same level as the Revenue's -50 axis. I would like to know how to raise the Traffic baseline to the same level as the Revenue 0 axis. enter image description here

Upvotes: 6

Views: 2295

Answers (1)

asgallant
asgallant

Reputation: 26340

I have a method that I am reasonably certain will always produce axis values with the same 0 point (I haven't proved that it can't produce axes with different 0 points, but I haven't encountered any).

To start off, get the range of the two date series (for our purposes, column 1 is "revenue" and column 2 is "traffic"):

var range1 = data.getColumnRange(1);
var range2 = data.getColumnRange(2);

For each series, get the max value of the series, or 1 if the max is less than or equal to 0. These values will be used as the upper bounds of the chart.

var maxValue1 = (range1.max <= 0) ? 1 : range1.max;
var maxValue2 = (range2.max <= 0) ? 1 : range2.max;

Then calculate a scalar value relating the two upper bounds:

var scalar = maxValue2 / maxValue1;

Now, calculate the lower bounds of the "revenue" series by taking the lower of range1.min and 0:

var minValue1 = Math.min(range1.min, 0);

then multiply that lower bound by the scalar value to get the lower bound of the "traffic" series:

var minValue2 = minValue1 * scalar;

Finally, set the vAxis minValue/maxValue options for each axis:

vAxes: {
    0: {
        maxValue: maxValue1,
        minValue: minValue1,
        title: 'Revenue'
    },
    1: {
        maxValue: maxValue2,
        minValue: minValue2,
        title: 'Traffic'
    }
}

The net result is that positive and negative proportions of each series are equal (maxValue1 / (maxValue1 - minValue1 == maxValue2 / (maxValue2 - minValue2 and minValue1 / (maxValue1 - minValue1 == minValue2 / (maxValue2 - minValue2), which means the chart axes should end up with the same positive and negative proportions, lining up the 0's on both sides.

Here's a jsfiddle with this working: http://jsfiddle.net/asgallant/hvJUC/. It should work for any data set, as long as the second data series has no negative values. I'm working on a version that will work with any data sets, but this should suffice for your use case.

Upvotes: 3

Related Questions