Google Charts: Horizontal Reference Line on Barchart - charts

Having a Barchart like the following
I want to be able to draw an horizontal reference line (For example at 80%). However this doesn't seem to be possible on Google Charts.
I've tried several things, including combo charts with multiple series.
However it won't look very nice since the hAxis is discrete :(
Your help would be very appreciated.

add another series for the Reference Line
use the same value for all rows and change the series type to 'line'
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Category', 'Value', 'Reference'],
['Quant', 0.10, 0.80],
['Verbal', 0.30, 0.80],
['Total', 0.20, 0.80]
]);
var chartDiv = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(chartDiv);
chart.draw(data, {
colors: ['lime', 'magenta'],
legend: 'none',
series: {
1: {
type: 'line'
}
},
title: 'Percentile Score',
vAxis: {
format: 'percent',
viewWindow: {
min: 0,
max: 1
}
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
in the above snippet, the reference line stops at the center of the first and last columns
extend the line to the edges of the columns by changing the coordinates of the reference line,
use the 'ready' listener to know when the chart has been drawn
the key is finding the specific chart elements you need to work with,
in the following snippet, the series color is used to find the columns and reference line
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Category', 'Value', 'Reference'],
['Quant', 0.10, 0.80],
['Verbal', 0.30, 0.80],
['Total', 0.20, 0.80]
]);
var chartDiv = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(chartDiv);
// use colors to find chart elements
var colorMagenta = '#ff00ff';
var colorLime = '#00ff00';
var xBeg; // save first x coord
var xWidth; // save width of column
var rowIndex = -1; // find first column
google.visualization.events.addListener(chart, 'ready', function () {
// columns
Array.prototype.forEach.call(chartDiv.getElementsByTagName('rect'), function(rect, index) {
if (rect.getAttribute('fill') === colorLime) {
rowIndex++;
xWidth = parseFloat(rect.getAttribute('width')) / 2;
if (rowIndex === 0) {
xBeg = parseFloat(rect.getAttribute('x'));
}
}
});
// reference line
Array.prototype.forEach.call(chartDiv.getElementsByTagName('path'), function(path, index) {
if (path.getAttribute('stroke') === colorMagenta) {
// change line coords
var refCoords = path.getAttribute('d').split(',');
refCoords[0] = 'M' + xBeg;
var refWidth = refCoords[2].split('L');
refWidth[1] = parseFloat(refWidth[1]) + xWidth;
refCoords[2] = refWidth.join('L');
path.setAttribute('d', refCoords.join(','));
}
});
});
chart.draw(data, {
colors: [colorLime, colorMagenta],
legend: 'none',
series: {
1: {
type: 'line'
}
},
title: 'Percentile Score',
vAxis: {
format: 'percent',
viewWindow: {
min: 0,
max: 1
}
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

Google LineChart - How to draw vertical axis line based on a max value. Lines stops before the max value

I have a Google LineChart where I need to draw the vertical axis lines based on a max value. Here is the scenario:
var options = {
vAxis: {
viewWindow: {
min: 0,
max: verticalAxisMaxValue // for my case it is 789. but could be anything.
},
gridlines: {
count: 10 // or something else
}
}
}
The value of verticalAxisMaxValue is determined before options is declared.
What I need is to draw the vertical axis lines to be drawn up to verticalAxisMaxValue (it could be anything like 789, 858, 560, ...) The problem I am having is the axis lines are being drawn but the line with the highest value never goes up to the verticalAxisMaxValue.
Please see the screenshot.
Here the highest value is 700, but I need to draw a line at 789. And the similar should happen for any verticalAxisMaxValue.
How can I do this?
viewWindow controls the visible range of the axis,
not necessarily the labels displayed on the axis.
to control the labels, you need to supply the ticks option.
the ticks option is an array of values, of the same type as on the axis.
it could be date, number, etc.
in this case, we can use the max value to build our ticks.
you will need to determine how much each label should increment by,
such as 100
here, we set the max, then add a tick for each 100 under the max,
then add the max as well to the ticks.
var verticalAxisMaxValue = 789;
var ticks = [];
for (var i = 0; i < verticalAxisMaxValue; i = i + 100) {
ticks.push(i);
}
ticks.push(verticalAxisMaxValue);
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Month', 'GROWTH TARGET'],
['Apr', 145],
['May', 169],
['Jun', 201],
['Jul', 231],
['Aug', 281],
['Sep', 325],
['Oct', 369],
['Nov', 444],
['Dec', 478]
]);
var verticalAxisMaxValue = 789;
var ticks = [];
for (var i = 0; i < verticalAxisMaxValue; i = i + 100) {
ticks.push(i);
}
ticks.push(verticalAxisMaxValue);
var options = {
vAxis: {
ticks: ticks,
viewWindow: {
min: 0,
max: verticalAxisMaxValue
}
}
};
var chart = new google.visualization.LineChart(document.getElementById('chart'));
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>

How to align v axis label w.r.t chart window in google charts?

The y asis labels of my google charts are aligned with respect to the vertical bar while I want them to be aligned with the margin of the chart. I looked everywhere. Can anyone help. The left to right and right to left uses thechart margin as reference not the chart area left margin.
no options for label alignment...
but you can move them manually when the chart's 'ready' event fires
you can use the following chart method to get the bounds of each label
getChartLayoutInterface().getBoundingBox(id)
then set the labels's x attribute to the same value as the width
if the labels need more room, use option --> chartArea.left
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = new google.visualization.DataTable();
data.addColumn('string', 'x');
data.addColumn('number', 'y0');
data.addRows([
['Brain Tree', 200],
['One Touch', 220],
['PayPal Email', 240],
['PayPal Here', 260],
['PayPal Invoice', 280],
['PayPal Mas', 300]
]);
var container = document.getElementById('chart_div');
var chart = new google.visualization.BarChart(container);
google.visualization.events.addListener(chart, 'click', function (gglClick) {
console.log(JSON.stringify(gglClick));
});
google.visualization.events.addListener(chart, 'ready', function () {
var chartLayout = chart.getChartLayoutInterface();
var labelIndex = -1;
var labelWidth;
var axisLabels = container.getElementsByTagName('text');
Array.prototype.forEach.call(axisLabels, function(label) {
if (label.getAttribute('text-anchor') === 'end') {
labelIndex++;
labelWidth = chartLayout.getBoundingBox('vAxis#0#label#' + labelIndex).width;
label.setAttribute('x', labelWidth);
}
});
});
chart.draw(data, {
chartArea: {
left: 128
},
height: 600
});
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Just provide is-stacked as true in option if you want to align Y-axis names with bar
options={ isStacked: true}

Google Charts - HTML axis label and title

So I am trying to make html axis labels in google charts. However there does not seem to be any support for creating the axis labels or the title as HTML objects. The title is easy enough to fix, just add it in as a separate HTML object to the page, but the axis labels are more challenging. Has anyone been able to do this? As an example the below jsfiddle should show what happens when you attempt to use simple sub and sup html tags.
https://jsfiddle.net/jqmya8j9/1/
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable =
google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'X<sub>m</sub> versus X<sup>2</sup>',
//best guess, does nothing
titleTextStyle: {isHtml: true},
hAxis: {title: 'X<sub>m</sub>'},
vAxis: {title: 'X<sup>2</sup>'}
};
chart = new
google.visualization.ScatterChart(document.body);
chart.draw(dataTable, options);
});
Based on the below answer (Thanks!), and what I am actually doing, I wrote the following general rule for this using _{} and ^{} instead of < sub > and < sup >
https://jsfiddle.net/jqmya8j9/2/
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable =
google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'X_{m} versus X^2',
hAxis: {title: 'X_m'},
vAxis: {title: 'X^{2}'}
};
chart = new
google.visualization.ScatterChart(document.body);
google.visualization.events.addListener(chart, 'ready', function () {
$.each($('text'), function (index, label) {
var labelText = $(label).text();
if (labelText.match(/_|\^/)) {
labelText = labelText.replace(/_([^\{])|_\{([^\}]*)\}/g, '<tspan style="font-size: smaller;" baseline-shift="sub">$1$2</tspan>')
labelText = labelText.replace(/\^([^\{])|\^\{([^\}]*)\}/g, '<tspan style="font-size: smaller;" baseline-shift="super">$1$2</tspan>')
$(label).html(labelText);
}
});
});
chart.draw(dataTable, options);
});
the labels will only accept text...
the chart is drawn with svg, which can be changed manually when the 'ready' event fires
the labels will be <text> elements
to change the font style inline, use svg <tspan> elements within <text>
e.g.
<text>X<tspan baseline-shift="super">m</tspan></text>
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = [['X','Y']], i, options,
chart, dataTable;
for (i = 0; i < 20; i += 1) {
data.push([i, i * i]);
}
dataTable = google.visualization.arrayToDataTable(data);
options = {
legend: 'none',
title: 'Xm versus X2',
hAxis: {title: 'Xm'},
vAxis: {title: 'X2'}
};
chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'ready', function () {
$.each($('text'), function (index, label) {
var labelText = $(label).text();
if (labelText.indexOf('X') > -1) {
labelText = labelText.replace(new RegExp(/m/g), '<tspan baseline-shift="super">m</tspan>');
labelText = labelText.replace(new RegExp(/2/g), '<tspan baseline-shift="super">2</tspan>');
$(label).html(labelText);
}
});
});
chart.draw(dataTable, options);
},
packages: ['corechart']
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

