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 had some code that set my V axis scale from 0 - 4. However I deleted it and now I cannot remember how I got it working again. See below for my chart code, and the code I think I used before.
This is what I think I used before...
vAxis: {
viewWindowMode:'explicit',
viewWindow: {
max:100,
min:99.8
}
}
Below is my chart
// Create a line chart, passing some options
var LineChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'chart_div',
'options': {
//'width': 300,
'height': 300,
'legend': 'top',
'backgroundColor': '#eeeeee',
'colors': [ '#8ea23f'],
'pointSize': 5,
'title': 'Selected Site and Species abundance over time'
},
'view':{'columns':[0,2]},
});
There you go:
'vAxis': {'title': 'Something Here',
'minValue': 0,
'maxValue': 4},
There are two approaches to take, depending on what you need. The first one (shown by Tom's answer) sets alternative min and max values for the data set sent to the chart, eg. the chart interprets the maximum data value is must accommodate as MAX(vAxis.maxValue, data set max value). If the data set goes outside the bounds of vAxis.minValue/maxValue, those options will essentially be ignored. Also, the chart's actual axis range is only based on the min/max values - the values displayed will include the min/max, but might go beyond the min/max in order to produce clean intervals between axis labels.
If you need to explicitly limit the axis to a specific range, where your min and max values are the absolute limits you want displayed, then you use the vAxis.viewWindow.min/max options.
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 am trying to use the Google charts api to create line charts that have datetimes on the x axis and values on the other. Generally these will only be for a 48 hour period, so I really need to show the times of day on the x axis as well as the days.
Does anyone know how to achieve this please?
Alternatively can anyone suggest another Javascript chart api that would allow this please?
The AnnotatedTimeline charts are old and outdated; you can replicate 95% of the functionality using a LineChart with "annotation" and "annotationText" column roles and a ChartRangeFilter. The LineCharts support using datetimes.
I'm using morris.js on a temperature time series.
Would like to see other suggestions.
#asgallant is right. A sample of what it would look like can but seen in Google Code Playground and pasting this script:
function drawVisualization() {
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Count');
data.addColumn({type: 'string', role: 'annotation'});
data.addColumn({type: 'string', role: 'annotationText'});
data.addRows([
[new Date(2013, 0, 31, 19, 30), 1, 'A', 'Event 1'],
[new Date(2013, 1, 2, 20, 30), 2, 'B', 'No event'],
[new Date(2013, 1, 7, 18, 30), 2.5, 'C', 'No event'],
]);
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {curveType: "function",
width: 500, height: 400,
vAxis: {maxValue: 10}}
);
}