Stepped Area Google charts wrong visualization - javascript

I'm using Google charts Stepped Area in my project, I have 2 data columns (datetime,state).
The problem is when the change in time is dynamic and not fixed the chart gets abnormal like this example, however when the data points are in fixed time change, the chart is drawn correctly for example in this code the points are one every 100 milliseconds.
Example 1 data
['Date', 'State'],
[new Date(1534078983500), 3],
[new Date(1534078983880), 1],
[new Date(1534080441460), 3],
[new Date(1534080441840), 1],
[new Date(1534080533960), 3],
[new Date(1534080534330), 1]
Example 2 data
['Date', 'State'],
[new Date(1534078983100), 3],
[new Date(1534078983200), 1],
[new Date(1534078983300), 3],
[new Date(1534078983400), 1],
[new Date(1534078983500), 3],
[new Date(1534078983600), 1]

according to the Data Format for the SteppedAreaChart,
the Data Type for the x-axis should be --> 'string'
although it may work with dates, the results may be inconsistent
instead, use the DateFormat class to convert the date to a timestamp string
see following working snippet...
here, a DataView is used to create a calculated column for the timestamp...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Date', 'State'],
[new Date(1534078983500), 3],
[new Date(1534078983880), 1],
[new Date(1534080441460), 3],
[new Date(1534080441840), 1],
[new Date(1534080533960), 3],
[new Date(1534080534330), 1]
]);
var formatTime = new google.visualization.DateFormat({
pattern: 'HH:ss.SSSS a'
});
var view = new google.visualization.DataView(data);
view.setColumns([{
calc: function (dt, row) {
return formatTime.formatValue(dt.getValue(row, 0));
},
label: data.getColumnLabel(0),
type: 'string'
}, 1]);
var options = {
title: 'The decline of \'The 39 Steps\'',
vAxis: {
title: 'Accumulated Rating',
ticks: [{ v: 0, f: '' }, { v: 1, f: 'Close' }, { v: 2, f: 'CLG/OPG' }, { v: 3, f: 'Open' }, { v: 4, f: '' }]
}
};
var chart = new google.visualization.SteppedAreaChart(document.getElementById('chart_div'));
chart.draw(view, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
if you need to use the explorer option,
you can use a number instead of a string
use the formatted value to display the actual dates,
and build custom ticks for the x-axis using the same approach...
see following working snippet...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Date', 'State'],
[new Date(1534078983500), 3],
[new Date(1534078983880), 1],
[new Date(1534080441460), 3],
[new Date(1534080441840), 1],
[new Date(1534080533960), 3],
[new Date(1534080534330), 1]
]);
var formatTime = new google.visualization.DateFormat({
pattern: 'HH:ss.SSSS a'
});
var view = new google.visualization.DataView(data);
view.setColumns([{
calc: function (dt, row) {
return {
v: row,
f: formatTime.formatValue(dt.getValue(row, 0))
};
},
label: data.getColumnLabel(0),
type: 'number'
}, 1]);
var xTicks = [];
for (var i = 0; i < view.getNumberOfRows(); i++) {
addTick(i);
}
function addTick(i) {
xTicks.push({
v: view.getValue(i, 0),
f: view.getFormattedValue(i, 0)
});
}
var options = {
explorer: {},
hAxis: {
ticks: xTicks
},
title: 'The decline of \'The 39 Steps\'',
vAxis: {
title: 'Accumulated Rating',
ticks: [{ v: 0, f: '' }, { v: 1, f: 'Close' }, { v: 2, f: 'CLG/OPG' }, { v: 3, f: 'Open' }, { v: 4, f: '' }]
}
};
var chart = new google.visualization.SteppedAreaChart(document.getElementById('chart_div'));
chart.draw(view, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

assign $scope.chart.options based on conditional check - javascript

I am working on google chart API.I am working on timeline chart. I want to assign the colors of the bar inside the timeline chart based on the conditional check.
Below is the condition:
var firstWord = value.detail.trim().split(' ')[0];
if(firstWord === 'monthly'){ $scope.chart.options.colors[0]='yellow';}
if(firstWord === 'daily') { $scope.chart.options.colors[0]='green';}
How to assign the colors in the $scope.chart.options dynamically at runtime based on conditional check.
complete js code:
app.controller('MyController', ['$rootScope', '$scope',function ($scope, MyService) {
$scope.chart = {};
$scope.chart.type = "Timeline";
$scope.chart.cssStyle = "height:80%; width:100%;";
$scope.chart.options = {
timeline: {
barLabelStyle: { fontSize: 14 ,bold:true}
},
// colors:['#7EAE5A','#0E77B4'],
};
$scope.chart.data = {
"cols": [
{id: "status", label: "Status", type: "string"},
{id: "detail", label: "Detail", type: "string"},
{id:"tooltip", role:"tooltip", type:"string"},
{id: "startDate", label: "startDate", type: "date"},
{id: "endDate", label: "endDate", type: "date"}
]
};
//getting the response data
MyService.getResponseData().then(
function (response) {
$scope.myResponse = response;
$scope.chart.data.rows = {};
angular.forEach($scope.myResponse, function (value, key) {
var firstWord = value.detail.trim().split(' ')[0];
if(firstWord === 'monthly'){ $scope.chart.options.colors[0]='yellow';}
if(firstWord === 'daily') { $scope.chart.options.colors[0]='green';}
var cData = {
c: [{v: i}, {v: value.detail },
{v: "tooltip"},{v: value.startDate}, {v: value.endDate}]
};
weekRows.push(cData);i++;
});
$scope.chart.data.rows = weekRows;
}
},
you can use a DataView to dynamically change the color
using a calculated column with the 'style' role
see following working snippet...
google.charts.load('current', {
packages:['timeline']
}).then(function () {
var chart;
var dataTable;
var options;
dataTable = google.visualization.arrayToDataTable([
['100', 'daily_HourlyMay', new Date(2018, 5, 1), new Date(2018, 5, 1) ],
['101', 'yearly_hourlyMarch113', new Date(2018, 3, 27), new Date(2018, 3, 27) ],
['102', 'monthly_hourlyFeb', new Date(2018, 2, 23), new Date(2018, 2, 30) ],
['103', 'daily_HourlyApril', new Date(2018, 4, 11), new Date(2018, 4, 18) ],
['104', 'daily_HourlyMarch224', new Date(2018, 3, 16), new Date(2018, 3, 27) ],
['105', 'monthly_HourlySept', new Date(2018, 6, 5), new Date(2018, 6, 18) ],
['106', 'yearly_sometext shown here', new Date(2018, 1, 12), new Date(2018, 1, 30) ],
['107', 'monthly_HourlySept', new Date(2018, 8, 5), new Date(2018, 8, 18) ],
['108', 'yearly_sometext shown here', new Date(2018, 9, 12), new Date(2018, 9, 30) ],
['109', 'daily_text1 data', new Date(2018, 7, 5), new Date(2018, 7, 18)
]], true);
dataView = new google.visualization.DataView(dataTable);
dataView.setColumns([0, 1, {
calc: function (dt, row) {
var color;
var firstWord = dt.getValue(row, 1).trim().split('_')[0];
switch (firstWord) {
case 'monthly':
color = 'yellow';
break;
case 'daily':
color = 'green';
break;
case 'yearly':
color = 'blue';
break;
default:
color = 'black';
}
return color;
},
role: 'style',
type: 'string',
}, 2, 3]);
options = {timeline: {showRowLabels: false}};
chart = new google.visualization.Timeline(document.getElementById('chart_div'));
chart.draw(dataView, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
UPDATE
in angular, set the view in app.js...
chart1.view = {columns: [0, 1, {
calc: function (dt, row) {
var color;
var firstWord = dt.getValue(row, 1).trim().split('_')[0];
switch (firstWord) {
case 'monthly':
color = 'yellow';
break;
case 'daily':
color = 'green';
break;
case 'yearly':
color = 'blue';
break;
default:
color = 'black';
}
return color;
},
role: 'style',
type: 'string',
}, 2, 3]};

Using google.charts.load once time for multiple chart types

I want to make a plugin with google chart, like this:
(function (global) {
'use strict';
if (!global.google || !global.google.charts) {
let s = document.createElement('script');
s.src = `//www.gstatic.com/charts/loader.js`;
document.head.appendChild(s);
}
let google = {};
google.ready = function (_) {
let t = setInterval(function () {
if (global.google && global.google.charts) {
clearInterval(t);
_.call(global.google);
}
}, 1);
};
let chart = (function () {
let _selector = Symbol('GoogleChart');
class GoogleChart {
constructor(selector) {
this[_selector] = selector;
}
CoreChart(options = {}) {
let _this = this, selector = document.getElementById(_this[_selector]);
let init = function () {
let google = this;
let drawChart = function () {
let O = {
width: options.width || 500,
height: options.height || 500,
legend: options.legend || {},
pointSize: options.pointSize || 1,
vAxis: options.vAxis || {},
hAxis: options.hAxis || {},
series: options.series || {},
colors: options.colors || [],
lineWidth: options.lineWidth || 2
};
let data = new google.visualization.DataTable();
if (!options.data || !options.data.columns || !options.data.rows) throw `Missing 'data'. No data to display in the chart.`;
for (let column in options.data.columns) data.addColumn(column, options.data.columns[column]);
if (options.tooltip && options.tooltip.type) {
let tooltip = {
type: options.tooltip.type,
role: 'tooltip'
};
if (options.tooltip.isHtml) {
tooltip.p = {
html: true
};
O.tooltip = {
isHtml: true
};
}
data.addColumn(tooltip);
}
data.addRows(options.data.rows);
//
let chart = new google.visualization.LineChart(selector);
//
chart.draw(data, O);
};
google.charts.load('current', { packages: ['corechart'] });
google.charts.setOnLoadCallback(drawChart);
};
//
google.ready(init);
}
}
return GoogleChart;
}());
global.GoogleChart = chart;
}(window));
// USAGE:
let chart = new GoogleChart('line');
chart.CoreChart({
width: 500,
height: 200,
data: {
columns: {
'string': 'Date',
'number': 'Date'
},
rows: [
['1', 2],
['', 7],
['3', 3],
['', 9],
['5', 3],
['', 1],
['7', 4],
['', 6],
['9', 3],
['', 5],
['11', 8],
['', 2],
['13', 1],
['', 0],
['15', 8]
]
},
legend: {
position: 'top'
},
series: {
0: {
color: '#f00',
lineDashStyle: [2, 2, 20, 2, 20, 2]
}
},
pointSize: 3
});
<div id="line"></div>
It works fine with only 1 chart type (CoreChart). Now, I want to support more chart types (Geo chart, Map chart).
let chart1 = new GoogleChart(selector1);
chart1.GeoChart(options);
let chart2 = new GoogleChart(selector2);
chart2.MapChart(options);
I notice the Limitations:
You can only call google.charts.load once. But you can list all the packages that you'll need in one call, so there's no need to make separate calls.
So, my plugin doesn't know exactly the chart type until it's called (.GeoChart or .MapChart). If there are multiple charts on a page, how to draw it?
If I do this:
google.charts.load('current', { packages: ['corechart', 'geochart', 'map'] });
and there is no GeoChart or MapChart called, that would be wasting (spending time to load the unused charts).
Any idea? Thank you!

Google visualization set column dock

I am struggling with google charts. I want bars to be displayed from bottom, rather than from top. Currently they are "hanging" like on the image below:
I don't see proper setting in docs, if it is there, please correct me. This is the code responsible for handling the display:
function parseInterval(value) {
var result = new Date(1,1,1);
result.setMilliseconds(value*1000);
return result;
}
(function($) {
$(document).ready(function(){
var loading = $('#loading');
$.getJSON("/api/v1/users", function(result) {
var dropdown = $("#user_id");
$.each(result, function(item) {
dropdown.append($("<option />").val(this.user_id).text(this.name));
});
dropdown.show();
loading.hide();
});
$('#user_id').change(function(){
var selected_user = $("#user_id").val();
var chart_div = $('#chart_div');
if(selected_user) {
loading.show();
chart_div.hide();
$.getJSON("/api/v1/mean_time_month/"+selected_user, function(result) {
$.each(result, function(index, value) {
value[1] = parseInterval(value[1]);
});
var data = new google.visualization.DataTable();
data.addColumn('string', 'Month');
data.addColumn('datetime', 'Mean time (h:m:s)');
data.addRows(result);
var options = {
hAxis: {
title: 'Month'
},
vAxis: {
title: 'Mean presence time',
minValue: new Date(1, 1, 1, 0, 0)
},
};
var formatter = new google.visualization.DateFormat({pattern: 'HH:mm:ss'});
formatter.format(data, 1);
chart_div.show();
loading.hide();
var chart = new google.visualization.ColumnChart(chart_div[0]);
chart.draw(data, options);
});
}
});
});
})(jQuery);
try using option vAxis.direction...
The direction in which the values along the vertical axis grow. Specify -1 to reverse the order of the values.
vAxis: {
direction: -1
}
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Month');
data.addColumn('datetime', 'Mean time (h:m:s)');
data.addRows([
['Jan', new Date(1, 1, 1, 8, 16, 13)],
['Feb', new Date(1, 1, 1, 9, 24, 45)],
['Mar', new Date(1, 1, 1, 7, 36, 56)],
['Apr', new Date(1, 1, 1, 4, 20, 42)],
['May', new Date(1, 1, 1, 6, 51, 16)]
]);
var options = {
hAxis: {
title: 'Month'
},
vAxis: {
direction: -1,
title: 'Mean presence time',
minValue: new Date(1, 1, 1, 0, 0)
}
};
var formatter = new google.visualization.DateFormat({pattern: 'HH:mm:ss'});
formatter.format(data, 1);
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
but i think the real problem lies within the data
notice the y-axis values the chart displays in the example above,
the order doesn't seem right, as well as the range (10am - 12am)
it appears you're only interested in the time values
as such, recommend using 'timeofday' vs. 'datetime'
(see --> working with timeofday)
The DataTable 'timeofday' column data type takes an array of either 3 or 4 numbers, representing hours, minutes, seconds, and optionally milliseconds, respectively. Using timeofday is different than using date and datetime in that the values are not specific to a date, whereas date and datetime always specify a date.
For example, the time 8:30am would be: [8, 30, 0, 0], with the 4th value being optional ([8, 30, 0] would output the same 'timeofday' value).
see following working snippet for example using 'timeofday'...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Month');
data.addColumn('timeofday', 'Mean time (h:m:s)');
data.addRows([
['Jan', [8, 16, 13]],
['Feb', [9, 24, 45]],
['Mar', [7, 36, 56]],
['Apr', [4, 20, 42]],
['May', [6, 51, 16]]
]);
var options = {
hAxis: {
title: 'Month'
},
vAxis: {
title: 'Mean presence time',
minValue: [0, 0, 0]
}
};
var formatter = new google.visualization.DateFormat({pattern: 'HH:mm:ss'});
formatter.format(data, 1);
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Google Charts - Shared label for adjacent columns with the same value

I have a Google Chart that's showing repeated values for adjacent rows containing the same value. Is there a way to make adjacent columns share a label if the value they represent is the same?
there are no standard options to prevent annotations from repeating,
but these could be easily removed
1)
if the annotation values are loaded as part of the data,
and you don't want to change how the data is loaded
use a simple routine to set the annotations to null
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Month', 'Members', {role: 'annotation'}],
['2015-09', 0, '0'],
['2015-10', 0, '0'],
['2015-11', 0, '0'],
['2015-12', 0, '0'],
['2016-01', 1, '1'],
['2016-02', 1, '1'],
['2016-03', 1, '1'],
['2015-04', 3, '3'],
['2016-05', 3, '3'],
['2016-06', 3, '3'],
['2016-07', 3, '3'],
['2016-08', 3, '3'],
['2016-09', 3, '3'],
['2016-10', 4, '4'],
['2016-11', 6, '6'],
['2016-12', 6, '6'],
['2017-01', 8, '8'],
['2017-02', 8, '8'],
['2017-03', 8, '8'],
]);
// remove repeated annotations
var annotationText = null;
for (var i = 0; i < data.getNumberOfRows(); i++) {
if (annotationText === data.getValue(i, 2)) {
data.setValue(i, 2, null);
} else {
annotationText = data.getValue(i, 2);
}
}
var options = {
annotations: {
alwaysOutside: true,
textStyle: {
bold: true,
fontSize: 20
}
},
colors: ['#0097A7'],
hAxis: {
slantedText: true,
textStyle: {
bold: true,
fontSize: 16
}
},
height: 400,
legend: {
position: 'none'
},
vAxis: {
title: data.getColumnLabel(1)
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(container);
chart.draw(data, options);
};
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
2)
if the annotation values are set using a DataView,
modify the calc function to not repeat annotations
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Month', 'Members'],
['2015-09', 0],
['2015-10', 0],
['2015-11', 0],
['2015-12', 0],
['2016-01', 1],
['2016-02', 1],
['2016-03', 1],
['2015-04', 3],
['2016-05', 3],
['2016-06', 3],
['2016-07', 3],
['2016-08', 3],
['2016-09', 3],
['2016-10', 4],
['2016-11', 6],
['2016-12', 6],
['2017-01', 8],
['2017-02', 8],
['2017-03', 8],
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: function (dt, row) {
if (row > 0) {
if (dt.getValue(row, 1) === dt.getValue(row - 1, 1)) {
return null;
}
}
return dt.getFormattedValue(row, 1);
},
role: 'annotation',
type: 'string'
}]);
var options = {
annotations: {
alwaysOutside: true,
textStyle: {
bold: true,
fontSize: 20
}
},
colors: ['#0097A7'],
hAxis: {
slantedText: true,
textStyle: {
bold: true,
fontSize: 16
}
},
height: 400,
legend: {
position: 'none'
},
vAxis: {
title: data.getColumnLabel(1)
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(container);
chart.draw(view, options);
};
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Dual y axes in Google charts

I am trying to use dual y axes with Google charts.I understand the basics and how it works.
On one y axis, I want BMI values and on other Weight Values.
I am taking out data from SQL database. However, BMI and Weight are itself values in a column called ReadingName.
So, if I use the query,
select * from table where ReadingName = 'BMI' or ReadingName = Weight
I get the result set which is serialized into JSON and then forwarded to render charts which again would be retrieved using column Name only.
Now, to have observation values for BMI on one yaxis and Weight on other, as per the example on GoogleCharts website, I need to have them as columns.
But I have them only as different values of same column called ReadingType.Is there a work around possible ?
This is how it should look like :
Unfortunately, you'll have to massage the data into a format it understands. The DataTable class provides lots of methods for populating but here is an example:
google.load("visualization", "1", {
packages: ["corechart"]
});
google.setOnLoadCallback(drawChart);
function drawChart() {
// Start with long data
var rawData = [
[new Date(2014, 8, 1), "Weight", 140],
[new Date(2014, 8, 1), "BMI", 5],
[new Date(2014, 8, 15), "Weight", 130],
[new Date(2014, 8, 15), "BMI", 4],
[new Date(2014, 9, 1), "Weight", 120],
[new Date(2014, 9, 1), "BMI", 3],
[new Date(2014, 9, 15), "Weight", 120],
[new Date(2014, 9, 15), "BMI", 3]
];
// Create a wide table from the long data
var data = new google.visualization.DataTable();
data.addColumn("date", "Date");
data.addColumn("number", "BMI");
data.addColumn("number", "Weight");
var lastDate = null;
var currentRow = null;
for (var i=0; i < rawData.length; i++) {
var date=rawData[i][0];
var col=rawData[i][1];
var value=rawData[i][2];
if (lastDate == null) {
// First pass
currentRow = [date, null, null];
}
else if (lastDate != date) {
data.addRow(currentRow);
currentRow = [date, null, null];
}
if (col=="BMI") currentRow[1] = value;
else if (col=="Weight") currentRow[2] = value;
lastDate = date;
}
if (currentRow != null) data.addRow(currentRow);
var options = {
title: 'Wight & BMI',
vAxes: [{
title: "Weight",
minValue: 0
}, {
title: "BMI",
minValue: 0
}],
series: {
0: { targetAxisIndex:0 },
1: { targetAxisIndex:1 }
},
interpolateNulls: true
}
var chart = new google.visualization.LineChart(document.getElementById("chart"));
chart.draw(data, options);
}
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id="chart" style="width: 900px; height: 300px;"></div>

Categories