How to prevent Google Charts from changing x-axis order?

I'm trying to draw a Google Chart whose x-axis represents the week numbers. As we're crossing a new year, the axis goes 50, 51, 52, 1, 2, 3, ....
I'm properly ordering my data, but Google Charts insists on reordering my x-axis, and I end up with a weird graph:
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
google.load("visualization", "1", {
packages:["corechart"],
callback: function() {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable);
}});
<div id="chart" style="height: 400px;">test</div>
<script src="//www.google.com/jsapi"></script>
How can I prevent it from reordering my data?
google's object notation allows you to provide a value (v:) and a formatted value (f:)
thus, you can use a value of 1 with a format of '40'
e.g. --> {v: 1, f: '40'}
in a row --> [{v: 1, f: '40'},227]
the following working snippet uses object notation to re-format the values for the x-axis,
and re-use those values for the x-axis labels (hAxis.ticks)
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
var hAxisTicks = [];
chartData.forEach(function (row, index) {
if (index === 0) {
return;
}
row[0] = {
v: index,
f: row[0].toString()
};
hAxisTicks.push(row[0]);
});
google.charts.load('current', {
callback: function () {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable, {
hAxis: {
ticks: hAxisTicks
}
});
},
packages:['corechart']
});
<div id="chart"></div>
<script src="https://www.gstatic.com/charts/loader.js"></script>
note:
recommend using loader.js to load the the library, instead of jsapi
according to the release notes...
The version of Google Charts that remains available via the jsapi loader is no longer being updated consistently. Please use the new gstatic loader from now on.
this only changes the load statement, see snippet above...
EDIT:
there are more options available for continuous axis
which must be sorted, or in reverse sort order ('number', 'date' values)
but the chart will respect the original sort order for a discrete axis ('string' values)
see following snippet for 'string' values
and discrete vs. continuous for more...
var chartData = [
["Week","Revenue"],
[40,227],
[41,317],
[42,320],
[43,482],
[44,418],
[45,345],
[46,313],
[47,316],
[48,380],
[49,467],
[50,349],
[51,256],
[52,393],
[1,276],
[2,349],
[3,312]
];
chartData.forEach(function (row, index) {
if (index === 0) {
return;
}
row[0] = row[0].toString();
});
google.charts.load('current', {
callback: function () {
var div = document.getElementById('chart');
var chartDataTable = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization['LineChart'](div);
chart.draw(chartDataTable);
},
packages:['corechart']
});
<div id="chart"></div>
<script src="https://www.gstatic.com/charts/loader.js"></script>

