google visualization multiple charts with own data queries - javascript

On my Google Visualization web page I want both a bar chart and an area chart but I can get only one or the other to display.
Each chart requires its own data and employs its own google.visualization.Query object against my own Python-based server. My initialize function calls the function to display the first chart, and at the bottom of the query response handler for the first chart, I'm calling the function to display the second chart. (I am doing this to make sure my second data query does not start until after the first chart is done drawing.) Each chart displays correctly when I code to draw only one chart at a time. But when I try to draw both charts, only the first chart ever draws even though I am verifying that both data queries are running and returning valid json responses, at the correct times.
Thanks for any help, BH
Edit 10/27/2013:
This post solved my problem:
Google Charts - "Missing Query for request id: 0"
To anyone implementing a Python data source, parse the reqId parameter like this:
import cgi
form = cgi.FieldStorage()
tqx = form.getvalue("tqx") # tqx comes back like "reqId:1"
req_id = int(tqx[tqx.find("reqId"): ].split(":")[1])
And pass it to the ToJSonResponse call:
response = data_table.ToJSonResponse(req_id=req_id,
columns_order=("vehicle_id", "num_events"))
print "Content-type: text/plain"
print
print response
Here is my updated code, which also uses the "ready" event.
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(initialize);
var timelineDate1 = "";
var messageCountsDate1 = "";
var timeline_drawn = false;
var message_count_drawn = false;
function initialize()
{
drawTimeline();
}
function drawTimeline()
{
var rows = QueryString.rows || "4";
var date1 = QueryString.date1 || "2013-9-1"; // Date start
timelineDate1 = date1;
var page = parseInt(QueryString.page) || 1;
if (page < 1)
{
page = 1;
}
// Timeline
var url_timeline = "http://localhost/emit_event_timeline.py"
+ "?date1=" + date1 + "&rows=" + rows + "&page=" + page;
var query_timeline = new google.visualization.Query(url_timeline);
query_timeline.setTimeout(14400);
query_timeline.send(handleTimelineQueryResponse);
}
function handleTimelineQueryResponse(response)
{
var stack = parseInt(QueryString.stack) || 1
var timeline_options =
{
title: 'Event Count Timeline, ' + timelineDate1 + ' to Present',
vAxis: {title: 'Date', titleTextStyle: {color: 'red'}},
hAxis: {title: 'Event Count', titleTextStyle: {color: 'blue'}},
isStacked: stack
};
if (response.isError())
{
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var timeline_data_table = response.getDataTable();
var timeline_chart = new google.visualization.AreaChart(document.getElementById('timeline_div'));
google.visualization.events.addListener(timeline_chart, 'ready', timeline_chart_ready);
google.visualization.events.addListener(timeline_chart, 'error', errorHandler);
timeline_chart.draw(timeline_data_table, timeline_options);
}
function timeline_chart_ready()
{
timeline_drawn = true;
if (!message_count_drawn)
{
drawMessagecounts();
}
}
function mc_chart_ready()
{
message_count_drawn = true;
if (!timeline_drawn)
{
drawTimeline();
}
}
function drawMessagecounts()
{
var rows = QueryString.rows || "20";
var date1 = QueryString.date1 || "2013-9-1"; // Date start
messageCountsDate1 = date1
var page = parseInt(QueryString.page) || 1;
if (page < 1)
{
page = 1;
}
// Message counts
var url_message_counts = "http://localhost/emit_all_message_counts.py"
+ "?date1=" + date1 + "&page=" + page + "&rows=" + rows;
var query_message_counts = new google.visualization.Query(url_message_counts)
query_message_counts.setTimeout(14400);
query_message_counts.send(handleMessageCountQueryResponse);
}
function handleMessageCountQueryResponse(response)
{
var stack = parseInt(QueryString.stack) || 1
var mc_options =
{
title: 'Message Counts, ' + messageCountsDate1 + ' to Present',
vAxis: {title: 'Message Source', titleTextStyle: {color: 'red'}},
hAxis: {title: 'Message Count', titleTextStyle: {color: 'blue'}},
isStacked: stack
};
if (response.isError())
{
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var mc_data_table = response.getDataTable();
var mc_chart = new google.visualization.BarChart(document.getElementById('message_count_div'));
google.visualization.events.addListener(mc_chart, 'ready', mc_chart_ready);
google.visualization.events.addListener(mc_chart, 'error', errorHandler);
mc_chart.draw(mc_data_table, mc_options);
}
// Thanks to:
// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values
var QueryString = function ()
{
// This function is anonymous, is executed immediately and
// the return value is assigned to QueryString!
var query_string = {};
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
// If first entry with this name
if (typeof query_string[pair[0]] === "undefined") {
query_string[pair[0]] = pair[1];
// If second entry with this name
} else if (typeof query_string[pair[0]] === "string") {
var arr = [ query_string[pair[0]], pair[1] ];
query_string[pair[0]] = arr;
// If third or later entry with this name
} else {
query_string[pair[0]].push(pair[1]);
}
}
return query_string;
} ();
function errorHandler(e)
{
// Called when an error occurs during chart processing
alert('Error handler: ' + e.message);
}
</script>
</head>
<body>
<div id="timeline_div" style="width:800px;height:500px;border:1px solid gray;float:left">
</div>
<div id="message_count_div" style="width:800px;height:500px;border:1px solid gray;float:left">
</div>
<div id="control_div" style="width:80px;height:60px;float:left">
</div>
</body>
</html>

The solution was for my Python data source to pass the reqId parameter from the request back on the json reqponse. This post solved my problem:
Google Charts - "Missing Query for request id: 0"

Related

Fix on_click function to change text

When I click on a button, a function is run. This function generates a string, and I am trying to display this string to the user in the div tag.
I tried to debug this in a few ways. For example, I check that the onclick is working. So, when I click the button, I do see "Clicked!" and then "In Function". This is expected. However, after that, it is supposed to display the string generated by the listAllEvents function. However, it does not seem to be working properly. (It logs the result as expected; it just doesn't display on the screen.)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
function myFunction() {
document.getElementById("data").innerHTML = "Clicked!";
listAllEvents()
}
function listAllEvents() {
document.getElementById("data").innerHTML = "In Function!";
var calendarId = 'primary';
var now = new Date();
var display = ""
var events = Calendar.Events.list(calendarId, {
timeMin: now.toISOString(),
maxResults: 2500,
});
if (events.items && events.items.length > 0) {
for (var i = 0; i < events.items.length; i++) {
var event = events.items[i];
if (event.start.date) {
// All-day event.
var start = new Date(event.start.date);
var end = new Date(event.end.date);
display = display + 'Start: ' + start.toLocaleDateString() + '; End: ' + end.toLocaleDateString() + ". ";
} else {
var start = new Date(event.start.dateTime);
var end = new Date(event.end.dateTime);
display = display + 'Start: ' + start.toLocaleString() + '; End: ' + end.toLocaleString() + ". ";
}
}
} else {
display = 'No events found.';
}
Logger.log('%s ', display);
document.getElementById("data").innerHTML = "Almost There";
document.getElementById("data").innerHTML = display;
}
</script>
<div id="data"> Hello! </div>
<button onclick="myFunction()">Run Function</button>
Expected, on click: Start....End.
Actual: "In Function!"
Can't use server side code on the client
The problem is that your trying to run server side code on the client.
function listAllEvents() {
document.getElementById("data").innerHTML = "In Function!";
var calendarId = 'primary';
var now = new Date();
var display = ""
var events = Calendar.Events.list(calendarId, {//This is server side Google Script
timeMin: now.toISOString(),
maxResults: 2500,
});
if (events.items && events.items.length > 0) {
for (var i = 0; i < events.items.length; i++) {
var event = events.items[i];
if (event.start.date) {
// All-day event.
var start = new Date(event.start.date);
var end = new Date(event.end.date);
display = display + 'Start: ' + start.toLocaleDateString() + '; End: ' + end.toLocaleDateString() + ". ";
} else {
var start = new Date(event.start.dateTime);
var end = new Date(event.end.dateTime);
display = display + 'Start: ' + start.toLocaleString() + '; End: ' + end.toLocaleString() + ". ";
}
}
} else {
display = 'No events found.';
}
Logger.log('%s ', display);
document.getElementById("data").innerHTML = "Almost There";
document.getElementById("data").innerHTML = display;
}
When you want to run server side google script you can call them with google.script.run
Here's a simple example of how to use google.script.run
This is the basic frame work:
Your html file:
The button click calls the Javascript function getCalendarEvents which prepares the appropriate (probably not required in this case) data to pass to the server and then it calls listCalendarEvents which is on the server. The server function gets the events and returns them to the withSuccessHandler and that handler then puts the information into the html page.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
function getCalendarEvents() {
google.script.run
.withSuccessHandler(function(eObj){
//load html with data from eObj
})
.listCalendarEvents();
}
function listAllEvents() {
}
</script>
<div id="data"> Hello! </div>
<button onclick="getCalendarEvents();">Run Function</button>
code.js:
function listCalendarEvents() {
//get all of the events
return eObj;
}
It crashes because Calendar is undefined. Your browser's console will tell you.

Expose additional data based on xAxis element click - Highcharts.js

I'm facing some difficulties while trying to implement 'xAxis clickable' column chart. I'm trying to expose additional Pie charts below my column chart, based on user click on one of the element in xAxis.
The way the first graph is build:
function chartBuilder(data) {
if (data.length === 0) {
return null;
}
var categories = [];
var uniqData = [
{name : 'Fatal', data:[], color:'black', stack: 'fatal'},
{name : 'Critical', data:[], color:'red', stack: 'critical'},
];
_.each(data, function (item) {
categories = categories.concat(item.site);
var fatalValue = {};
fatalValue[item.site] = parseFloat(item.fatal || 0);
uniqData[0].data = uniqData[0].data.concat(fatalValue);
var criticalValue = {};
criticalValue[item.site] = parseFloat(item.critical || 0);
uniqData[1].data = uniqData[1].data.concat(criticalValue);
});
var chartConfig = util.basicConfigChart(categories, uniqData);
chartConfig.yAxis.title = {
text: 'Num Of Events'
};
chartConfig.xAxis.labels = {
formatter: function() {
var ret = this.value,
len = ret.length;
if (len > 10) {
ret = '<strong>' + ret.slice(0,ret.indexOf('_')) + '<br/>' + ret.slice(ret.indexOf('_') + 1, len) + '</strong>';
}
if (len > 25) {
ret = ret.slice(0,25) + '...';
}
return '<strong>' + ret + '</strong>';
},
useHTML: true
};
chartConfig.options.tooltip = {
formatter : function () {
return '<strong>' + this.series.name + '</strong>:' + this.point.y + '<br>Total: ' + this.point.total;
}
};
return chartConfig;
}
So basically, what I need is a way to determine which element in xAxis was clicked, and expose below pie charts with data relevant to this element.
If I understand you correctly, you want to add a click event on the xAxis columns. This can be done using a click event
events: {
click: function (event) {
alert(
'x index: ' + event.point.x + ', \n' +
'series.index: ' + event.point.series.index
);
}
}
This event can be added to a specific series, or to the plotOptions to affect all series.
The code above, will make an alert that shows the relevant indexes.
Working example: https://jsfiddle.net/ewolden/xr17pen6/6/
API on click event: https://api.highcharts.com/highcharts/series.column.events.click

Need new eyes on this script getting a 417 error cod

I get this error in the Google Sheets application trying to text reminders every day I used this format 4175555555, (417) 5555555, and (417) 5555555 you are not sure what the problems are.
The error is:
Request failed for api.fluentcloud.com/v1/sms/send/GeneralRentalCenter returned code 417. Truncated server response: {"error":{"code":417,"message":"Expectation Failed: To number: is not formatted properly"}} (use muteHttpExceptions option to examine full response) (line 25, file "REMINDER")
//This sends out sms to phone number in row
function sendSms(to, name, time) {
var messages_url = 'https://api.fluentcloud.com/v1/sms/send/GeneralRentalCenter';
var body = {
'direction': '',
'to': to,
'from': '(417) 886-7368',
'timestamp': '',
'message': 'Hello' + ' ' + name + ', This is a reminder of your reservation at General Rental at ' + time + ' tomorrow. If you have any questions call 417-886-7368 ',
'messageId': '',
'particContactName': ''
};
var options = {
"method": "post",
"payload": body
};
options.headers = {
"Authorization": "4LsEvTFn-jD4i-XOmg-iGEXji7x2ZTb"
};
//sends out SMS to number for the row
UrlFetchApp.fetch(messages_url, options);
};
function sendAll() {
var date = new Date();
var today = ((date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear());
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var activeSheet;
for (i in sheets) {
if ((((new Date(today)) - (new Date(sheets[i].getName()))) / 86400000) === -1) {
activeSheet = sheets[i].getName();
SpreadsheetApp.setActiveSheet(sheets[i]);
}
}
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = sheet.getLastRow() - 1;
var dataRange = sheet.getRange(startRow, 8, numRows, 4);
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
if (!row[1]) {
continue;
};
var num = row[1].toString().split(".")[0];
if (row[3] === 'y') {
`enter code here`
try {
response_data = sendSms(num, row[0], row[2]);
} catch (err) {
Logger.log(err);
}
}
}
};
function myFunction() {
sendAll();
}
When script works it should pull there name,number and items and send out a reminder to them

Uncaught TypeError: Cannot read property 'setRowData' of undefined

I am using with Angular 1.x with ag-grid. first of all I am confused how I do activate enterprise feature. I am evaluating now we are planing to buy the enterprise but support is pretty weak.
Now the actual problem I am trying to feed the data from ElasticSearch to the grid. I am trying to simulate like demo of ag-grid. If change the pagesize it will retrieve the data from ES server and feed the grid with new datasets with new pagesize. For that I am using $scope.gridOptions.api.setRowData(data) on any action if I try to update the grid I mean setRowData. I am getting error "method is undefined" It works for the first time when it loads the page.
How do I resolve this issue? Am I missing anything?
Function: This is the function where I invoking the $scope.gridOptions.api.setRowData(data) and I am getting error
"Uncaught TypeError: Cannot read property 'setRowData' of undefined"
function displayGrid(fromDate, toDate, fieldNameArray, affiliate, product,consmb, region, customer, page, pageSize)
{
// Constructing Query from dashboard input
var gridQuery = globalFiltersDrillDown(fromDate, toDate, fieldNameArray, page, pageSize);
var finalGridQuery = buildQueryForDrillQuery(affiliate,product, consmb, region, customer, gridQuery, "" , false);
console.log("final Query :" + JSON.stringify(finalGridQuery));
var data =[];
setTimeout(function ()
{
esClientIndirect.search
(
{
index: esIndex1,
type: esType1,
size : pageSize,
from : page,
body: finalGridQuery
},
function (error, response, status)
{
$scope.numberOfRecords = numberCommas(response.hits.total);
if(error)
{
$scope.error = "Error : " + status ;
}
else
{
var startBrace = "{ ";
var endBrace = " }"
data.length = 0;
var k = 0;
for(var o in response.hits.hits)
{
var dataFields = response.hits.hits[o].fields;
var numberOfElements = fieldNameArray.length -1;
var row = startBrace;
for (var i in dataFields)
{
var columnName = fieldNameArray[k];
var columnValue = dataFields[columnName];
if (k == numberOfElements)
{
row += (" \"" + columnName +"\" : \"" + columnValue +"\"");
}
else
{
row += (" \"" + columnName +"\" : \"" + columnValue +"\",");
}
k = k+1;
}
row += endBrace;
k =0;
data.push(JSON.parse(row));
}
// pushing data into the ag-grid
setTimeout(function()
{
$scope.gridOptions.api.setRowData(data);
}, 200);
}
}, 100); // end of elastic search call back
}); // end of elastic search set time out call back
The error indicates that the api doesn't exist. Have you made sure that you have instantiated $scope.gridOptions before you do this call?

JavaScript Variable and passing data issues

I have an issue in that the $.getJSON segment of code works fine and produces a variable called 'zippy'. I need to access 'zippy' under 'series: data' further down in the code.
I have tried a number of things unfortunately I can't make it work. The easiest would be way to 'return data' $.getJSON(jsonUrl,function(zippy) out of the function(zippy) call but I'm lost as to how to make that data available.
$(function() {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var jsonUrl = "http://www.someurl.com/thing.php?callback=?";
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
console.log("++NEED ACCESS HERE FOR ZIPPY++");
console.log(" =============== \r\n");
console.log(" FINAL " + zippy.cpmdata[5].timestamp + " \r\n");
return data;
})()
}]
}
Your problem is that getJSON is asynchronous. What's happening in your code is this:
document.ready is triggered
getJSON is called and registers a callback "function(zippy)"
note that getJSON returns immediately without executing the callback
You try to draw a chart using HighCharts
... several hundred milliseconds later
The browser makes the JSON request
... several hundred milliseconds later
The JSON request returns with data and triggers the
callback to "function(zippy)"
"function(zippy)" is executed
So you see. The problem is not how "function(zippy)" is executed but when it is executed. As such, you cannot execute code that wants to use the return value of the JSON request outside of the callback function. (Actually you can but we'll ignore polling with setTimeout or using synchronous ajax for now)
The solution is to move all the code that you want to run later on inside the callback function:
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
}
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline',
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
console.log(" FINAL " + zippy.cpmdata[5].timestamp + " \r\n");
return data;
})()
}]
});
You need to put all of the new Highcharts.Chart({...}) stuff inside the getJSON callback, because you need to wait until the json request completes before creating the chart. See my code comment that says CUT AND PASTE chart = new Highcharts.Chart({...}) STUFF HERE!!!.
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
var jsonUrl = "http://www.someurl.com/thing.php?callback=?";
$.getJSON(jsonUrl, function(zippy) {
for(i = 0; i < zippy.cpmdata.length; i++) {
console.log("TIMESTAMP: " + zippy.cpmdata[i].timestamp + " AFTER: ");
zippy.cpmdata[i].timestamp = Date.parse(zippy.cpmdata[i].timestamp).getTime() / 1000;
//var unixtime Date.parse(temptime).getTime()/1000
console.log(" TESST " + zippy.cpmdata[i].timestamp + " \r\n");
// CUT AND PASTE chart = new Highcharts.Chart({...}) STUFF HERE!!!
}
});
console.log("+++++++++++++++++++++++++++++++++++++");
});

Categories

Resources