Related
I'm trying to combine two charts and a filter, specifically a Pie Chart and Sankey Diagram with no success. There is a similar answered question, but the difference with my problem is that I am embedding my charts inside a dashboard so I can use the slicer filter.
I have tried several ideas to solve it but only the Pie Chart and the slicer appear or simply nothing appears.
Ideas I have tried:
Passing only the columns I need in the view property of the ChartWrapper class.
Naming the columns and casting the data types as shown in the examples for the Sankey diagram
Passing only the data I need to the Sankey through the dataTable property of the ChartWrapper class
For the moment, I have used the sample code from Google Charts documentation. What I am trying to do is to make appear both charts, so I can arrange de visualizations in the dashboard and then use my own data.
Thanks for the help!
Sample code bellow:
I include the loader in the partials/header file
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<%- include("partials/header"); -%>
<script type="text/javascript">
// Load the Visualization API and the controls package.
google.charts.load('current', {
'packages': ['corechart', 'controls', 'sankey']
});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.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() {
// Create our data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', 'Donuts eaten');
data.addColumn('string', 'From');
data.addColumn('string', 'To');
data.addColumn('number', 'Weight');
data.addRows([
['Michael', 5, 'A', 'X', 2],
['Elisa', 7, 'A', 'Y', 7],
['Robert', 3, 'A', 'Z', 6],
['John', 2, 'B', 'X', 1],
['Jessica', 6, 'B', 'Y', 9],
['Aaron', 1, 'B', 'Z', 4],
['Margareth', 8, 'C', 'X', 4]
]);
// Create a dashboard.
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_div'));
// Create a range slider, passing some options
var donutRangeSlider = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'filter_div',
'options': {
'filterColumnLabel': 'Donuts eaten'
},
'view': {
'columns': [0, 1]
}
});
// Create a pie chart, passing some options
var pieChart = new google.visualization.ChartWrapper({
'chartType': 'PieChart',
'containerId': 'chart_div',
'options': {
'width': 300,
'height': 300,
'pieSliceText': 'value',
'legend': 'right'
},
'view': {
'columns': [0, 1]
}
});
var sankeyChart = new google.visualization.ChartWrapper({
'chartType': 'Sankey',
'containerId': 'sankey_div',
'options': {
'width': 600
},
'view': {
'columns': [2, 3, 4]
}
});
// 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(donutRangeSlider, pieChart, sankeyChart);
// Draw the dashboard.
dashboard.draw(data);
}
</script>
<div id="dashboard_div">
<!--Divs that will hold each control and chart-->
<div id="filter_div"></div>
<div id="chart_div"></div>
<div id="sankey_div" style="width: 900px; height: 300px;"></div>
</div>
<%- include("partials/footer"); -%>
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...
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>
I want to display the results of students using a single chart.
There are 4 exam phases in a year and 5 activities in each phase and each activity has grades ranging from A to G.
I'm using google line chart for this purpose.
Code for Generating the graph
[<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['line']});
google.charts.setOnLoadCallback(drawLineChart);
function drawLineChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Phase');
data.addColumn('string', 'Activity 1');
data.addColumn('string', 'Activity 2');
data.addColumn('string', 'Activity 3');
data.addColumn('string', 'Activity 4');
data.addColumn('string', 'Activity 5');
data.addRows([
['1', 'A','B','C','D','E'],
['2', 'E','D','C','B','A'],
['3', 'A','B','C','D','E'],
['4', 'E','D','C','B','A'],
]);
var options = {
title: 'Student Result',
width: 600,
height: 550,
legend: { position: 'bottom' },
vAxis: { ticks: ['A','B','C','D','E','F','G']}
};
var chart = new google.charts.Line(document.getElementById('line_top_x'));
chart.draw(data, google.charts.Line.convertOptions(options));
}
</script>
</head>
<body>
<div id="line_top_x"></div>
</body>
</html>
Link to the Output of this code
The axis is null. It is not generating the chart as per data.
if you check the data format for a line chart,
only the first column in the data table may be of type 'string',
the rest should be 'number'
in this case, you could convert each grade to a number.
then use object notation to show the grade instead of the number.
using object notation allows you to provide the value (v:) and the formatted value (f:)
{v: 0, f: 'A'}
the formatted value is displayed by default.
next, if you want to customize the vertical axis, by using ticks,
you won't be able to use a material chart --> google.charts.Line
you will need to use a classic chart instead --> google.visualization.LineChart
there are several options that are not supported by material charts, including ticks
see Tracking Issue for Material Chart Feature Parity for more info.
see following working snippet for an example...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var scale = {
'A': 0,
'B': 1,
'C': 2,
'D': 3,
'E': 4,
'F': 5,
'G': 6
};
var grades = [
['1','A','B','C','D','E'],
['2','E','D','C','B','A'],
['3','A','B','C','D','E'],
['4','E','D','C','B','A']
];
var data = new google.visualization.DataTable();
data.addColumn('string', 'Phase');
data.addColumn('number', 'Activity 1');
data.addColumn('number', 'Activity 2');
data.addColumn('number', 'Activity 3');
data.addColumn('number', 'Activity 4');
data.addColumn('number', 'Activity 5');
grades.forEach(function (activities) {
var row = [];
activities.forEach(function (grade, indexGrade) {
if (indexGrade === 0) {
row.push(grade);
} else {
row.push({
v: scale[grade],
f: grade
});
}
});
data.addRow(row);
});
var options = {
title: 'Student Result',
width: 600,
height: 550,
legend: {
position: 'bottom'
},
vAxis: {
ticks: [
{v: 0, f: 'A'},
{v: 1, f: 'B'},
{v: 2, f: 'C'},
{v: 3, f: 'D'},
{v: 4, f: 'E'},
{v: 5, f: 'F'},
{v: 6, f: 'G'}
]
}
};
var chart = new google.visualization.LineChart(document.getElementById('line_top_x'));
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="line_top_x"></div>
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?