Reputation: 7592
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.
Upvotes: 6
Views: 2295
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