Amazon did a great job with the monitoring in OpsWorks (see screenshot). You can point at any time in any of the area charts and see all values for all charts at that time.
Is it possible to achieve something similar with the Google Visualisation API?
I also have multiple (stacked) area charts and it's a pain to point at each datapoint to get the exact value. Some of them are overlapping or very close together.
You can't trigger the tooltips in all of the charts at the same time, but if you disable the built-in tooltips, you can achieve something similar by building out your tooltips in HTML and populating them manually in a "onmouseover" event handler:
function mouseOverHandler (e) {
// use e.row, e.column to find data and populate your tooltips
}
function mouseOutHandler (e) {
// clear the tooltips
}
google.visualization.events.addListener(chart1, 'onmouseover', mouseOverHandler);
google.visualization.events.addListener(chart1, 'onmouseout', mouseOutHandler);
google.visualization.events.addListener(chart2, 'onmouseover', mouseOverHandler);
google.visualization.events.addListener(chart2, 'onmouseout', mouseOutHandler);
// etc...
In your stacked area chart (assuming you do not replace the tooltips with a custom solution), you can set the focusTarget option to 'category' to make all values at a given x-axis value show up in the tooltip (works only within one chart, not across charts).
You can also cheat by putting all three charts in the same chart element with a little trickery (and some limitations). For instance, you can make the chart like this:
Here is the code for that (dummy data):
function drawVisualization() {
// Some raw data (not necessarily accurate)
var data = new google.visualization.DataTable();
data.addColumn('number', 'time');
data.addColumn('number', 'used');
data.addColumn('number', 'cached');
data.addColumn('number', 'free');
data.addColumn('number', 'user');
data.addColumn('number', 'system');
data.addColumn('number', 'io wait');
data.addColumn('number', '1 min');
data.addColumn('number', '5 min');
data.addColumn('number', '15 min');
data.addRows([
[1, {v:0.1, f:'10%'},{v:0.55, f:'45%'},{v:1, f:'45%'},{v:1.01, f:'0.15 GiB'},{v:1.83, f:'12.45 GiB'},{v:1.18, f:'2.7 GiB'},{v:2.28166561658701, f:'28.2%'},{v:2.38024858239246, f:'38.0%'},{v:2.42249842488051, f:'42.2%'}],
[2, {v:0.2, f:'20%'},{v:0.6, f:'40%'},{v:1, f:'40%'},{v:1.54, f:'8.1 GiB'},{v:1.47, f:'7.05 GiB'},{v:1.77, f:'11.55 GiB'},{v:2.53503269167234, f:'53.5%'},{v:2.74904576834128, f:'74.9%'},{v:2.4119751725877, f:'41.2%'}],
[3, {v:0.3, f:'30%'},{v:0.65, f:'35%'},{v:1, f:'35%'},{v:1.13, f:'1.95 GiB'},{v:1.15, f:'2.25 GiB'},{v:1.75, f:'11.25 GiB'},{v:2.73464579773048, f:'73.5%'},{v:2.85218912536736, f:'85.2%'},{v:2.80811037750353, f:'80.8%'}],
[4, {v:0.4, f:'40%'},{v:0.7, f:'30%'},{v:1, f:'30%'},{v:1.27, f:'4.05 GiB'},{v:1.86, f:'12.9 GiB'},{v:1.1, f:'1.5 GiB'},{v:2.86045009159487, f:'86.0%'},{v:2.92068159800651, f:'92.1%'},{v:2.54208355770477, f:'54.2%'}],
[5, {v:0.5, f:'50%'},{v:0.75, f:'25%'},{v:1, f:'25%'},{v:1.23, f:'3.45 GiB'},{v:1.12, f:'1.8 GiB'},{v:1.88, f:'13.2 GiB'},{v:2.89980619585711, f:'90.0%'},{v:2.8728120099814, f:'87.3%'},{v:2.75583720451997, f:'75.6%'}],
[6, {v:0.6, f:'60%'},{v:0.8, f:'20%'},{v:1, f:'20%'},{v:1.5, f:'7.5 GiB'},{v:1.78, f:'11.7 GiB'},{v:1.26, f:'3.9 GiB'},{v:2.84876005903125, f:'84.9%'},{v:2.66203284604438, f:'66.2%'},{v:2.63657004427344, f:'63.7%'}],
[7, {v:0.7, f:'70%'},{v:0.85, f:'15%'},{v:1, f:'15%'},{v:1.91, f:'13.65 GiB'},{v:1.26, f:'3.9 GiB'},{v:1.69, f:'10.35 GiB'},{v:2.71244021344925, f:'71.2%'},{v:2.78368423479417, f:'78.4%'},{v:2.69819140918026, f:'69.8%'}],
[8, {v:0.8, f:'80%'},{v:0.9, f:'10%'},{v:1, f:'10%'},{v:1.48, f:'7.2 GiB'},{v:1.51, f:'7.65 GiB'},{v:1.41, f:'6.15 GiB'},{v:2.50454251895529, f:'50.5%'},{v:2.59031474717769, f:'59.0%'},{v:2.33299806251049, f:'33.3%'}],
[9, {v:0.9, f:'90%'},{v:0.95, f:'5%'},{v:1, f:'5%'},{v:1.18, f:'2.7 GiB'},{v:1.53, f:'7.95 GiB'},{v:1.97, f:'14.55 GiB'},{v:2.24595415946281, f:'24.6%'},{v:2.24103507627355, f:'24.1%'},{v:2.22381828511115, f:'22.4%'}],
[10, {v:1, f:'100%'},{v:1, f:'0%'},{v:1, f:'0%'},{v:1.66, f:'9.9 GiB'},{v:1.61, f:'9.15 GiB'},{v:1.2, f:'3 GiB'},{v:2.1229770797314, f:'12.3%'},{v:2.13527478770454, f:'13.5%'},{v:2.14757249567768, f:'14.8%'}],
]);
// Create and draw the visualization.
var ac = new google.visualization.AreaChart(document.getElementById('visualization'));
ac.draw(data, {
title : 'Monthly Coffee Production by Country',
isStacked: false,
width: 600,
height: 400,
areaOpacity: 0.0,
focusTarget: 'category',
series: { 0: {areaOpacity: 0.5}, 1: {areaOpacity: 0.5}, 2: {areaOpacity: 0.5} },
vAxis: { ticks: [{v:0, f:""}, {v:0.5, f:"7.5 GiB"}, {v:1, f:"15.0 GiB"}, {v:1.5, f:"50%"}, {v:2, f:"100%"}, {v:2.5, f:"50%"}, {v:3, f:"100%"}, ] }
});
}
Basically, I put all 3 series on the same chart by putting them all as percentages of 1/3rd of the chart. So the first series is from 0-1, the second from 1-2, and the third from 2-3. I then used liberal quantities of {v:, f:} notation to make them look like different numbers (for the GiB particularly), and used the ticks option to make the axis look like it has 3 scales. Finally, I set focusTarget: 'category' so all lines get selected when you mouseover any of them.
You can format colors and even add dummy series to add thicker black lines between the series if you want to make them look more 'distinct'. You can also do some tricky stuff with dummy series and white areas and 100% opacity to potentially add background colors to higher areas. But the general concept is as outlined above, depending on what you are going for, it could work too.
I want following Google Chart (Column Chart) to show its first label on horizontal axis. Also I want each column to have same width; first and last column need a change. How is it possible?
var chartDataRaw = [{
"month": "201211",
"articles": 41467
}, {
"month": "201212",
"articles": 31820
}, {
"month": "201301",
"articles": 43817
}, {
"month": "201302",
"articles": 42773
}, {
"month": "201303",
"articles": 38695
}, {
"month": "201304",
"articles": 41257
}];
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('date', 'Month');
dataTable.addColumn('number', 'Articles');
var i = 1;
//chartDataRaw is array of objects, requested from server. looped through jquery each to fill dataTable
$.each(chartDataRaw, function () {
var year = this.month.substring(0, 4);
var month = this.month.substring(4);
var dataItem = [new Date(year, month), this.articles];
dataTable.addRow(dataItem);
});
var options = {
title: 'Company Coverage',
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px'
},
vAxis: {
textPosition: 'none'
},
trendlines: {
0: {
color: 'black',
lineWidth: 3,
opacity: 0.4
}
},
legend: 'none'
};
var monthYearFormatter = new google.visualization.DateFormat({
pattern: "MMM, yyyy"
});
monthYearFormatter.format(dataTable, 0); //change date format to render on chart
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(dataTable, options);
http://jsfiddle.net/YyYsN/2/
Edit: Added chart data
Executive Summary
You are committing several mortal sins:
You are not defining dates right
You have no y axis values distorting your data
You are using columns to describe a continuous series
You are predicting based on only 6 data points
You are not defining dates right
Look at the value for January 2013. It says 31,820 articles. The issue is your data says there were 43,817 articles in January. What the heck is going on?
Javascript Date Objects use month values from 0-11, not 1-12. That means when you convert the dates, you need to change your function.
Old:
var dataItem = [new Date(year, month), this.articles];
New:
var dataItem = [new Date(year, month - 1), this.articles];
You have no y axis values distorting your data
Compare the second bar to the third bar. What is the ratio between the two? It looks like the second bar is around .5 gridlines, and the third bar is around 3.5 gridlines. That is a 700% increase in articles!
Only if you look at the data, it's actually going from 31,820 to 43,817, and increase of only 37%.
Bar charts should always start from zero, otherwise you get incredibly distorted perspective of the data, especially when there are no labels to boot.
Old:
vAxis: {
textPosition: 'none',
},
New:
vAxis: {
textPosition: 'none',
minValue: 0
},
You are using columns to describe a continuous series
Columns show discrete items. If I want to poll how many kids in a class like dogs, cats, and iguanas, a column chart is great since it allows me to compare the popularity (height) across unrelated categories (horizontal). Columns are okay for showing sales per month (or articles per month), but by making them columns you are implying that the columns should be compared as individual items, not as a progressing series.
If you want to show that these data items are connected (as implied by the trendline) it would make much more sense to show an area chart.
(Ideally, the area chart would show articles over the last 30 days, and have daily data, rather than a monthly compilation since months are arbitrary cutoffs, and things like weekends and holidays probably have a significant impact on your data which further distorts what you're trying to show).
Old
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
New
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
You are predicting based on only 6 data point
Six points does not a trend make. Your data's highest value is the second point, yet you are showing the trend increasing over time. Perhaps the trendline suggests an upward trend (since the later values are higher than the first value), but as soon as you move 1 month forward you will have a descending trendline (barring a massive increase in articles).
This makes no rational sense. 5 months of data are the same. How can changing 1 month of a 6-month series change the direction of the trendline? Forecasting is iffy-enough as it is (see the Black Swan theory), but doing it on a minimal 6-month series likely isn't the best. This means the trendline should probably be removed altogether since it not only doesn't convey useful information, it potentially conveys incorrect information.
Summary
That said, if you just want your left and right columns not to be cut off, you can change the following code:
Old
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px',
},
New
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px',
minValue: new Date(2012,9),
maxValue: new Date(2013,4)
},
fixed it myself by changing corechart visualization version to 1.1
google.load("visualization", "1.1", {packages:["corechart"]});
I have been using Area Chart for one of my project. I want the area chart to show full grid lines, and come to find out that it will only show if you have number or date data on major axis. Well I want year on major axis. But putting year as number, display that with number format. Something like this... 2005 displays 2005.00 .
I have found out by going through documentation that data can be passed in this format - {v:2005, f:'2005'}. But this is not working when I pass the value in this format using google.visualization.arrayToDataTable().
json data I was trying to pass on has format something like this -
[["Years", "sales"],[{v:2005, f:'2005'}, 52450],[{v:2006, f:'2006'}, 63457]]
But the chart is not coming up... :(
If you want to use the {v:2005,f:'2005'} trick, you can't use ArrayToDataTable, you need to define the DataTable somewhat differently. You can see a similar problem here:
Not Working DataTable:
var data = google.visualization.arrayToDataTable([
['Category', 'Amount'],
['Food', {v:5595.819984, f:'5.595,82'}],
['Home', {v:1890.530002, f:'1.890,53'}],
['Mail', {v:8.380000, f:'8,38'}],
['Train', {v:564.899998, f:'564,90'}],
['Photo', {v:959.119995, f:'959,12'}],
['Lego', {v:428.760004, f:'428,76'}],
Working DataTable:
var data = google.visualization.DataTable();
data.addColumn('string', 'Category');
data.addColumn('number', 'Amount');
data.addRows([
['Food', {v:5595.819984, f:'5.595,82'}],
['Home', {v:1890.530002, f:'1.890,53'}],
['Mail', {v:8.380000, f:'8,38'}],
['Train', {v:564.899998, f:'564,90'}],
['Photo', {v:959.119995, f:'959,12'}],
['Lego', {v:428.760004, f:'428,76'}],
]);
The tooltips can be set to display percentages using the following code:
var formatter = new google.visualization.NumberFormat({
fractionDigits: 2,
suffix: '%'
});
formatter.format(data, 1); // Apply formatter to first column.
Is there a way for NumberFormat to multiply each element by 100? Otherwise the tooltip appears as .50%.
I am using vAxis.format = "format:'#%' " which does multiply by 100. So .5 is displayed as 50% on the vertical axis.
According to the documentation(icu-project.org/apiref), this can be overwritten by enclosing the % in single quotes, but this did not work.
The net result is that the tooltips do not match the axis. What is the best way to do this?
I got this working by specifying a formatter exactly as you do:
var chartData = google.visualization.arrayToDataTable(tableData);
var formatter = new google.visualization.NumberFormat({
fractionDigits: 2,
suffix: '%'
});
formatter.format(chartData, 1);
The 1 in the last call means the second column, in which I have float values.
Then I specify a format for the axis in the chart options, escaping the percentage sign as pointed out by documentation and others here:
var chartOptions = {
vAxis: { format: '#\'%\'' }
};
I then draw the chart:
var chart = new google.visualization.ColumnChart(document.getElementById('chart'));
chart.draw(chartData, chartOptions);
This renders a left side axis with values like 10%, 20% and so on. And the tooltips looks like the default one but with a percentage like 10.10%, 20.20% and so on.
If you want two fraction digits in the left side axis as well, use this as format in the chart options instead:
vAxis: { format: '#.00\'%\'' }
var formatter = new google.visualization.NumberFormat({
pattern: '#%',
fractionDigits: 2
});
Thanks to http://groups.google.com/group/google-visualization-api/
You must surround the percent (%) symbol itself in single quotes.
The line I used to do this looks like this: options['vAxis'] = {'format': "#,###'%'"};
Combining this with your formatter above, you can make the vertical axis have a percent symbol and also make the tooltip include it too.
Ok... So this is a little late. I admit I didn't need this seven years ago. Nevertheless, this worked for me.
var rows = data.getNumberOfRows();
for (var i = 0; i < rows; i++) {
data.setFormattedValue(i, 4, (data.getFormattedValue(i, 4)*100).toFixed(1) + "%"); //LY
data.setFormattedValue(i, 3, (data.getFormattedValue(i, 3)*100).toFixed(1) + "%"); //TY
}
In my case, I am using four columns, two of which are assigned to the right axis with percentages. I wanted those columns' tooltips to reflect the proper percentage rather than the decimal representation.
Here is a link to the Google docs:
https://developers.google.com/chart/interactive/docs/reference#DataTable_setFormattedValue
I hope this helps some random stranger looking for it. ;)