Multiple data points per date in Google Charts - javascript

I am using a standard php array that pulls data from a database in reverse order to create a Google Chart. Something like this...
$graph_data = array(array('Date', 'Amount'));
foreach (array_reverse($transactions) as $transaction)
{
array_push($graph_data, array(date("d M", strtotime(substr($transaction->createdOn, 0, 10))), $transaction->balanceAfter + 0));
}
Works fine.
This process creates a new data point on the chart for each row of the array. The problem I have is when there are multiple events ($transaction) on a date. Each event is plotted as a new chart point, whereas I would like to graph the last data point for each date. (constant time series)
What is the best way to go about this?
Is there a simple google chart setting to use the last data point per date? I have searched but found nothing on this.
Thanks

we can use the group() method,
with a custom aggregation function,
to only display the last point for a given date.
var dataLast = google.visualization.data.group(
data, // data table
[0], // group by column
[{ // aggregated column
column: 1,
type: 'number',
label: data.getColumnLabel(1),
// aggregation function
aggregation: function (values) {
// return the last value for the group
return values[values.length - 1];
}
}]
);
the aggregation property above,
should be a function that accepts a single argument,
that is an array of the values for each group.
in this case, we just return the last value in the array.
the group method returns a data table,
which we can use to draw the chart.
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Date', 'Amount'],
['09 Jan', 13],
['29 Jan', 11],
['29 Jan', 9],
['29 Jan', 4],
['29 Jan', -3],
['29 Jan', 0],
['29 Jan', -3],
['30 Jan', -5],
['30 Jan', 0],
['30 Jan', -1],
['30 Jan', -2],
['30 Jan', -3],
['30 Jan', -4],
['30 Jan', -5]
]);
var dataLast = google.visualization.data.group(
data, // data table
[0], // group by column
[{ // aggregated column
column: 1,
type: 'number',
label: data.getColumnLabel(1),
// aggregation function
aggregation: function (values) {
// return the last value for the group
return values[values.length - 1];
}
}]
);
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(dataLast); // use grouped data to draw the chart
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

How can I sort the result of a google charts join

I have 2 arrayToDataTable and I am doing a full join to represent the 2 in the graph, but when doing the join the result is alphabetically ordered.
I need to reorder or make the join not order the result, or find another way to join the two arrays.
Important the first element of the row will always be a string, but it will not always be the same.
function drawChart() {
var data = (
[
["X","Chart 1"],
['Sun', 6],
['Mon', 5],
['Tue', 8],
['Wed', 2],
['Thu', 5]
]);
var dt1 = google.visualization.arrayToDataTable(data);
var data2 = new google.visualization.DataTable();
data2.addColumn('string', 'X');
data2.addColumn('number', 'Chart 2');
data2.addRows([
['Sun', 6],
['Mon', 5],
['Tue', 8],
['Wed', 2],
['Thu', 5],
['Fri', 5],
['Sat', 5]
]);
var joinedData = google.visualization.data.join(dt1, data2, 'full', [[0, 0]], [1], [1]);
var chart = new google.visualization.LineChart(document.querySelector('#chart_div'));
chart.draw(joinedData, {
height: 300,
width: 600,
interpolateNulls: true
});
}
google.load('visualization', '1', {packages:['corechart'], callback: drawChart});
<script src="https://www.google.com/jsapi?fake=.js"></script>
<div id="chart_div"></div>
we cannot prevent the join method from sorting the results.
but we can use a DataView to provide a custom order,
by using the setRows method.
setRows takes an array of row indexes.
so we can order the row indexes in order of weekday.
here, we start by using an array with the order of days we want.
var sortOrder = [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat'
];
then loop the joined data table, find the index of the day in the sort order,
and place the row index in that position in our array.
var sortIndexes = [];
for (var i = 0; i < joinedData.getNumberOfRows(); i++) {
var day = joinedData.getValue(i, 0);
sortIndexes[sortOrder.indexOf(day)] = i;
}
finally, create the data view and set the rows.
var sortedData = new google.visualization.DataView(joinedData);
sortedData.setRows(sortIndexes);
and draw the chart with the data view.
var chart = new google.visualization.LineChart(document.querySelector('#chart_div'));
chart.draw(sortedData, {
height: 300,
width: 600,
interpolateNulls: true
});
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = ([
['X','Chart 1'],
['Sun', 7],
['Mon', 6],
['Tue', 9],
['Wed', 3],
['Thu', 6]
]);
var dt1 = google.visualization.arrayToDataTable(data);
var data2 = new google.visualization.DataTable();
data2.addColumn('string', 'X');
data2.addColumn('number', 'Chart 2');
data2.addRows([
['Sun', 6],
['Mon', 5],
['Tue', 8],
['Wed', 2],
['Thu', 5],
['Fri', 5],
['Sat', 5]
]);
var joinedData = google.visualization.data.join(dt1, data2, 'full', [[0, 0]], [1], [1]);
var sortOrder = [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat'
];
var sortIndexes = [];
for (var i = 0; i < joinedData.getNumberOfRows(); i++) {
var day = joinedData.getValue(i, 0);
sortIndexes[sortOrder.indexOf(day)] = i;
}
var sortedData = new google.visualization.DataView(joinedData);
sortedData.setRows(sortIndexes);
var chart = new google.visualization.LineChart(document.querySelector('#chart_div'));
chart.draw(sortedData, {
height: 300,
width: 600,
interpolateNulls: true
});
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
NOTE: recommend using loader.js, rather than jsapi to load google charts...
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.
the newer library can be found here...
<script src="https://www.gstatic.com/charts/loader.js"></script>
this will only change the load statement, see above snippet...

