I'm trying to make a bar chart using Google Charts with dependent controls. The problem I am having concerns inputting the data in a format that is usable for my task.
Here is an example of the data I want to use:
'Option1heading', 'Option2heading', 'Option3heading', 'val1', 'val2', 'val3', 'val4', 'val5', 'val6'
'Row1val1', 'Row1val2', 'Row1val3', 1336060, 1538156, 1576579, 1600652, 1968113, 123345
'Row2val1', 'Row2val2', 'Row2val3', 400361, 366849, 440514, 434552, 393032, 234374
'Row3val1', 'Row3val2', 'Row3val3', 1001582, 1119450, 993360, 1004163, 979198, 578236
'Row4val1', 'Row4val2', 'Row4val3', 997974, 941795, 930593, 897127, 108087, 4893
The first row in this example contains the options that I want to filter on 'Option1heading', 'Option2heading' and 'Option3heading'. In reality these might be something like 'country', 'region', 'state'. The second row onwards then contains the data, 'Row1val1', 'Row1val2', 'Row1val3' being the filter information (e.g. 'France', 'North', 'Paris').
Following that, the 6 numeric values would be individual bars of data for that row. In the legend for this example these would equal 'val1' - 'val6' (as per the first row). In reality these might be things like 'population', 'Male', 'female', '0-10 years' etc.
Here is the code as it currently stands. It 'kind of' works but is not working correctly. Is this even possible and can anyone point me in the right direction in order to do it?
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="jquery.dump.js"></script>
<script type="text/javascript">
// Load the Visualization API and the controls package.
google.load('visualization', '1.1', {'packages':['corechart', 'controls']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawDashboard);
// Callback that creates and populates a data table,
// instantiates a dashboard, a range slider and a pie chart,
// passes in the data and draws it.
function drawDashboard() {
var data = new google.visualization.DataTable();
var raw_data = [['Option1', 'Option2', 'option3', 'val 1', 'val 2', 'val 3', 'val 4', 'val 5', 'val 6'],
['Ford', 's', 'm', 1336060, 1538156, 1576579, 1600652, 1968113, 123345],
['Citroen', 's', 'm', 400361, 366849, 440514, 434552, 393032, 234374],
['BMW', 's', 'm', 1001582, 1119450, 993360, 1004163, 979198, 578236],
['Toyota', 's', 'm', 997974, 941795, 930593, 897127, 108087, 4893]];
var my_rows = ['Row1', 'Row2', 'Row3', 'Row4', 'Row5', 'Row6'];
data.addColumn('string', 'Year');
for (var i = 0; i < raw_data.length; ++i) {
data.addColumn('number', raw_data[i][0]);
}
data.addRows(my_rows.length);
for (var j = 0; j < my_rows.length; ++j) {
data.setValue(j, 0, my_rows[j].toString());
}
for (var i = 1; i < raw_data.length; ++i) {
for (var j = 3; j < raw_data[i].length; ++j) {
data.setValue(j-3, i+1, raw_data[i][j]);
}
}
// Create a dashboard.
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div'));
var controlPicker1 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'Ford',
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true
}
}
});
var controlPicker2 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnLabel': 'Citroen',
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true
}
}
});
var controlPicker3 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control3',
'options': {
'filterColumnLabel': 'BMW',
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true
}
}
});
var barChart = new google.visualization.ChartWrapper({
'chartType': 'BarChart',
'containerId': 'chart_div',
'options': {
'width': '100%',
'height': '100%',
'vAxis': {title: "Year"},
'hAxis': {title: "Cups"},
'fontSize': 14,
'chartArea': {top: 0, right: 0, bottom: 0, height:'100%', width:'70%'}
},
// Configure the barchart to use columns 2 (City) and 3 (Population)
});
google.visualization.events.addListener(dashboard, 'ready', function() {
// Dashboard redraw, have a look at how many rows the barChart is displaying
var numRows = barChart.getDataTable().getNumberOfRows();
var expectedHeight = (numRows * 60)+50;
if (parseInt(barChart.getOption('height'), 10) != expectedHeight) {
// Update the chart options and redraw just it
Div("chart_div", expectedHeight);
barChart.setOption('height', expectedHeight);
barChart.draw();
}
});
// Establish dependencies, declaring that 'filter' drives 'pieChart',
// so that the pie chart will only display entries that are let through
// given the chosen slider range.
dashboard.bind(controlPicker1, controlPicker2);
dashboard.bind(controlPicker2, controlPicker3);
dashboard.bind(controlPicker3, barChart);
// Draw the dashboard.
dashboard.draw(data);
}
function Div(id,h) {
var div=document.getElementById(id);
h = (h) + "px";
var w=parseInt(div.style.width);
if($(this).width() >= 1200){
w = 1200 + "px";
}else{
w = ($(this).width()-30) + "px";
}
$(div).height(h);
$(div).width(w);
}
</script>
</head>
<style>
#chart_div { width: 1200px; height: 30000px; }
</style>
<body>
<!--Div that will hold the dashboard-->
<div id="dashboard_div">
<!--Divs that will hold each control and visualization-->
<div id="control1"></div>
<div id="control2"></div>
<div id="control3"></div>
<div id="chart_div"></div>
</div>
</body>
</html>
Many thanks in advance for any help you can provide.
The JSON data structure should be something like this:
{
"cols": [ {"id":"Col1", "label":"", "type":"date"} ],
"rows":
[
{ "c": [ {"v":"a"}, {"v":"Date(2010,10,6)"} ] },
{ "c": [ {"v":"b"}, {"v":"Date(2010,10,7)"} ] }
]
}
There's more info in the google.visualization.DataTable reference docs.
Related
I'm new to coding but over the last several months I've managed to fumble my way through creating a web site that utilises a Google Line Chart and embedded linear trendline to display historical Mean Sea Level and the rate of Mean Sea Level rise for various locations around New Zealand and the Pacific. Each location has it's own Google Line Chart with a linear trendline to show the rate of Mean Sea Level Change for a user selected period. I now want to extend the functionality of each Google Line Chart such that both a linear and polynomial trendline extend to the year 2120 (they currently only show up to the year 2018) even though the available data from which they are calculated uses observed data up to the year 2018. This will allow the user to predict the sea level height up to the year 2020. I realise this explanation may be confusing, so please see my web site www.sealevel.nz to see the existing charts which I hope will aid in understanding my problem.
Below is the code for the extended version of the chart that shows both a linear and second degree polynomial trendline with the x axis of the Google Line Chart now showing up the year 2120. My problem is that I need the y axis to adjust dynamically to show the entirety of both trendlines no matter which time period the user selects. For example if you select the years 1971 and 2018 from the date range slider, then both trendlines are cut off at the years 2017 (linear) and 2031 (polynomial) respectively. I need to be able to see both trendlines and their values up to the year 2120.
Please excuse my novice coding skills. My Code:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://unpkg.com/mathjs/dist/math.min.js"></script>
<script type="text/javascript">
google.load('visualization', 'current', {'packages':['controls','corechart']});
google.setOnLoadCallback(initialize);
function initialize() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1vn1iuhsG33XzFrC4QwkTdUnxOGdcPQOj-cuaEZeX-eA/edit#gid=0');
query.send(drawDashboard);
}
function drawDashboard(response) {
var data = response.getDataTable();
//Asign units of 'mm' to data.
var formatMS = new google.visualization.NumberFormat({
pattern: '# mm'
});
// format into data mm..
for (var colIndex = 1; colIndex < data.getNumberOfColumns(); colIndex++) {
formatMS.format(data, colIndex);
}
var YearPicker = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'filter_div',
'options': {
'filterColumnLabel': 'Year',
'ui': {
cssClass: 'filter-date',
'format': { pattern: '0000' },
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
},
});
var MSLChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'chart_div',
'options': {
'fontSize': '14',
'title': 'Timbucktoo Annual Mean Sea Level Summary',
hAxis: {title: 'Year', format:'0000', maxValue: 2120},
vAxis: {title: 'Height above Chart Datum (mm)', format:'0000'},
'height': 600,
chartArea: {height: '81%', width: '85%', left: 100},
'legend': {'position': 'in', 'alignment':'end', textStyle: {fontSize: 13} },
colors: ['blue'],
trendlines: {
0: {
type: 'polynomial',
degree: 2,
color: 'green',
visibleInLegend: true,
},
1: {
type: 'linear',
color: 'black',
visibleInLegend: true,
},
},
series: {
0: { visibleInLegend: true },
1: { visibleInLegend: false },
},
},
'view': {'columns': [0,1,2]}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div')).
bind(YearPicker, MSLChart).
draw(data)
</script>
first, I'm not sure why the chart would draw a trend line that isn't visible
which makes this a bit tricky, because we first have to draw the chart,
in order to find the min & max y-axis values.
but there are chart methods we can use to find the max value.
first, we get the chart's layout interface.
var chartLayout = MSLChart.getChart().getChartLayoutInterface();
since we're using a ChartWrapper, we have to get the chart from the wrapper (MSLChart.getChart()).
next, we use method getBoundingBox to find the min & max values of each line.
var yAxisCoords = {min: null, max: null};
var lineIndex = 0;
var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
do {
yAxisCoords.max = yAxisCoords.max || boundsLine.top;
yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
lineIndex++;
boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
} while (boundsLine !== null);
then we use method getVAxisValue to determine what each y-axis value should be,
set the viewWindow on the y-axis, and re-draw the chart.
MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
MSLChart.draw();
we do all this in a function.
we use a one time 'ready' event on the chart wrapper for the first calculation.
then again, on the chart.
google.visualization.events.addOneTimeListener(MSLChart, 'ready', filterChange);
function filterChange() {
// get chart layout
var chartLayout = MSLChart.getChart().getChartLayoutInterface();
// get y-axis bounds
var yAxisCoords = {min: null, max: null};
var lineIndex = 0;
var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
do {
yAxisCoords.max = yAxisCoords.max || boundsLine.top;
yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
lineIndex++;
boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
} while (boundsLine !== null);
// re-draw chart
MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
MSLChart.draw();
google.visualization.events.addOneTimeListener(MSLChart.getChart(), 'ready', filterChange);
}
see following working snippet...
(when you run the snippet, click "full page" at the top right)
google.charts.load('current', {
packages: ['controls']
}).then(initialize);
function initialize() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1vn1iuhsG33XzFrC4QwkTdUnxOGdcPQOj-cuaEZeX-eA/edit#gid=0');
query.send(drawDashboard);
}
function drawDashboard(response) {
var data = response.getDataTable();
//Asign units of 'mm' to data.
var formatMS = new google.visualization.NumberFormat({
pattern: '# mm'
});
// format into data mm..
for (var colIndex = 1; colIndex < data.getNumberOfColumns(); colIndex++) {
formatMS.format(data, colIndex);
}
var YearPicker = new google.visualization.ControlWrapper({
controlType: 'NumberRangeFilter',
containerId: 'filter_div',
options: {
filterColumnLabel: 'Year',
ui: {
cssClass: 'filter-date',
format: {pattern: '0000'},
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false
}
},
});
var MSLChart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart_div',
dataTable: data,
options: {
fontSize: '14',
title: 'Timbucktoo Annual Mean Sea Level Summary',
hAxis: {title: 'Year', format: '0000', maxValue: 2120},
vAxis: {title: 'Height above Chart Datum (mm)', format:'###0'},
height: 600,
chartArea: {height: '81%', width: '85%', left: 100},
legend: {position: 'in', alignment: 'end', textStyle: {fontSize: 13}},
colors: ['blue'],
trendlines: {
0: {
type: 'polynomial',
degree: 2,
color: 'green',
visibleInLegend: true,
},
1: {
type: 'linear',
color: 'black',
visibleInLegend: true,
},
},
series: {
0: { visibleInLegend: true },
1: { visibleInLegend: false },
},
},
view: {columns: [0,1,2]}
});
google.visualization.events.addOneTimeListener(MSLChart, 'ready', filterChange);
function filterChange() {
// get chart layout
var chartLayout = MSLChart.getChart().getChartLayoutInterface();
// get y-axis bounds
var yAxisCoords = {min: null, max: null};
var lineIndex = 0;
var boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
do {
yAxisCoords.max = yAxisCoords.max || boundsLine.top;
yAxisCoords.max = Math.min(yAxisCoords.max, boundsLine.top);
yAxisCoords.min = yAxisCoords.min || (boundsLine.top + boundsLine.height);
yAxisCoords.min = Math.max(yAxisCoords.min, (boundsLine.top + boundsLine.height));
lineIndex++;
boundsLine = chartLayout.getBoundingBox('line#' + lineIndex);
} while (boundsLine !== null);
// re-draw chart
MSLChart.setOption('vAxis.viewWindow.max', chartLayout.getVAxisValue(yAxisCoords.max));
MSLChart.setOption('vAxis.viewWindow.min', chartLayout.getVAxisValue(yAxisCoords.min));
MSLChart.draw();
google.visualization.events.addOneTimeListener(MSLChart.getChart(), 'ready', filterChange);
}
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_div')
).bind(YearPicker, MSLChart).draw(data);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
<div id="chart_div"></div>
<div id="filter_div"></div>
</div>
note: it appears you're using an old load statement, to load google chart.
see above snippet for update...
I have been having trouble trying to set up a Google Charts dashboard with two charts and two controlwrappers using two queries to a Google sheet.
I have gone through many of the examples on here demonstrating multiple graphs from single sources, or multiple queries for multiple charts but no control aspect.
I am ultimately trying to run two queries of a single Google sheet, each query pulling a different set of data from the sheet based on the query string, then displaying the data in a graph. There would also be a filterColumn control wrapper that selects data from the data table.
I have the following code which works for one query and graph. When I try to double up the process so that I can display both in one page, one or the other graph will appear, but not both.
I get that this may be something to do with a conflict between the queries, but I don't understand it.
I tried building one function that ran both queries that would be initiated by the google.setOnLoadCallback function. However, that didn't work. I tried to combine the various parts using others examples as guides, but those don't work.
This is the closest version, and when I refresh it several times in a row sometimes one chart will load, other times the other, but never both.
If someone can point me in the right direction I would appreciate it.
<html>
<head>
<title>Google visualisation demo: chart query controls</title>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load the Visualization API and the controls package.
// Packages for all the other charts you need will be loaded
// automatically by the system.
google.load('visualization', '1.1', {
'packages': ['controls', 'linechart', 'corechart']
});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(initialize);
google.setOnLoadCallback(initialize2);
function initialize() {
var queryString = encodeURIComponent("select B, ((5-avg(F))*.4) + ((5-avg(G))*.4) + ((5-avg(H))*.2) + ((5-avg(I))*.125) + ((5-avg(J))*.125) where C contains 'Sept 26' and E contains 'Forced' group by B");
// Replace the data source URL on next line with your data source URL.
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1_DuiDpbRyegaN0zYR4iYp8ZXefO-kIV-F054e9aIcIY/gviz/tq?gid=1757506986&headers=1&tq=' + queryString);
// Send the query with a callback function.
query.send(drawDashboard);
}
function initialize2() {
var queryString2 = encodeURIComponent("select B, ((5-avg(F))*.4) + ((5-avg(G))*.4) + ((5-avg(H))*.2) + ((5-avg(I))*.125) + ((5-avg(J))*.125) where C contains 'Sept 26' and E contains 'Unforced' group by B");
var query2 = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1_DuiDpbRyegaN0zYR4iYp8ZXefO-kIV-F054e9aIcIY/gviz/tq?gid=1757506986&headers=1&tq=' + queryString2);
// Send the query with a callback function.
query2.send(drawDashboard2);
}
function drawDashboard(response) {
var data = response.getDataTable();
// Everything is loaded. Assemble your dashboard...
var namePicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_div',
'options': {
'filterColumnLabel': 'Sample ID',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var laptimeChart = new google.visualization.ChartWrapper({
'chartType': 'Bar',
'containerId': 'chart_div',
'dataSourceUrl': 'https://docs.google.com/spreadsheets/d/1_DuiDpbRyegaN0zYR4iYp8ZXefO-kIV-F054e9aIcIY/gviz/tq?gid=1757506986&headers=1',
'query': "select B, ((5-avg(F))*.4) + ((5-avg(G))*.4) + ((5-avg(H))*.2) + ((5-avg(I))*.125) + ((5-avg(J))*.125) where C contains 'Sept 26' and E contains 'Forced' group by B",
'options': {
'width': 1600,
'height': 800,
axes: {
x: {
0: {
side: 'top',
label: 'Sample ID'
} // Top x-axis.
}
},
chart: {
title: 'Aging Panel Results',
subtitle: 'Beer force-aged for 2 weeks',
},
'legend': {
position: 'none'
},
'colors': ['#ed8907']
}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div')).
bind(namePicker, laptimeChart).
draw(data)
}
function drawDashboard2(response2) {
var data2 = response2.getDataTable();
// Everything is loaded. Assemble your dashboard...
var namePicker2 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_div2',
'options': {
'filterColumnLabel': 'Sample ID',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var laptimeChart2 = new google.visualization.ChartWrapper({
'chartType': 'Bar',
'containerId': 'chart_div2',
'options': {
'width': 1600,
'height': 800,
axes: {
x: {
0: {
side: 'top',
label: 'Sample ID'
} // Top x-axis.
}
},
chart: {
title: 'Aging Panel Results',
subtitle: 'Beer aged 2 weeks',
},
'legend': {
position: 'none'
},
'colors': ['Red']
}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div2')).
bind(namePicker2, laptimeChart2).
draw(data2)
}
</script>
</head>
<body>
<!--Div that will hold the dashboard-->
<div id="dashboard_div">
<!--Divs that will hold each control and chart-->
<div id="filter_div"></div>
<div id="chart_div"></div>
</div>
<div id="dashboard_div2">
<!--Divs that will hold each control and chart-->
<div id="filter_div2"></div>
<div id="chart_div2"></div>
</div>
</body>
</html>
first, need to use loader.js for loading the libraries,
this...
<script src="https://www.gstatic.com/charts/loader.js"></script>
not this...
<script src="https://www.google.com/jsapi"></script>
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.
second, you should only use google.setOnLoadCallback once per page
it can also be included in the google.charts.load statement, as in the following example
next, the chartType is incorrect and needs to exist in the packages loaded
for core charts, load package 'corechart' and use --> chartType: 'BarChart'
for material charts, load package: 'bar' --> chartType: 'Bar'
(don't recommend using material charts, several options don't work)
finally, since the chart wrappers are drawn using a dashboard,
don't need these options --> 'dataSourceUrl' or 'query'
see following working snippet...
google.charts.load('current', {
callback: function () {
var queryString = encodeURIComponent("select B, ((5-avg(F))*.4) + ((5-avg(G))*.4) + ((5-avg(H))*.2) + ((5-avg(I))*.125) + ((5-avg(J))*.125) where C contains 'Sept 26' and E contains 'Forced' group by B");
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1_DuiDpbRyegaN0zYR4iYp8ZXefO-kIV-F054e9aIcIY/gviz/tq?gid=1757506986&headers=1&tq=' + queryString);
query.send(drawDashboard);
var queryString2 = encodeURIComponent("select B, ((5-avg(F))*.4) + ((5-avg(G))*.4) + ((5-avg(H))*.2) + ((5-avg(I))*.125) + ((5-avg(J))*.125) where C contains 'Sept 26' and E contains 'Unforced' group by B");
var query2 = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1_DuiDpbRyegaN0zYR4iYp8ZXefO-kIV-F054e9aIcIY/gviz/tq?gid=1757506986&headers=1&tq=' + queryString2);
query2.send(drawDashboard2);
},
packages: ['controls', 'corechart']
});
function drawDashboard(response) {
var namePicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'filter_div',
options: {
filterColumnLabel: 'Sample ID',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false
}
}
});
var laptimeChart = new google.visualization.ChartWrapper({
chartType: 'BarChart',
containerId: 'chart_div',
options: {
width: 1600,
height: 800,
axes: {
x: {
0: {
side: 'top',
label: 'Sample ID'
}
}
},
chart: {
title: 'Aging Panel Results',
subtitle: 'Beer force-aged for 2 weeks',
},
legend: {
position: 'none'
},
colors: ['#ed8907']
}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div')).
bind(namePicker, laptimeChart).
draw(response.getDataTable());
}
function drawDashboard2(response) {
var namePicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'filter_div2',
options: {
filterColumnLabel: 'Sample ID',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false
}
}
});
var laptimeChart = new google.visualization.ChartWrapper({
chartType: 'BarChart',
containerId: 'chart_div2',
options: {
width: 1600,
height: 800,
axes: {
x: {
0: {
side: 'top',
label: 'Sample ID'
}
}
},
chart: {
title: 'Aging Panel Results',
subtitle: 'Beer force-aged for 2 weeks',
},
legend: {
position: 'none'
},
colors: ['#ed8907']
}
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div2')).
bind(namePicker, laptimeChart).
draw(response.getDataTable());
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
<div id="filter_div"></div>
<div id="chart_div"></div>
</div>
<div id="dashboard_div2">
<div id="filter_div2"></div>
<div id="chart_div2"></div>
</div>
How exactly do I use the jquery ui slider instead of a numberrange filter. I have an idea of how each work, but am unsure how this needs to be related to the chart data.
EDIT: Whole code(sorry about comments):
<!DOCTYPE html>
<head>
<title>Google Chart Example</title>
<script src="https://www.google.com/jsapi"></script>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<!-- <script src="http://prithwis.x10.bz/charts/jquery.csv-0.71.js"></script> -->
<script src="https://jquery-csv.googlecode.com/files/jquery.csv-0.71.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link href="http://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet">
<!--script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script-->
<!--script src="http://code.jquery.com/jquery-1.10.2.js"></script-->
<script type="text/javascript">
google.load('visualization', '1.1', {packages: ['controls']});
google.setOnLoadCallback(drawVisualization);
function drawVisualization() {
// Prepare the data
//$.get("abc.csv - abc.csv.csv", function(csvString) {
$.get("Data_Actual_V2.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// use arrayData to load the select elements with the appropriate options
for (var i = 1; i < arrayData[0].length; i++) { // i starts from 1, not 0 because the first column is text
// this adds the given option to both select elements
$("select").append("<option value='" + i + "'>" + arrayData[0][i] + "</option");
}
// set the default selection
$("#range option[value='1']").attr("selected","selected");
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);
var columnsTable = new google.visualization.DataTable();
columnsTable.addColumn('number', 'colIndex');
columnsTable.addColumn('string', 'colLabel');
var initState = {
selectedValues: []
};
// put the columns into this data table (skip column 0)
for (var i = 2; i < data.getNumberOfColumns(); i++) {
columnsTable.addRow([i, data.getColumnLabel(i)]);
}
initState.selectedValues.push(data.getColumnLabel(4));
var CountryPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control3',
options: {
filterColumnLabel: 'Location',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: true,
caption: 'Country',
label: 'Country'
}
}
});
/*var slider2 = new google.visualization.ControlWrapper({
//'controlType': 'DateRangeFilter',
'controlType': 'NumberRangeFilter',
'containerId': 'control4',
'options': {
//'ui.format': 'pattern:"yyyy"',
// 'ui.format': 'fractionDigits: 0',
'filterColumnLabel': 'Year',
'ui': { 'format': { 'fractionDigits':'0',
'groupingSymbol':'' } }
},
}); */
//Define a chart to show AML CFT Risk per country
var options1 = {
title: 'A',
displayMode: 'regions',
//width: 1000,
datalessRegionColor: 'C0C0C0',
hAxis: {title: 'Year', }
colorAxis: {
values: [0, 12.5, 25, 37.5, 50, 62.5, 75, 87.5, 100],
colors: ['#3366FF','#33CCCC', '#00FFFF', '#CCFFFF', '#00FF00', '#FFFF99','#FFCC00','#FF9900','#FF0000'],
minValue: 0,
maxValue: 100,
}
}
var xA;
//var yB = 4;
/*var view1 = { // Defines data to show in geoChart
columns: [x1, y1] //[0,4]
}*/
var geoChart = new google.visualization.ChartWrapper({
chartType: 'GeoChart',
containerId: 'chart1',
options: options1,
view: {
columns: [0, 4]
}
});
$(function() {
$('#slider').slider({
disabled: true,
range: 'min',
value: 44,
min: 1969,
max: 2013,
change: function(event, ui) {
$('#header').text('debug=' + ui.value);
//options1.minValue = ui.value;/////HERE TO LINK TO ABOVE
xA = ui.value;
console.log(xA);
//drawChart();
setChartView();
}
});
});
var GenderPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control2',
dataTable: columnsTable,
options: {
filterColumnLabel: 'colLabel',
ui: {
label: 'Columns',
allowTyping: false,
allowMultiple: false,
allowNone: false,
selectedValuesLayout: 'belowStacked'
}
},
state: initState
});
function setChartView() {
var state = GenderPicker.getState();
var row;
var view = {
columns: [0]
};
for (var i = 0; i < state.selectedValues.length; i++) {
row = columnsTable.getFilteredRows([{
column: 1,
value: state.selectedValues[i]
}])[0];
view.columns.push(columnsTable.getValue(row, 0));
}
// sort the indices into their original order
view.columns.sort(function (a, b) {
return (a - b);
});
geoChart.setView(view);
geoChart.draw();
}
google.visualization.events.addListener(GenderPicker, 'statechange', setChartView);
google.visualization.events.addOneTimeListener(geoChart, 'ready', function () {
$('#slider').slider('enable');
setChartView();
});
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
dashboard.bind([CountryPicker/*, slider2*/],[geoChart]). // consolidated all of the bind calls
// Draw the dashboard
draw(data);
GenderPicker.draw();
});
}
<body>
<div id="dashboard">
<table>
<tr style='vertical-align: top'>
<td style='width: 300px; font-size: 0.9em;'>
<div id="control1"></div>
<div id="control2"></div>
<div id="control3"></div>
<div id="control4"></div>
<div id="slider"></div>
<h3 id ="header">Sometext</h3>
</td>
<td style='width: 600px'>
<div style="float: left;" id="chart1"></div>
</td>
</tr>
</table>
</div>
</body>
</html>
Have been trying to follow: Using jQuery slider to change Google chart viewWindow
With a bit of this as well: https://stackoverflow.com/questions/26154248/how-to-display-various-controlwrappers-from-2-datatables-with-a-single-geochart?noredirect=1#comment41031194_26154248
EDIT V2
I solved it by using the standard google slider, and assigning my jquery slider value to it's 'highValue'. I then set the div containing the google slider to display: none.
var slider2 = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'control4',
'options': {
'filterColumnLabel': 'Year',
'ui': { 'format': { 'fractionDigits':'0',
'groupingSymbol':'' } }
},
});
$(function() {
$('#slider').slider({
disabled: true,
range: 'min',
value: 53,
min: 1960,
max: 2013,
change: function(event, ui) {
$('#header').text('debug=' + ui.value);
//options1.minValue = ui.value;/////HERE TO LINK TO ABOVE
xA = ui.value;
console.log(xA);
//drawChart();
slider2.setState({'highValue': ui.value});
slider2.draw();
setChartView();
}
});
});
<div id="control4" style="display: none;"></div>
Definitely, not the nicest or most correct method of doing this, however it did solve the problem.
I have google vis datatable and dashboard (control filters, string control, datatable, charts). All element is bind.
So I get from database JSON and send to gViz api to draw table, chart and control.
When I use contols to filter some data and if there is no data for that string then I get error from google visualisation like this:
One or more participants failed to draw()×
Table has no rows.×
and similar messages. So in my app this is so ugly so is there any way to not showing it?
So if there is no data to not show the error...
I try with CSS option:
#google-visualization-errors-all-3 {
display:none;
}
but its not good solution for me.
Is there any other way, maybe in google visualusation api for dashboard?
UPDATE:
var slider;
var ajdi = '';
function drawVisualization() {
var cssClassNames = {
'headerRow': 'zaglavlje',
'tableRow': 'red',
'oddTableRow': 'red1',
'selectedTableRow': 'orange-background large-font',
'hoverTableRow': 'prekoreda',
'headerCell': 'gold-border',
'tableCell': 'cell',
'rowNumberCell': 'underline-blue-font'
};
var json = $.ajax({
url: 'getzadaci.php', // make this url point to the data file
dataType: 'json',
async: false
}).responseText;
// Create our data table out of JSON data loaded from server.
var data = new google.visualization.DataTable(json);
//dodajemo kolonu sa kontrolama
// Define a category picker control for the Gender column
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'Status',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Status'
}
}
});
var categoryPicker1 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnIndex': 8,
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Parcela'
}
}
});
var categoryPicker2 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control4',
'options': {
'filterColumnIndex': 2,
'ui': {
'labelStacking': 'horizontal',
'allowTyping': false,
'allowMultiple': true,
'caption': 'Vrsta zadatka'
}
}
});
var stringFilter1 = new google.visualization.ControlWrapper({
'controlType': 'StringFilter',
'containerId': 'control3',
'options': {
'matchType': 'any',
'filterColumnIndex': 1,
'ui': {'labelStacking': 'vertical'}
}
});
var slider = new google.visualization.ControlWrapper({
'controlType': 'DateRangeFilter',
'containerId': 'control5',
'options': {
'filterColumnLabel': 'Pocetak',
'ui': {'labelStacking': 'vertical'}
}
});
// Define a Pie chart
// Define a table
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'chart2',
'cssClassNames': 'cssClassNames',
'view': { 'columns': [1,2,12,5,6,8,11] },
'options': {
cssClassNames: cssClassNames,
allowHtml: true
}
});
var timeline = new google.visualization.ChartWrapper({
chartType: 'Timeline',
containerId: 'chart5',
options: {
height: '350',
timeline: { colorByRowLabel: true,
backgroundColor: '#ffd' },
//timeline.barLabelStyle: {color: '#000', fontName: 'Arial', fontSize: '13px'},
//backgroundColor: '#fff',
colors: ['#55c2a2', '#89d168', '#d3eb87','#8ec63e', '#FFF0BA','#FF542E', '#CFD6DE', '#ADC1D6', '#7297BA']
//timeline: { rowLabelStyle: {fontName: 'Helvetica', fontSize: 24, color: '#603913' },
// barLabelStyle: { fontName: 'Garamond', fontSize: 14 } }
},
view: {
// as an example, use columns "Naziv", "Vrsta", "Pocetak", and "Zavrsetak" for the timeline
columns: [8, 2, 5, 6]
},
});
var formatter_short = new google.visualization.DateFormat({formatType: 'short'});
formatter_short.format(data, 5);
formatter_short.format(data, 6);
new google.visualization.events.addListener(table, 'ready', function () {
google.visualization.events.addListener(table.getChart(), 'select', function () {
var selection = table.getChart().getSelection();
// iterate over all selected rows
for (var i = 0; i < selection.length; i++) {
//$("#edit").removeClass("edit btn btn-success")
//$('#edit').addClass('edit btn btn-success');
ajdi = table.getDataTable().getValue(selection[i].row,0);
$("#vrednostid").val(table.getDataTable().getValue(selection[i].row,0));
$("#naziv1").val(table.getDataTable().getValue(selection[i].row,1));
$("#vrsta_rada1").val(table.getDataTable().getValue(selection[i].row,2));
$("#status1").val(table.getDataTable().getValue(selection[i].row,3));
$("#opis1").val(table.getDataTable().getValue(selection[i].row,4));
$("#usluzno1").val(table.getDataTable().getValue(selection[i].row,9));
var p = new Date(table.getDataTable().getValue(selection[i].row,5));
$("#dp31").datepicker("setDate", p);
var z = new Date(table.getDataTable().getValue(selection[i].row,6));
$("#dp41").datepicker("setDate", z);
//$("#parcele1").val(table.getDataTable().getValue(selection[i].row,8));
//$("#parcele1").select2("val", ["3","19"]);
var id = table.getDataTable().getValue(selection[i].row,10);
var naziv = table.getDataTable().getValue(selection[i].row,8);
var idArr = (id.lastIndexOf(',') == (id.length - 1) ? id.substr(0, id.length - 1) : id).split(', ');
var nazivArr = (naziv.lastIndexOf(',') == (naziv.length - 1) ? naziv.substr(0, naziv.length - 1) : naziv).split(', ');
var objHold = [];
for(var j=0,length=idArr.length;j<length;j++)
{
if(idArr[j] && nazivArr[j]) // make sure both arrays have a value
objHold.push({id: idArr[j], naziv: nazivArr[j]});
}
$("#parcele1").select2("data", objHold);
}
});
});
// Create a dashboard
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Establish bindings, declaring the both the slider and the category
// picker will drive both charts.
bind([categoryPicker, categoryPicker1, categoryPicker2, slider, stringFilter1], [table, timeline]).
// Draw the entire dashboard.
draw(data, {'allowHtml':true, 'cssClassNames': 'cssClassNames'}); }
//table.draw(data, {'allowHtml':true, 'cssClassNames': cssClassNames}); }
function dashboardReady() {
// The dashboard is ready to accept interaction. Configure the buttons to
// programmatically affect the dashboard when clicked.
// Change the slider selected range when clicked.
document.getElementById('rangeButton').onclick = function() {
slider.setState({'lowValue': 2, 'highValue': 5});
slider.draw();
};
// Change the pie chart rendering options when clicked.
document.getElementById('optionsButton').onclick = function() {
piechart.setOption('is3D', true);
piechart.draw();
};
}
google.setOnLoadCallback(drawVisualization);// JavaScript Document
This is my code, so the important part is .ajac function, so how I can here integrate if row>0 to show charts ???
I had the same problem using the Google Charts API. To get around it I simply had to check the number of rows that made it through the filters. If it's >= 1, draw the chart. else do whatever you need to; don't draw the chart, display error, etc.
I've seen a solution to your code in someone else's fork of a GitHub project I've done a bit of work on. Since I didn't write this I'll link to it in this repository:
leonardean/angular-google-charts
Here's to code in case this link breaks:
google.visualization.events.addListener(chartWrapper, 'error', function (err) {
google.visualization.errors.removeError(err.id);
});
If you click the link above it will show you the lines I'm refering to highlighted. Basically, the author of this code is passing an event listener to the google charts api that listens for the error event, and then in the error handler removes the error. Not exactly a best practice, but I believe this would still log to console. If it doesn't you can just log the error to console yourself from the handler, but it does get rid of the ugly red box.
This function will get rid of all google chart error messages. Call it in a script tag after your DOM and charts have loaded.
// Gets rid of all Google's error messages
function removeGoogleErrors() {
var id_root = "google-visualization-errors-all-";
var index = 1;
while (document.getElementById(id_root + index.toString()) != null) {
document.getElementById(id_root + index.toString()).style.display = 'none';
index += 2;
}
}
I am writing to seek help, in how do can I create multi-series line chart from [name] column below. Currently, I am plotting the chart using [date] and [tag] points. However, I would like to show multi-series line chart for each names. Is this plausible or does this task require manual functions to be created to link in with the API.
Please advice.
function drawVisualization() {
// Prepare the data
var data = google.visualization.arrayToDataTable([
['Name', 'Tag', 'Date'],
['ACCA', 45, 'May 14'],
['ABBA', 85, 'May 14'],
['ANNA', 100, 'May 14'],
['AMMA', 100.5, 'May 14'],
['ACCA', 99.5, 'May 15'],
['ABBA', 85.5, 'May 15'],
['ACCA', 99.6, 'May 15'],
['BACM', 94, 'May 15'],
['MMBS', 96, 'May 15']
]);
// Define category pickers for 'Name',
var countryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'Name',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var barChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'chart1',
'options': {
'width': 400,
'height': 300,
'chartArea': { top: 0, right: 0, bottom: 0 }
},
// Configure the Linechart to use columns 2 (Date) and 1 (Tag)
'view': { 'columns': [2, 1] }
});
// Define a table.
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'chart2',
'options': {
'width': '300px'
}
});
new google.visualization.Dashboard(document.getElementById('dashboard')).bind([countryPicker], [barChart, table]).draw(data);
}
Edit:
Thanks.
To make this work, I would suggest removing the LineChart from your Dashboard, and using the Table's "ready" event to get the filtered data, create appropriate settings for the chart's view.columns parameter, and then drawing the chart with the filtered data:
google.visualization.events.addListener(table, 'ready', function () {
var filteredData = table.getDataTable();
// get a list of all the labels in column 0
var group = filteredData.getDistinctValues(0);
// build the columns for the view
var columns = [0];
for (var i = 0; i < group.length; i++) {
var label = group[i];
// set the columns to use in the chart's view
// calculated columns put data belonging to each country in the proper column
columns.push({
type: 'number',
label: label,
calc: (function (name) {
return function (dt, row) {
return (dt.getValue(row, 0) == name) ? dt.getValue(row, 1) : null;
}
})(label)
});
}
var view = barChart.getView() || {};
view.columns = columns;
barChart.setView(view);
barChart.setDataTable(filteredData);
barChart.draw();
});
new google.visualization.Dashboard(document.getElementById('dashboard')).bind([countryPicker], [table]).draw(data);