Google charts different colors w/ single series Material bar chart

Using {role: 'style'} I can apply different colors to a single series bar chart. But if I use the new Google "Material" barcharts, I can't.
"regular" Google charts (works):
google.load("visualization", '1.1', {packages:['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Element', 'Density', {role: 'style'} ],
['Copper', 8.94, 'color: #FF9900'],
['Silver', 10.49,'color: #109618'],
['Gold', 19.30,'color: #3B3EAC'],
['Platinum', 21.45,'color: #0099C6']
]);
var view = new google.visualization.DataView(data);
var options = {
title: "Density of Precious Metals, in g/cm^3",
width: 600,
height: 400,
bar: {groupWidth: '85%'},
legend: { position: 'none' },
};
var chart = new google.visualization.ColumnChart(document.getElementById('barchart_values'));
chart.draw(view, options);
}
Same chart but using Google "Material" bar chart (different colors are not applied)
google.load("visualization", "1.1", {packages:["bar"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Element', 'Density', { role: 'style' } ],
['Copper', 8.94, 'color: #FF9900'],
['Silver', 10.49,'color: #109618'],
['Gold', 19.30,'color: #3B3EAC'],
['Platinum', 21.45,'color: #0099C6']
]);
var view = new google.visualization.DataView(data);
var options = {
title: "Density of Precious Metals, in g/cm^3",
width: 600,
height: 400,
bar: {groupWidth: '95%'},
legend: { position: 'none' },
};
options = google.charts.Bar.convertOptions(options);
var chart = new google.charts.Bar(document.getElementById('barchart_values'));
chart.draw(view, options);
}
It really seems impossible. There is no clou anywhere for Material Charts using individual colors, and if you set a color array the old way, like colors: [...] the Material Chart just adopt the first color and add this to all the bars. I believe this is not implemented in Material Charts at all (yet?).
But if you really want to colorize the bars, you can do it by code :
function colorize() {
var colors = ['#FF9900', '#109618', '#3B3EAC', '#0099C6'],
svg = document.getElementById('barchart_values').querySelector('svg'),
bars = svg.querySelectorAll('path');
for (var i=0;i<bars.length;i++) {
if (i !== selected) bars[i].setAttribute('fill', colors[i]);
}
}
colors[] are the colors from your data DataTable above. It is safe just to target <path>'s, since the paths that visualizes the bars are the only one present inside the <svg>.
This function can be triggered by the ready event :
google.visualization.events.addListener(chart, 'ready', colorize);
Since the chart is continuously redrawn upon select and onmouseover, attach listeners to those events too :
google.visualization.events.addListener(chart, 'select', colorize);
google.visualization.events.addListener(chart, 'onmouseover', colorize);
and let the user be able to select a bar, i.e dont redraw a selected bar :
function colorize() {
var colors = ['#FF9900', '#109618', '#3B3EAC', '#0099C6'],
selection = chart.getSelection(),
selected = selection[0] ? selection[0].row : -1,
svg = document.getElementById('barchart_values').querySelector('svg'),
bars = svg.querySelectorAll('path');
for (var i=0;i<bars.length;i++) {
if (i !== selected) bars[i].setAttribute('fill', colors[i]);
}
}
your Material Chart added with the code from above -> http://jsfiddle.net/o00oayvu/
This one helps me out
var tmpColors = new Array(['orange'],['purple'],['red'],['green']);
loop{
.....
.....
options.colors = tmpColors[i];
....
....
}