Draw straight line on google bar chart (combo)

I'm kinda bound to use google charts for one of my projects. What I need is, to display a bar chart, and in the bars a line intersecting each bar the represents another value. If you look at the jsfiddle below, you'll notice that the line chart only intersects the bars at the middle and continues to move forward towards other bars.
https://jsfiddle.net/ark7qbsc/
I would instead have, for example if you look at "Apples", for the line to intersect the entire bar (from start to finish) at y=2.5 and end within the bar, not to linger in the white spaces, nor make its way to the other bars.
Could anyone help me with this (Using only google charts.)
I've tired to inject null values after each data row, that at least removes the line from the white spaces. However, now there is just a dot on the centre of the bar. Looking a way to extend that to the entire bar width.
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawVisualization);
function drawVisualization() {
// Some raw data (not necessarily accurate)
var data = google.visualization.arrayToDataTable([
['Fruit', 'Jane', 'Average'],
['Apples', 3, 2.5],
['Oranges', 2, 1.5],
['Pears', 4, 3],
['Bananas', 3, 2],
['Plums', 4, 3]
]);
// Set chart options
var options = {
title : 'Fruits distribution',
vAxis: {title: 'Fruits'},
hAxis: {title: 'Person'},
seriesType: 'bars',
series: {1:{type: 'line'}}
};
// Instantiate and draw the chart.
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
Can't seem to get a line to be contained in the bar, from start to finish
not possible using standard methods / options,
but we can draw custom lines on the chart's ready event.
add nulls in between the rows to break the line.
['Fruit', 'Jane', 'Average'],
['Apples', 3, 2.5],
[null, null, null],
['Oranges', 2, 1.5],
[null, null, null],
we can use the following option to bring the bars closer together.
bar: {
groupWidth: '95%'
},
then we can use the circles to place the custom lines.
and we can use the chart's layout interface to find the width of the bars.
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Fruit', 'Jane', 'Average'],
['Apples', 3, 2.5],
[null, null, null],
['Oranges', 2, 1.5],
[null, null, null],
['Pears', 4, 3],
[null, null, null],
['Bananas', 3, 2],
[null, null, null],
['Plums', 4, 3]
]);
var options = {
bar: {
groupWidth: '95%'
},
title : 'Fruits distribution',
vAxis: {title: 'Fruits'},
hAxis: {title: 'Person'},
seriesType: 'bars',
series: {1:{type: 'line'}}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.ComboChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
// get chart layout and svg
var chartLayout = chart.getChartLayoutInterface();
var svg = document.querySelector('#chart_div svg');
var svgNS = svg.namespaceURI;
// process each circle
Array.prototype.forEach.call(container.getElementsByTagName('circle'), function(circle, index) {
// find width of the bar
var bounds = chartLayout.getBoundingBox('bar#0#' + (index * 2));
// create line
var line = document.createElementNS(svgNS, 'rect');
line.setAttribute('x', parseFloat(circle.getAttribute('cx')) - (bounds.width / 2));
line.setAttribute('y', parseFloat(circle.getAttribute('cy')));
line.setAttribute('width', bounds.width);
line.setAttribute('height', 1);
line.setAttribute('stroke', circle.getAttribute('fill'));
line.setAttribute('stroke-width', 2);
line.setAttribute('fill', circle.getAttribute('fill'));
circle.parentNode.appendChild(line);
});
});
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Google Charts throws "cannot read property '1' of undefined" when creating a view

I am working with google charts and would like to create a line chart where not all colums from the underlying data is visible. I found here - https://developers.google.com/chart/interactive/docs/reference#DataView that DataViewClass should be a good solution for it and tried to implement it as below. Unfortunately when I try to generate the chart I am getting "cannot read property '1' of undefined" error but no errors in the console.
Has anyone came across this? Any ideas for the solution?
best,
Adam
function testersBreakdown (testType, app){
// Data for the graph - need to be replaced by a correct query to backend
// TO DO: Format data and generate graphs
var data;
data = new google.visualization.DataTable();
data.addColumn('number', 'Test Cycle');
data.addColumn('number', 'Total');
data.addColumn('number', 'F2F');
data.addColumn('number', 'Scalable In the Office');
data.addColumn('number', 'Remote Testing');
data.addRows([
[1, 10, 3, 4, 3],
[2, 11, 4, 4, 3],
[3, 15, 3, 9, 3],
[4, 20, 3, 9, 8],
[5, 45, 30, 14, 1]
]);
var options = {
width: '100%',
height: 600,
hAxis: {
title: 'Test Cycle'
},
vAxis: {
title: 'Responses'
},
colors: ['#a52714', '#097138', 'black', 'blue'],
animation: {
duration: 300,
startup: true,
},
};
// Intermediate object to control views based on dropdown
// TO DO: Determine what to show based on the testType dropdown selected
var view = new google.visualization.DataView(data);
view.setColumns(['Test Cycle','Total' ]); //here you set the columns you want to display
//Visualization Go draw!
var chart = new google.visualization.LineChart(document.getElementById('testTypeChart'));
chart.draw(view, options);
};
This is due to a bug when using animations with a dataView (see this issue for more info regarding the bug). To solve this try loading the release candidate from google instead of the stablegoogle.load("visualization", "1", {packages:["corechart"]}); with google.load("visualization", "1.1", {packages:["corechart"]});.
Check here for more info about using release candidates.
I've got to little repuptation to post more than 2 links, so if you go to the google developers page (that you linked to) and then navigate to "Google Chart News" and scroll to the bottom-ish you can find more info about this.
I also tried it in a fiddle and it works like a charm.Hope it helped!Henrik

google charts api - column chart - percentage above vertical bar along with normal values on left side of vaxis

I am using google charts to generate a column chart as shown in this image:
http://postimg.org/image/mt7tzwwob/
Here, data will be like [['a', 1], ['b', 2], ['c', 3]]
Here, I am getting values 1,2,3 on left left side of vaxis which is ok for me.
What I want extra is: The percentages at the top of the vertical bar.
x+2x+3x = 100, means, x=16, 2x=33, 3x=50. So, 16% should be at top of vertical bar with value 1.
How can I get these percentages ?
The ColumnChart's don't support adding labels like a percentage above the columns, but there is a work-around that involves using a ComboChart and a hidden line to add them in. Here's some example code that adds in labels (you can replace the labels with percents in you want):
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', 'Value');
data.addColumn({type: 'string', role: 'annotation'});
data.addRows([
['Foo', 53, 'Foo text'],
['Bar', 71, 'Bar text'],
['Baz', 36, 'Baz text'],
['Cad', 42, 'Cad text'],
['Qud', 87, 'Qud text'],
['Pif', 64, 'Pif text']
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, 1, 2]);
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(view, {
height: 400,
width: 600,
series: {
0: {
type: 'bars'
},
1: {
type: 'line',
color: 'grey',
lineWidth: 0,
pointSize: 0,
visibleInLegend: false
}
},
vAxis: {
maxValue: 100
}
});
}
see it working here: http://jsfiddle.net/asgallant/QjQNX/
This only works well for charts that have a single series of data (as the labels will be misaligned if there is more than one series).

Dashboard using google charts with two tables

I'm trying to create a Dashboard with column chart and a few category filters in my app, I have data like this :
['First name', 'City', 'Number of children'],
['Michael' , 'London', 2],
['Elisa', 'Paris', 3],
['Robert', 'Moskov', 3],
['John','LA', 1],
['Jessica', 'Kyiv', 3],
['Aaron', 'New York', 2],
['Margareth','Tokyo', 3 ]
but I have to visualize not this data, but a table with total amount of people with same number of children:
['1 child', '2 children', '3 children'],
[1, 2 , 4]
So when I apply some filter to first table than data in second table must be re-calculated automatically. Can I somehow bind this tables and controls together ? Or I have to put some handlers for each filter and re-calculate data manually ?
I assume that given your data:
['First name', 'City', 'Number of children'],
['Michael' , 'London', 2],
['Elisa', 'Paris', 3],
['Robert', 'Moskov', 3],
['John','LA', 1],
['Jessica', 'Kyiv', 3],
['Aaron', 'New York', 2],
['Margareth','Tokyo', 3 ]
You want to group by your 2nd column (number of children) to get this result:
[1, 1],
[2, 2],
[3, 4]
You can do this easily using the group by aggregation feature for data tables.
Here is sample code:
function drawJoin() {
var dt = google.visualization.arrayToDataTable([
['First name', 'City', 'Number of children'],
['Michael' , 'London', 2],
['Elisa', 'Paris', 3],
['Robert', 'Moskov', 3],
['John','LA', 1],
['Jessica', 'Kyiv', 3],
['Aaron', 'New York', 2],
['Margareth','Tokyo', 3 ]
]);
// Group dt by column 2, and count number of entries for each.
var grouped_dt = google.visualization.data.group(
dt, [2],
[{'column': 0, 'aggregation': google.visualization.data.count, 'type': 'number'}]);
var table = new google.visualization.Table(document.getElementById('table'));
table.draw(dt, null);
var grouped_table = new google.visualization.Table(document.getElementById('grouped_table'));
grouped_table.draw(grouped_dt, null);
}
Feel free to try it out on Google Playground (just copy-paste the above code in).
You can graph that as is, or you can transpose it using a javascript function to transcribe rows/columns in your datatable.
So you should filter using your controls on the original data table, and then create a grouping function, and draw the grouped table in your chart.
If you want the labels to read '1 child' instead of just the number 1, then you need to create a function using SetFormattedValue() since the output of the group would be a number. You could mix this with the transpose function above since you're already doing work on the data table.
Assume I have the same data, group them and build column chart based on grouped data. Now I want to add some filters. I can easy add any filter for the column I use in grouping data, but when I add some filter for another column I got error "Invalid column label". For example if I add :
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnLabel': 'Performance',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': true
}
}
});
everything will be fine, but my aim is to add filters for columns 'City' and 'First name' and changing their values should effect on my column chart with grouped data. If this possible to do?

Categories

Resources