Google Bar Chart - custom Legend text with total values & column wise total for Table chart - charts

i would like get the total value of Grades in Stacked Bar Graph Legend. picture attached how i wud like to have... for the following working snippet.
and also the Column wise Total for the Table Chart...
i think this can be done with following but how to get it done..
data.setFormattedValue(i, 0, key + ' (' + val + ')');
can have something like this.. when mouseover one location on Bar... need to show all the grades values in single annotation..??
is it possible to have the different values in highlighted places like in below picture? circle B is overall total of Grade1 in graph is correct. and circle A the tooltip total should show for that particular locations total of every Grade's annotation like below.
['Location', 'Company', 'Grade1',{ role: 'annotation' }, 'Grade2',{ role: 'annotation' }, 'Grade3',{ role: 'annotation' }, 'Bal-Grade', 'Total', { role: 'annotation' } ],
google.charts.load('current', {
packages: ['corechart', 'table', 'gauge', 'controls']
}).then(function () {
drawMainDashboard();
});
function drawMainDashboard() {
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_division1'));
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'categoryPicker_div',
'options': {
'filterColumnIndex': 1,
'ui': {
'labelStacking': 'vertical',
'label': 'Company Selection:',
'allowTyping': false,
'allowMultiple': false
}
}
});
var categoryPicker1 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'categoryPicker_div1',
'options': {
'filterColumnIndex': 0,
'ui': {
'labelStacking': 'vertical',
'label': 'Location Selection:',
'allowTyping': false,
'allowMultiple': false
}
}
});
var columnchrt = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'chart_div',
'options': {
title: "Locations charts",
width: 850,
height: 500,
legend: { position: 'top', maxLines: 2 },
bar: { groupWidth: '70%' },
isStacked: true,
focusTarget: 'category',
aggregationTarget: 'category',
explorer: {keepInBounds: true, maxZoomIn: 10.0}
}
});
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'table_div',
'options': {
showRowNumber: true,
width: '100%',
height: '100%',
allowHtml: true
},
'view': {'columns': [0,1,2,3,4,5,6]}
});
google.visualization.events.addOneTimeListener(table, 'ready', calcTotals);
function calcTotals() {
// get filtered data table from table chart
var dt = table.getDataTable();
// build aggregation and view columns
var aggColumns = [];
var viewColumns = [0];
for (var i = 2; i < dt.getNumberOfColumns(); i++) {
if (i !== dt.getNumberOfColumns() - 1) {
if (dt.getColumnType(i) === 'number') {
if (dt.getColumnRole(i) !== 'annotation') {
addAggColumn(i);
if (i !== dt.getNumberOfColumns() - 2) {
viewColumns.push(i - 1);
}
}
}
}
}
function addAggColumn(index) {
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index,
label: dt.getColumnLabel(index),
type: dt.getColumnType(index)
});
}
// aggregate data table
var agg = google.visualization.data.group(
dt,
[0],
aggColumns
);
var aggTotal = google.visualization.data.group(
dt,
[{
column: 0,
label: 'Total',
modifier: function (val) {
return 'Total';
},
type: 'string'
}],
aggColumns
);
dt = dt.toDataTable();
dt.addRow(['Total', '--', aggTotal.getValue(0, 1), aggTotal.getValue(0, 2), aggTotal.getValue(0, 3), aggTotal.getValue(0, 4), aggTotal.getValue(0, 5), null]);
table.setDataTable(dt);
table.draw();
viewColumns.push({
calc: function (dt, row) {
var total = 0;
for (var c = 1; c < dt.getNumberOfColumns(); c++) {
if (dt.getColumnLabel(c) !== 'Total') {
total += dt.getValue(row, c);
}
}
return total.toFixed(0);
},
role: 'annotation',
type: 'string'
});
// create agg data view to add annotation
var view = new google.visualization.DataView(agg);
view.setColumns(viewColumns);
view = view.toDataTable();
for (var vc = 0; vc < view.getNumberOfColumns(); vc++) {
var viewLabel = view.getColumnLabel(vc);
for (var ac = 0; ac < agg.getNumberOfColumns(); ac++) {
var aggLabel = agg.getColumnLabel(ac);
if (viewLabel === aggLabel) {
view.setColumnLabel(vc, viewLabel + ' (' + aggTotal.getFormattedValue(0, ac) + ')');
}
}
}
// draw chart
columnchrt.setDataTable(view);
columnchrt.draw();
google.visualization.events.addOneTimeListener(table, 'ready', calcTotals);
}
var data = google.visualization.arrayToDataTable([
['Location', 'Company', 'Grade1', 'Grade2', 'Grade3', 'Bal-Grade', 'Total', { role: 'annotation' } ],
['NYC', 'CUSTOMERS', 0, 0, 13, 5, 19, 29],
['CALI', 'ORG', 270, 210, 0, 32, 51, 60],
['CALI', 'CUSTOMERS', 35.942, 39, 0, 50, 126, 150],
['WDC', 'CUSTOMERS', 0, 0, 35, 52, 88, 100],
['WDC', 'CUSTOMERS', 44.507, 0, 25, 18, 88, 110],
['NJ', 'ORG', 0, 0, 54, 22, 28, 45],
['TXS', 'CUSTOMERS', 0, 0, 0, 10, 11, 20]
]);
dashboard.bind([categoryPicker,categoryPicker1], [table]);
dashboard.draw(data);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_division" style="clear:left; display:inline-block; width:100%; float:left; margin-top:5px;">
<div class="float_left panel" style="float:left; width:50%; padding:0px;">
<div id="chart_div"></div>
</div>
<div class="float_left panel" style="width:50%; padding:0px;">
<div class="table_bbar" style="background-color:#27ae60;" >
<div id="categoryPicker_div" style="right:15px; position:absolute;"></div>
<div id="categoryPicker_div1" ></div>
</div>
<div id="table_div"></div>
</div>
</div>

to get the total row for the table chart,
we can use a modifier function in the aggregation.
we aggregate once by location,
then again in total.
the modifier function allows us to return the same value for every row,
thus giving us the total for all rows.
then we can add the results from the total agg to the location agg.
// aggregate data table
var agg = google.visualization.data.group(
dt,
[0],
aggColumns
);
var aggTotal = google.visualization.data.group(
dt,
[{
column: 0,
label: 'Total',
modifier: function (val) {
return 'Total';
},
type: 'string'
}],
aggColumns
);
var rowIndex = agg.addRow();
for (var i = 0; i < agg.getNumberOfColumns(); i++) {
agg.setValue(rowIndex, i, aggTotal.getValue(0, i));
}
then we can use the agg total data table to set the labels in the column chart legend.
// create agg data view to add annotation
var view = new google.visualization.DataView(agg);
view.setColumns(viewColumns);
view = view.toDataTable();
for (var vc = 0; vc < view.getNumberOfColumns(); vc++) {
var viewLabel = view.getColumnLabel(vc);
for (var ac = 0; ac < agg.getNumberOfColumns(); ac++) {
var aggLabel = agg.getColumnLabel(ac);
if (viewLabel === aggLabel) {
view.setColumnLabel(vc, viewLabel + ' (' + aggTotal.getFormattedValue(0, ac) + ')');
}
}
}
one other slight change, since we are re-drawing the charts inside the 'ready' event,
we must use a one time event, else we'll go into an endless loop.
google.visualization.events.addOneTimeListener(table, 'ready', calcTotals);
see following working snippet...
google.charts.load('current', {
packages: ['corechart', 'table', 'gauge', 'controls']
}).then(function () {
drawMainDashboard();
});
function drawMainDashboard() {
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_division1'));
var categoryPicker = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'categoryPicker_div',
'options': {
'filterColumnIndex': 1,
'ui': {
'labelStacking': 'vertical',
'label': 'Company Selection:',
'allowTyping': false,
'allowMultiple': false
}
}
});
var categoryPicker1 = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'categoryPicker_div1',
'options': {
'filterColumnIndex': 0,
'ui': {
'labelStacking': 'vertical',
'label': 'Location Selection:',
'allowTyping': false,
'allowMultiple': false
}
}
});
var columnchrt = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'chart_div',
'options': {
title: "Locations charts",
width: 850,
height: 500,
legend: { position: 'top', maxLines: 2 },
bar: { groupWidth: '70%' },
isStacked: true,
explorer: {keepInBounds: true, maxZoomIn: 10.0}
}
});
var table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'table_div',
'options': {
showRowNumber: true,
width: '100%',
height: '100%',
allowHtml: true
},
'view': {'columns': [0,1,2,3,4,5,6]}
});
google.visualization.events.addOneTimeListener(table, 'ready', calcTotals);
function calcTotals() {
// get filtered data table from table chart
var dt = table.getDataTable();
// build aggregation and view columns
var aggColumns = [];
var viewColumns = [0];
for (var i = 2; i < dt.getNumberOfColumns(); i++) {
if (i !== dt.getNumberOfColumns() - 1) {
if (dt.getColumnType(i) === 'number') {
if (dt.getColumnRole(i) !== 'annotation') {
addAggColumn(i);
if (i !== dt.getNumberOfColumns() - 2) {
viewColumns.push(i - 1);
}
}
}
}
}
function addAggColumn(index) {
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index,
label: dt.getColumnLabel(index),
type: dt.getColumnType(index)
});
}
// aggregate data table
var agg = google.visualization.data.group(
dt,
[0],
aggColumns
);
var aggTotal = google.visualization.data.group(
dt,
[{
column: 0,
label: 'Total',
modifier: function (val) {
return 'Total';
},
type: 'string'
}],
aggColumns
);
dt = dt.toDataTable();
dt.addRow(['Total', '--', aggTotal.getValue(0, 1), aggTotal.getValue(0, 2), aggTotal.getValue(0, 3), aggTotal.getValue(0, 4), aggTotal.getValue(0, 5), null]);
table.setDataTable(dt);
table.draw();
viewColumns.push({
calc: function (dt, row) {
var total = 0;
for (var c = 1; c < dt.getNumberOfColumns(); c++) {
if (dt.getColumnLabel(c) !== 'Total') {
total += dt.getValue(row, c);
}
}
return total.toFixed(0);
},
role: 'annotation',
type: 'string'
});
// create agg data view to add annotation
var view = new google.visualization.DataView(agg);
view.setColumns(viewColumns);
view = view.toDataTable();
for (var vc = 0; vc < view.getNumberOfColumns(); vc++) {
var viewLabel = view.getColumnLabel(vc);
for (var ac = 0; ac < agg.getNumberOfColumns(); ac++) {
var aggLabel = agg.getColumnLabel(ac);
if (viewLabel === aggLabel) {
view.setColumnLabel(vc, viewLabel + ' (' + aggTotal.getFormattedValue(0, ac) + ')');
}
}
}
// draw chart
columnchrt.setDataTable(view);
columnchrt.draw();
google.visualization.events.addOneTimeListener(table, 'ready', calcTotals);
}
var data = google.visualization.arrayToDataTable([
['Location', 'Company', 'Grade1', 'Grade2', 'Grade3', 'Bal-Grade', 'Total', { role: 'annotation' } ],
['NYC', 'CUSTOMERS', 0, 0, 13, 5, 19, 19],
['CALI', 'ORG', 270, 210, 0, 32, 51, 51],
['CALI', 'CUSTOMERS', 35.942, 39, 0, 50, 126, 126],
['WDC', 'CUSTOMERS', 0, 0, 35, 52, 88, 88],
['WDC', 'CUSTOMERS', 44.507, 0, 25, 18, 88, 88],
['NJ', 'ORG', 0, 0, 54, 22, 28, 28],
['TXS', 'CUSTOMERS', 0, 0, 0, 10, 11, 11]
]);
dashboard.bind([categoryPicker,categoryPicker1], [table]);
dashboard.draw(data);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_division" style="clear:left; display:inline-block; width:100%; float:left; margin-top:5px;">
<div class="float_left panel" style="float:left; width:50%; padding:0px;">
<div id="chart_div"></div>
</div>
<div class="float_left panel" style="width:50%; padding:0px;">
<div class="table_bbar" style="background-color:#27ae60;" >
<div id="categoryPicker_div" style="right:15px; position:absolute;"></div>
<div id="categoryPicker_div1" ></div>
</div>
<div id="table_div"></div>
</div>
</div>

Related

How to put vertical lines on google chart scatter

How I can make vertical lines on a scatter google chart?
I need to put the red line vertically:
here is my current code:
//making array with data
var dataArray = [];
dataArray.push(["", "", { role: 'annotation' }, "", ""]);
projects.forEach(function(item, index){
dataArray.push([parseFloat(item["bottomData"]), parseFloat((item["leftData"])), index+1, 10, 15]);
});
var data = google.visualization.arrayToDataTable(dataArray);
//define ticks
var rangeX = data.getColumnRange(0);
var ticksX = [];
for (var i = (Math.floor(rangeX.min / 5) * 5); i <= (Math.ceil(rangeX.max / 5) * 5); i = i + 5) {
ticksX.push(i);
}
var rangeY = data.getColumnRange(1);
var ticksY = [];
for (var i =(Math.floor(rangeY.min/5) * 5); i <= Math.ceil(rangeY.max/5) * 5; i=i+5) {
ticksY.push(i);
}
//define options
var options = {
series: {
1: {
lineWidth: 2,
pointSize: 0,
color: 'green'
},
2: {
lineWidth: 2,
pointSize: 0,
color: 'red'
},
},
colors:['002060'],
vAxis: {
ticks: ticksY,
},
hAxis: {
ticks: ticksX,
},
};
//print chart
var chart = new google.visualization.ScatterChart(document.getElementById("chartDiv"));
chart.draw(data, options);
I also tried using multiple axes putting some with direction=-1 or orientation=vertical but it doesn't work
in order to mix line series with scatter,
you will need to use a ComboChart
and to get vertical lines,
you will need to add multiple rows with the same x axis value,
with values for the min and max y axis values.
in the options, set the seriesType to 'scatter'
and change the series type to 'line'
see following working snippet...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['x', 'y0', {role: 'annotation', type: 'number'}],
[26, 1, 1],
[33, 5, 2],
[36, 1, 3],
[38, 6, 4],
[58, 1, 5]
]);
var ticksX = [25, 30, 35, 40, 45, 50, 55, 60];
var ticksY = [0, 5, 10, 15, 20, 25];
data.addColumn('number', 'y1');
data.addColumn('number', 'y2');
//red line (vertical)
ticksY.forEach(function (value) {
data.addRow([40, null, null, null, value]);
});
//green line (horizontal)
ticksX.forEach(function (value) {
data.addRow([value, null, null, 10, null]);
});
data.sort([{column: 0}]);
var options = {
interpolateNulls: true,
seriesType: 'scatter',
series: {
1: {
color: 'green',
type: 'line'
},
2: {
color: 'red',
type: 'line'
},
},
colors:['002060'],
vAxis: {
ticks: ticksY
},
hAxis: {
ticks: ticksX
},
};
var chart = new google.visualization.ComboChart(document.getElementById("chartDiv"));
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chartDiv"></div>

Add labels for point in google charts

Does google charts support the ability to add labels to a chart? I need to add labels to the chart, but I don't know how to do it.
I'm using such function for chart draw:
function drawChart(node, rows) {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Index');
data.addRows(rows);
var options = {
titleTextStyle: {
color: '#00FF00',
},
height: 350,
width: $('#' + node).width(),
pointsVisible: true,
colors:['#00FF00'],
backgroundColor: '#1b1b1b',
legend: {position: 'right', textStyle: {color: '#fff', fontSize: 12}},
pointShape: 'square',
annotations: {
textStyle: {
fontName: 'Times-Roman',
fontSize: 18,
bold: true,
italic: true,
color: '#e5d385',
},
stem: {
length: 0
}
},
hAxis: {
title: "Date",
titleTextStyle: {
color: '#fff'
},
format: 'dd.MM.yyyy',
gridlines: {count: 15, color: '#7d7d7d'},
baselineColor: '#fff',
slantedTextAngle: 45,
slantedText: true,
baselineColor: '#fff',
minorGridlines:{
color: "#494949"
},
textStyle:{color: '#FFF'},
ticks: ticksX
},
vAxis: {
title: "Index",
titleTextStyle: {
color: '#fff'
},
gridlines: {color: '#7d7d7d'},
minValue: 0,
baselineColor: '#fff',
minorGridlines:{
color: "#494949"
},
textStyle:{color: '#FFF'},
ticks: ticksY
},
};
var dataView = new google.visualization.DataView(data);
dataView.setColumns([
// reference existing columns by index
0, 1,
// add function for line color
{
calc: function(data, row) {
var colorDown = '#FF0000';
var colorUp = '#00FF00';
if ((row === 0) && (data.getValue(row, 1) < data.getValue(row + 1, 1))) {
return colorDown;
} else if ((row > 0) && (data.getValue(row - 1, 1) < data.getValue(row, 1))) {
return colorDown;
}
return colorUp;
},
type: 'string',
role: 'style',
}
]);
var chart = new google.visualization.LineChart(document.getElementById(node));
chart.draw(dataView, options);
}
I can't find information how to add labels to a chart. All documentation contains information how to add labels to the axes of the chart. I need to add labels above the line chart points.
Can you help me with it?
annotations, or labels, are added using an annotation column role,
similar to the style column role, already being used.
here, I add an annotation column role to the data view,
to display labels for the min & max values...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var rows = [];
var oneDay = (24 * 60 * 60 * 1000);
var currentEndDate = new Date();
var currentStartDate = new Date(currentEndDate.getTime() - (oneDay * 365.25));
for (var i = currentStartDate.getTime(); i <= currentEndDate.getTime(); i = i + oneDay) {
var direction = (i % 2 === 0) ? 1 : -1;
var rowDate = new Date(i);
rows.push([rowDate, rowDate.getMonth() + (rowDate.getDate() * direction)]);
}
drawChart('chart_div', rows);
});
function drawChart(node, rows) {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Index');
data.addRows(rows);
var options = {
titleTextStyle: {
color: '#00FF00',
},
height: 350,
width: $('#' + node).width(),
pointsVisible: true,
colors:['#00FF00'],
backgroundColor: '#1b1b1b',
legend: {position: 'right', textStyle: {color: '#fff', fontSize: 12}},
pointShape: 'square',
annotations: {
textStyle: {
fontName: 'Times-Roman',
fontSize: 18,
bold: true,
italic: true,
color: '#e5d385',
},
stem: {
length: 0
}
},
hAxis: {
title: "Date",
titleTextStyle: {
color: '#fff'
},
format: 'dd.MM.yyyy',
gridlines: {count: 15, color: '#7d7d7d'},
baselineColor: '#fff',
slantedTextAngle: 45,
slantedText: true,
baselineColor: '#fff',
minorGridlines:{
color: "#494949"
},
textStyle:{color: '#FFF'}
},
vAxis: {
title: "Index",
titleTextStyle: {
color: '#fff'
},
gridlines: {color: '#7d7d7d'},
minValue: 0,
baselineColor: '#fff',
minorGridlines:{
color: "#494949"
},
textStyle:{color: '#FFF'}
},
};
var range = data.getColumnRange(1);
var dataView = new google.visualization.DataView(data);
dataView.setColumns([
// reference existing columns by index
0, 1,
// add function for line color
{
calc: function(data, row) {
var colorDown = '#FF0000';
var colorUp = '#00FF00';
if ((row === 0) && (data.getValue(row, 1) < data.getValue(row + 1, 1))) {
return colorDown;
} else if ((row > 0) && (data.getValue(row - 1, 1) < data.getValue(row, 1))) {
return colorDown;
}
return colorUp;
},
type: 'string',
role: 'style',
},
// add annotation
{
calc: function(data, row) {
var value = data.getValue(row, 1);
if (value === range.min) {
return 'Min: ' + data.getFormattedValue(row, 1);
} else if (value === range.max) {
return 'Max: ' + data.getFormattedValue(row, 1);
}
return null;
},
type: 'string',
role: 'annotation',
}
]);
var chart = new google.visualization.LineChart(document.getElementById(node));
chart.draw(dataView, options);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src='https://www.gstatic.com/charts/loader.js'></script>
<div id="chart_div"></div>

Google Charts API Area Chart display only max and min values in annotation

I'm using a Google Charts API Area Chart to display a simple Google Spreadsheet: Column 0 stores dates and Column 1 values. Actually the chart is displaying all values in annotation by default. But I only want to display the min and max value of column 1 in annotation.
I can't find the solution for my problem and maybe you can help me with my sourcecode.
Thanks Mags
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["corechart"]});
function initialize() {
var opts = {sendMethod: 'auto'};
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/MYSPREADSHEET', opts);
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
type: 'string',
role: 'annotation',
sourceColumn: 1,
calc: 'stringify'
}]);
var options = {
title: '',
curveType: 'function',
legend: {position: 'none'},
lineWidth: 4,
backgroundColor: '#2E4151',
colors:['white'],
fontSize: '26',
fontName: 'Open Sans',
animation:{
"startup": true,
duration: 800,
easing: 'inAndOut',
},
hAxis: {
gridlines: {color: 'transparent', count: 4},
textStyle: {color: '#FFF'}
},
vAxis: {
gridlines: {color: 'white', count: 5},
viewWindow: {min: 87, max: 101},
textStyle: {
color: '#FFF',
fontSize: 18
},
},
trendlines: {
0: {
type: 'polynomial',
color: 'yellow',
lineWidth: 5,
opacity: 0.7,
showR2: true,
visibleInLegend: true
}
}
};
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
chart.draw(view, options);
}
google.setOnLoadCallback(initialize);
</script>
</head>
<body>
<div id="chart_div" style="width:100%; height:100%"></div>
</body>
</html>
you can use data table method --> getColumnRange(columnIndex)
this will return an object with the min & max values of the column.
then you can use the calc function on the data view,
to determine if the value matches either the min or max,
and return the formatted value for the annotation.
return null if it does not, see following snippet...
var data = response.getDataTable();
var range = data.getColumnRange(1);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
type: 'string',
role: 'annotation',
sourceColumn: 1,
calc: function (dt, row) {
var value = dt.getValue(row, 1);
if ((value === range.min) || (value === range.max)) {
return dt.getFormattedValue(row, 1);
}
return null;
}
}]);

Highmaps mappies with drilldown

I need to do a drilldown of mappies, from country to states:
https://www.highcharts.com/maps/demo/map-pies
Actually I am using a custom map from Peru, but already with the example of USA would help me a lot showing me some solution.
Is it possible to do this?
I've made an example with mappie and drilldown to show you how to start and achieve it. I've added drilldown for California so only this state will work.
Add drilldown module: https://code.highcharts.com/maps/modules/drilldown.js
Each point should have a drilldown property set. You can add it to a point object or to data array (then keys array in series should point to it. API: https://api.highcharts.com/highmaps/plotOptions.series.keys)
When drilldown event occurs hide or remove each mappie series and create it again on drillup event.
Code:
// New map-pie series type that also allows lat/lon as center option.
// Also adds a sizeFormatter option to the series, to allow dynamic sizing
// of the pies.
Highcharts.seriesType('mappie', 'pie', {
center: null, // Can't be array by default anymore
clip: true, // For map navigation
states: {
hover: {
halo: {
size: 5
}
}
},
dataLabels: {
enabled: false
}
}, {
getCenter: function() {
var options = this.options,
chart = this.chart,
slicingRoom = 2 * (options.slicedOffset || 0);
if (!options.center) {
options.center = [null, null]; // Do the default here instead
}
// Handle lat/lon support
if (options.center.lat !== undefined) {
var point = chart.fromLatLonToPoint(options.center);
options.center = [
chart.xAxis[0].toPixels(point.x, true),
chart.yAxis[0].toPixels(point.y, true)
];
}
// Handle dynamic size
if (options.sizeFormatter) {
options.size = options.sizeFormatter.call(this);
}
// Call parent function
var result = Highcharts.seriesTypes.pie.prototype.getCenter.call(this);
// Must correct for slicing room to get exact pixel pos
result[0] -= slicingRoom;
result[1] -= slicingRoom;
return result;
},
translate: function(p) {
this.options.center = this.userOptions.center;
this.center = this.getCenter();
return Highcharts.seriesTypes.pie.prototype.translate.call(this, p);
}
});
var data = [
// state, demVotes, repVotes, libVotes, grnVotes, sumVotes, winner, offset config for pies
['Alabama', 729547, 1318255, 44467, 9391, 2101660, -1],
['Alaska', 116454, 163387, 18725, 5735, 304301, -1],
['Arizona', 1161167, 1252401, 106327, 34345, 2554240, -1],
['Arkansas', 380494, 684782, 29829, 9473, 1104578, -1],
['California', 8577206, 4390272, 467370, 271047, 13705895, 1, {
lon: -1,
drawConnector: false
}, 'us-ca'],
['Colorado', 1338870, 1202484, 144121, 38437, 2723912, 1],
['Connecticut', 897572, 673215, 48676, 22841, 1642304, 1, {
lat: -1.5,
lon: 1
}],
['Delaware', 235603, 185127, 14757, 6103, 441590, 1, {
lat: -1.3,
lon: 2
}],
['District of Columbia', 282830, 12723, 4906, 4258, 304717, 1, {
lat: -2,
lon: 2
}],
['Florida', 4504975, 4617886, 207043, 64399, 9394303, -1],
['Georgia', 1877963, 2089104, 125306, 0, 4092373, -1],
['Hawaii', 266891, 128847, 15954, 12737, 424429, 1, {
lat: -0.5,
lon: 0.5,
drawConnector: false
}],
['Idaho', 189765, 409055, 28331, 8496, 635647, -1],
['Illinois', 2977498, 2118179, 208682, 74112, 5378471, 1],
['Indiana', 1039126, 1557286, 133993, 7841, 2738246, -1],
['Iowa', 653669, 800983, 59186, 11479, 1525317, -1],
['Kansas', 427005, 671018, 55406, 23506, 1176935, -1],
['Kentucky', 628854, 1202971, 53752, 13913, 1899490, -1],
['Louisiana', 780154, 1178638, 37978, 14031, 2010801, -1],
['Maine', 352156, 332418, 37578, 13995, 736147, 1],
['Maryland', 1502820, 878615, 78225, 33380, 2493040, 1, {
lon: 0.6,
drawConnector: false
}],
['Massachusetts', 1995196, 1090893, 138018, 47661, 3271768, 1, {
lon: 3
}],
['Michigan', 2268839, 2279543, 172136, 51463, 4771981, -1],
['Minnesota', 1367716, 1322951, 112972, 36985, 2840624, 1, {
lon: -1,
drawConnector: false
}],
['Mississippi', 462127, 678284, 14411, 3595, 1158417, -1],
['Missouri', 1054889, 1585753, 96404, 25086, 2762132, -1],
['Montana', 174281, 273879, 28036, 7868, 484064, -1],
['Nebraska', 273185, 485372, 38746, 8337, 805640, -1],
['Nevada', 539260, 512058, 37384, 0, 1088702, 1],
['New Hampshire', 348526, 345790, 30694, 6465, 731475, 1],
['New Jersey', 1967444, 1509688, 72143, 37131, 3586406, 1, {
lat: -1,
lon: 1.2
}],
['New Mexico', 380923, 316134, 74544, 9797, 781398, 1],
['New York', 4145376, 2638135, 162273, 100110, 7045894, 1],
['North Carolina', 2169496, 2345235, 130021, 1038, 4645790, -1],
['North Dakota', 93758, 216794, 21434, 378, 332364, -1],
['Ohio', 2320596, 2776683, 174266, 44310, 5315855, -1],
['Oklahoma', 420375, 949136, 83481, 0, 1452992, -1],
['Oregon', 991580, 774080, 93875, 49247, 1908782, 1],
['Pennsylvania', 2874136, 2945302, 144826, 49334, 6013598, -1],
['Rhode Island', 227062, 166454, 14700, 6171, 414387, 1, {
lat: -0.7,
lon: 1.7
}],
['South Carolina', 855373, 1155389, 49204, 13034, 2073000, -1],
['South Dakota', 117442, 227701, 20845, 0, 365988, -1],
['Tennessee', 868853, 1519926, 70286, 15952, 2475017, -1],
['Texas', 3877868, 4685047, 283492, 71558, 8917965, -1],
['Utah', 222858, 375006, 39608, 7695, 645167, -1],
['Vermont', 178573, 95369, 10078, 6758, 290778, 1, {
lat: 2
}],
['Virginia', 1981473, 1769443, 118274, 27638, 3896828, 1],
['Washington', 1727840, 1210370, 160356, 57571, 3156137, 1],
['West Virginia', 187519, 486304, 22958, 8016, 704797, -1],
['Wisconsin', 1382947, 1407028, 106470, 31016, 2927461, -1],
['Wyoming', 55973, 174419, 13287, 2515, 246194, -1]
],
maxVotes = 0,
demColor = 'rgba(74,131,240,0.80)',
repColor = 'rgba(220,71,71,0.80)',
libColor = 'rgba(240,190,50,0.80)',
grnColor = 'rgba(90,200,90,0.80)';
// Compute max votes to find relative sizes of bubbles
Highcharts.each(data, function(row) {
maxVotes = Math.max(maxVotes, row[5]);
});
// Build the chart
var chart = Highcharts.mapChart('container', {
chart: {
animation: false, // Disable animation, especially for zooming
events: {
load: function() {
addMapPie(this);
},
drilldown: function(e) {
if (!e.seriesOptions) {
var chart = this,
mapKey = 'countries/us/' + e.point.drilldown + '-all',
// Handle error, the timeout is cleared on success
fail = setTimeout(function() {
if (!Highcharts.maps[mapKey]) {
chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
fail = setTimeout(function() {
chart.hideLoading();
}, 1000);
}
}, 3000);
// Show the spinner
chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
// Load the drilldown map
$.getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', function() {
data = Highcharts.geojson(Highcharts.maps[mapKey]);
// Set a non-random bogus value
$.each(data, function(i) {
this.value = i;
});
chart.series.forEach(function(s) {
if (s.options.type === 'mappie') {
s.hide();
}
});
// Hide loading and add series
chart.hideLoading();
clearTimeout(fail);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
});
}
this.setTitle(null, {
text: e.point.name
});
},
drillup: function() {
this.setTitle(null, {
text: ''
});
this.series.forEach(function(s) {
if (s.options.type === 'mappie') {
s.show();
}
});
}
}
},
title: {
text: 'USA 2016 Presidential Election Results'
},
colorAxis: {
dataClasses: [{
from: -1,
to: 0,
color: 'rgba(244,91,91,0.5)',
name: 'Republican'
}, {
from: 0,
to: 1,
color: 'rgba(124,181,236,0.5)',
name: 'Democrat'
}, {
from: 2,
to: 3,
name: 'Libertarian',
color: libColor
}, {
from: 3,
to: 4,
name: 'Green',
color: grnColor
}]
},
mapNavigation: {
enabled: true
},
// Limit zoom range
yAxis: {
minRange: 2300
},
tooltip: {
useHTML: true
},
// Default options for the pies
plotOptions: {
mappie: {
borderColor: 'rgba(255,255,255,0.4)',
borderWidth: 1,
tooltip: {
headerFormat: ''
}
}
},
series: [{
mapData: Highcharts.maps['countries/us/us-all'],
data: data,
name: 'States',
borderColor: '#FFF',
showInLegend: false,
joinBy: ['name', 'id'],
keys: ['id', 'demVotes', 'repVotes', 'libVotes', 'grnVotes',
'sumVotes', 'value', 'pieOffset', 'drilldown'
],
tooltip: {
headerFormat: '',
pointFormatter: function() {
var hoverVotes = this.hoverVotes; // Used by pie only
return '<b>' + this.id + ' votes</b><br/>' +
Highcharts.map([
['Democrats', this.demVotes, demColor],
['Republicans', this.repVotes, repColor],
['Libertarians', this.libVotes, libColor],
['Green', this.grnVotes, grnColor]
].sort(function(a, b) {
return b[1] - a[1]; // Sort tooltip by most votes
}), function(line) {
return '<span style="color:' + line[2] +
// Colorized bullet
'">\u25CF</span> ' +
// Party and votes
(line[0] === hoverVotes ? '<b>' : '') +
line[0] + ': ' +
Highcharts.numberFormat(line[1], 0) +
(line[0] === hoverVotes ? '</b>' : '') +
'<br/>';
}).join('') +
'<hr/>Total: ' + Highcharts.numberFormat(this.sumVotes, 0);
}
}
}, {
name: 'Separators',
type: 'mapline',
data: Highcharts.geojson(Highcharts.maps['countries/us/us-all'], 'mapline'),
color: '#707070',
showInLegend: false,
enableMouseTracking: false
}, {
name: 'Connectors',
type: 'mapline',
color: 'rgba(130, 130, 130, 0.5)',
zIndex: 5,
showInLegend: false,
enableMouseTracking: false
}],
drilldown: {
activeDataLabelStyle: {
color: '#FFFFFF',
textDecoration: 'none',
textOutline: '1px #000000'
},
drillUpButton: {
relativeTo: 'spacingBox',
position: {
x: 0,
y: 60
}
}
}
});
function addMapPie(chart) {
// Add the pies after chart load, optionally with offset and connectors
Highcharts.each(chart.series[0].points, function(state) {
if (!state.id) {
return; // Skip points with no data, if any
}
var pieOffset = state.pieOffset || {},
centerLat = parseFloat(state.properties.latitude),
centerLon = parseFloat(state.properties.longitude);
// Add the pie for this state
chart.addSeries({
type: 'mappie',
name: state.id,
zIndex: 6, // Keep pies above connector lines
sizeFormatter: function() {
var yAxis = this.chart.yAxis[0],
zoomFactor = (yAxis.dataMax - yAxis.dataMin) /
(yAxis.max - yAxis.min);
return Math.max(
this.chart.chartWidth / 45 * zoomFactor, // Min size
this.chart.chartWidth / 11 * zoomFactor * state.sumVotes / maxVotes
);
},
tooltip: {
// Use the state tooltip for the pies as well
pointFormatter: function() {
return state.series.tooltipOptions.pointFormatter.call({
id: state.id,
hoverVotes: this.name,
demVotes: state.demVotes,
repVotes: state.repVotes,
libVotes: state.libVotes,
grnVotes: state.grnVotes,
sumVotes: state.sumVotes
});
}
},
data: [{
name: 'Democrats',
y: state.demVotes,
color: demColor
}, {
name: 'Republicans',
y: state.repVotes,
color: repColor
}, {
name: 'Libertarians',
y: state.libVotes,
color: libColor
}, {
name: 'Green',
y: state.grnVotes,
color: grnColor
}],
center: {
lat: centerLat + (pieOffset.lat || 0),
lon: centerLon + (pieOffset.lon || 0)
}
}, false);
// Draw connector to state center if the pie has been offset
if (pieOffset.drawConnector !== false) {
var centerPoint = chart.fromLatLonToPoint({
lat: centerLat,
lon: centerLon
}),
offsetPoint = chart.fromLatLonToPoint({
lat: centerLat + (pieOffset.lat || 0),
lon: centerLon + (pieOffset.lon || 0)
});
chart.series[2].addPoint({
name: state.id,
path: 'M' + offsetPoint.x + ' ' + offsetPoint.y +
'L' + centerPoint.x + ' ' + centerPoint.y
}, false);
}
});
// Only redraw once all pies and connectors have been added
chart.redraw();
}
#container {
min-width: 320px;
max-width: 800px;
height: 500px;
margin: 1em auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.15/proj4.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/maps/modules/map.js"></script>
<script src="https://code.highcharts.com/maps/modules/data.js"></script>
<script src="https://code.highcharts.com/maps/modules/drilldown.js"></script>
<script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
<script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
<script src="https://code.highcharts.com/mapdata/countries/us/us-all.js"></script>
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<div id="container"></div>
Demo:
https://jsfiddle.net/BlackLabel/1d845opk/1/
EDIT
To add mappies also to the first level of drilldown you have to remove mappies series form the main view of the map when drilldown event occurs and create new ones for drilled data. It's quite difficult to explain exactly how to make it, so I prepared an example where each drilled level has sample data (you can get them from a server the same as drilled map data). I hope this example will help and you will see what's going on there.
Demo:
http://jsfiddle.net/BlackLabel/zLcnby79/
Thank you Wojciech Chmiel !
I did my map with the help of your post.
// New map-pie series type that also allows lat/lon as center option.
// Also adds a sizeFormatter option to the series, to allow dynamic sizing
// of the pies.
Highcharts.seriesType('mappie', 'pie', {
center: null, // Can't be array by default anymore
clip: true, // For map navigation
states: {
hover: {
halo: {
size: 5
}
}
},
dataLabels: {
enabled: false
}
}, {
getCenter: function() {
var options = this.options,
chart = this.chart,
slicingRoom = 2 * (options.slicedOffset || 0);
if (!options.center) {
options.center = [null, null]; // Do the default here instead
}
// Replace lat/lon with plotX/plotY
if (options.center.plotX !== undefined) {
options.center = [options.center.plotX, options.center.plotY];
}
// Handle dynamic size
if (options.sizeFormatter) {
options.size = options.sizeFormatter.call(this);
}
// Call parent function
var result = Highcharts.seriesTypes.pie.prototype.getCenter.call(this);
// Must correct for slicing room to get exact pixel pos
result[0] -= slicingRoom;
result[1] -= slicingRoom;
return result;
},
translate: function (p) {
this.options.center = this.userOptions.center;
this.center = this.getCenter();
return Highcharts.seriesTypes.pie.prototype.translate.call(this, p);
}
});
var data = [
// state, demVotes, repVotes, libVotes, grnVotes, sumVotes, winner, drilldown
['CAPLINA-OCONA', 729547, 1318255, 44467, 9391, 2101660, -1, 'aaa01'],
['CHAPARRA-CHINCHA', 116454, 163387, 18725, 5735, 304301, -1, 'aaa02'],
['CANETE-FORTALEZA', 1161167, 1252401, 106327, 34345, 2554240, -1, 'aaa03'],
['HUARMEY-CHICAMA', 380494, 684782, 29829, 9473, 1104578, -1, 'aaa04'],
['JEQUETEPEQUE-ZARUMILLA', 8577206, 4390272, 467370, 271047, 13705895, 1, 'aaa05'],
['MARANON', 1338870, 1202484, 144121, 38437, 2723912, 1, 'aaa06'],
['AMAZONAS', 897572, 673215, 48676, 22841, 1642304, 1, 'aaa07'],
['HUALLAGA', 235603, 185127, 14757, 6103, 441590, 1, 'aaa08'],
['UCAYALI', 282830, 12723, 4906, 4258, 304717, 1, 'aaa09'],
['MANTARO', 4504975, 4617886, 207043, 64399, 9394303, -1, 'aaa10'],
['PAMPAS-APURIMAC', 1877963, 2089104, 125306, 0, 4092373, -1, 'aaa11'],
['URUBAMBA-VILCANOTA', 266891, 128847, 15954, 12737, 424429, 1, 'aaa12'],
['MADRE DE DIOS', 189765, 409055, 28331, 8496, 635647, -1, 'aaa13'],
['TITICACA', 2977498, 2118179, 208682, 74112, 5378471, 1, 'aaa14']
],
maxVotes = 0,
demColor = 'rgba(74,131,240,0.80)',
repColor = 'rgba(220,71,71,0.80)',
libColor = 'rgba(240,190,50,0.80)',
grnColor = 'rgba(90,200,90,0.80)';
// Compute max votes to find relative sizes of bubbles
Highcharts.each(data, function(row) {
maxVotes = Math.max(maxVotes, row[5]);
});
// Build the chart
var chart = Highcharts.mapChart('container', {
chart: {
animation: false, // Disable animation, especially for zooming
events: {
load: function() {
addMapPie(this);
},
drilldown: function(e) {
if (!e.seriesOptions) {
var chart = this,
//mapKey = 'countries/us/' + e.point.drilldown + '-all',
mapKey = 'paises/pe/' + e.point.drilldown,
ruta = e.point.drilldown,
// Handle error, the timeout is cleared on success
fail = setTimeout(function() {
if (!Highcharts.maps[mapKey]) {
chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
fail = setTimeout(function() {
chart.hideLoading();
}, 1000);
}
}, 3000);
// Show the spinner
chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
// Load the drilldown map
//$.getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', function() {
//$.getScript('http://test1.ana.gob.pe/prueba-mappies/' + ruta + '.js', function () {
$.getScript('https://aplicaciones01.ana.gob.pe/mappies/' + ruta + '.js', function () {
data = Highcharts.geojson(Highcharts.maps[mapKey]);
// Set a non-random bogus value
$.each(data, function(i) {
this.value = i;
});
chart.series.forEach(function(s) {
if (s.options.type === 'mappie') {
s.hide();
}
});
// Hide loading and add series
chart.hideLoading();
clearTimeout(fail);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
});
}
this.setTitle(null, {
text: e.point.name
});
},
drillup: function() {
this.setTitle(null, {
text: ''
});
this.series.forEach(function(s) {
if (s.options.type === 'mappie') {
s.show();
}
});
}
}
},
title: {
text: 'Resultados'
},
colorAxis: {
dataClasses: [{
from: -1,
to: 0,
color: 'rgba(244,91,91,0.5)',
name: 'Republican'
}, {
from: 0,
to: 1,
color: 'rgba(124,181,236,0.5)',
name: 'Democrat'
}, {
from: 2,
to: 3,
name: 'Libertarian',
color: libColor
}, {
from: 3,
to: 4,
name: 'Green',
color: grnColor
}]
},
mapNavigation: {
enabled: true //Para el zoom (+ -)
},
// Limit zoom range
yAxis: {
minRange: 2300
},
tooltip: {
useHTML: true
},
// Default options for the pies
plotOptions: {
mappie: {
borderColor: 'rgba(255,255,255,0.4)',
borderWidth: 1,
tooltip: {
headerFormat: ''
}
}
},
series: [{
mapData: Highcharts.maps['paises/pe/aaa-all'],
data: data,
name: 'States',
borderColor: '#FFF',
showInLegend: false,
joinBy: ['name', 'id'],
//keys: ['id', 'demVotes', 'repVotes', 'libVotes', 'grnVotes',
// 'sumVotes', 'value', 'pieOffset'],
keys: ['id', 'demVotes', 'repVotes', 'libVotes', 'grnVotes', 'sumVotes', 'value', 'drilldown'],
tooltip: {
headerFormat: '',
pointFormatter: function () {
var hoverVotes = this.hoverVotes; // Used by pie only
return '<b>' + this.id + ' votes</b><br/>' +
Highcharts.map([
['Democrats', this.demVotes, demColor],
['Republicans', this.repVotes, repColor],
['Libertarians', this.libVotes, libColor],
['Green', this.grnVotes, grnColor]
].sort(function (a, b) {
return b[1] - a[1]; // Sort tooltip by most votes
}), function (line) {
return '<span style="color:' + line[2] +
// Colorized bullet
'">\u25CF</span> ' +
// Party and votes
(line[0] === hoverVotes ? '<b>' : '') +
line[0] + ': ' +
Highcharts.numberFormat(line[1], 0) +
(line[0] === hoverVotes ? '</b>' : '') +
'<br/>';
}).join('') +
'<hr/>Total: ' + Highcharts.numberFormat(this.sumVotes, 0);
}
}
}],
drilldown: {
activeDataLabelStyle: {
color: '#FFFFFF',
textDecoration: 'none',
textOutline: '1px #000000'
},
drillUpButton: {
relativeTo: 'spacingBox',
position: {
x: 0,
y: 60
}
}
}
});
function addMapPie(chart) {
// Add the pies after chart load, optionally with offset and connectors
Highcharts.each(chart.series[0].points, function(state) {
//if (!state.id) {
if (!state.id || !state.properties) {
return; // Skip points with no data, if any
}
var pieOffset = state.pieOffset || {},
centerLat = parseFloat(state.properties.latitude),
centerLon = parseFloat(state.properties.longitude);
// Add the pie for this state
chart.addSeries({
type: 'mappie',
name: state.id,
zIndex: 6, // Keep pies above connector lines
sizeFormatter: function () {
var yAxis = this.chart.yAxis[0],
zoomFactor = (yAxis.dataMax - yAxis.dataMin) /
(yAxis.max - yAxis.min);
return Math.max(
this.chart.chartWidth / 45 * zoomFactor, // Min size
this.chart.chartWidth / 11 * zoomFactor * state.sumVotes / maxVotes
);
},
/*****/
tooltip: {
// Use the state tooltip for the pies as well
pointFormatter: function () {
return state.series.tooltipOptions.pointFormatter.call({
id: state.id,
hoverVotes: this.name,
demVotes: state.demVotes,
repVotes: state.repVotes,
libVotes: state.libVotes,
grnVotes: state.grnVotes,
sumVotes: state.sumVotes
});
}
},
data: [{
name: 'Democrats',
y: state.demVotes,
color: demColor
}, {
name: 'Republicans',
y: state.repVotes,
color: repColor
}, {
name: 'Libertarians',
y: state.libVotes,
color: libColor
}, {
name: 'Green',
y: state.grnVotes,
color: grnColor
}],
center: {
/*lat: centerLat + (pieOffset.lat || 0),
lon: centerLon + (pieOffset.lon || 0)*/
plotX: state.plotX,
plotY: state.plotY
}
}, false);
});
// Only redraw once all pies and connectors have been added
chart.redraw();
}
#container {
min-width: 320px;
max-width: 800px;
height: 500px;
margin: 1em auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.15/proj4.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/maps/modules/map.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
<script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
<script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
<script src="https://aplicaciones01.ana.gob.pe/mappies/AAA_psad56_simp.js"></script>
<link href="https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<div id="container"></div>
Here:
- https://jsfiddle.net/JMarcia/w06k5zog/17/

Google Charts: Remove default Sort for x-axis

Is there a way to remove the default sort for the x-axis? It automatically sorts from A-Z but I want to have it as January - December.
Chart Image :
For the missing months for each year and product type, I've auto generated them in PHP(where my final code is). So it would look like:
["January",0,"Apitong","2018","Analog"],["January",0,"Apitong","2018","Digital"],["January",0,"Apitong","2018","Internet"],["February",0,"Apitong","2018","Analog"],["February",0,"Apitong","2018","Digital"], .. etc
My Sample Code: JSFiddle
google.charts.load('current', {
callback: function() {
var data = google.visualization.arrayToDataTable([
['Month', 'Amount', 'Area', 'Year', 'Product Type'],
['January', 3300, 'Apitong', 2015, 'Analog'],
['February', 1000, 'Apitong', 2015, 'Analog'],
['March', 2000, 'Apitong', 2015, 'Analog'],
]);
google.visualization.events.addListener(product, 'ready', drawChart);
function drawChart() {
var areaData = new google.visualization.DataView(area.getDataTable());
var filters = [{
column: 2,
value: area.getState().selectedValues[0]
}
];
// group by 'Group' / 'Year'
var dataGroup = google.visualization.data.group(
areaData, [0, 3], [{
column: 1,
aggregation: google.visualization.data.sum,
type: 'number',
label: 'Sum'
}, {
column: 1,
aggregation: google.visualization.data.count,
type: 'number',
label: 'Count'
}]
);
dataGroup.sort([{
column: 0
}, {
column: 1
}]);
var ColumnChart = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'productssold_chart_div',
'dataTable': view
});
ColumnChart.draw();
}
},
packages: ['controls', 'corechart']
});
when using a Discrete axis ('string' values),
the axis will sort by the order of the rows in the data table
in this case, the rows are set to alphabetical as a result of using static method --> data.group
to correct this issue, an array of month names is used to build a custom sort order
a new column is added to finalData and the index from the array is used as the order
// build final data table
var monthOrder = [
'January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December'
];
var finalData = new google.visualization.DataTable({
cols: [{
label: 'Group',
type: 'string'
}, {
label: 'Amount',
type: 'number'
}, {
label: 'Count',
type: 'number'
}, {
label: 'Sort',
type: 'number'
}]
});
// add row for each month AMOUNT | COUNT
var rowMonth = null;
var rowIndex = null;
for (var i = 0; i < dataGroup.getNumberOfRows(); i++) {
if (rowMonth !== dataGroup.getValue(i, 0)) {
rowMonth = dataGroup.getValue(i, 0);
rowIndex = finalData.addRow();
finalData.setValue(rowIndex, 0, rowMonth);
}
for (var x = 1; x < finalData.getNumberOfColumns(); x++) {
switch (finalData.getColumnLabel(x)) {
case 'Amount':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 2).toString());
break;
case 'Count':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 3).toString());
break;
case 'Sort':
finalData.setValue(rowIndex, x, monthOrder.indexOf(rowMonth));
break;
}
}
}
finalData.sort([{column: 3}]);
see following working snippet...
google.charts.load('current', {
callback: function() {
var data = google.visualization.arrayToDataTable([
['Month', 'Amount', 'Area', 'Year', 'Product Type'],
['February', 1000, 'Apitong', 2015, 'Analog'],
['February', 1700, 'Apitong', 2015, 'Internet'],
['February', 1200, 'Avenida Veteranos', 2015, 'Digital'],
['February', 2800, 'Brgy. Baras', 2015, 'Internet'],
['February', 2150, 'Avenida Veteranos', 2018, 'Digital'],
['February', 2700, 'Apitong', 2018, 'Internet'],
['February', 2500, 'Brgy. Baras', 2018, 'Internet'],
['March', 2000, 'Apitong', 2015, 'Digital'],
['March', 2400, 'Avenida Veteranos', 2015, 'Digital'],
['March', 1600, 'Brgy. Baras', 2015, 'Internet'],
['March', 3000, 'Avenida Veteranos', 2018, 'Analog'],
['March', 1400, 'Apitong', 2018, 'Digital'],
['January', 3300, 'Avenida Veteranos', 2015, 'Analog'],
['March', 2000, 'Brgy. Baras', 2018, 'Analog'],
['January', 2600, 'Brgy. Baras', 2015, 'Internet'],
['January', 1800, 'Apitong', 2015, 'Digital'],
['January', 2100, 'Brgy. Baras', 2015, 'Analog']
]);
var area = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_area_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Area',
'ui': {
'allowTyping': false,
'allowMultiple': false,
'allowNone': false,
'sortValues': false,
'label': 'Choose Area',
}
}
});
var year = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_year_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Year',
'ui': {
'allowTyping': false,
'allowMultiple': false,
'allowNone': false,
'sortValues': false,
'label': 'Choose Year',
}
}
});
var product = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_product_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Product Type',
'ui': {
'allowTyping': false,
'allowMultiple': true,
'allowNone': true,
'sortValues': false,
'label': 'Choose Product',
}
}
});
google.visualization.events.addListener(area, 'ready', drawChart);
google.visualization.events.addListener(area, 'statechange', drawChart);
google.visualization.events.addListener(year, 'ready', drawChart);
google.visualization.events.addListener(year, 'statechange', drawChart);
google.visualization.events.addListener(product, 'ready', drawChart);
google.visualization.events.addListener(product, 'statechange', drawChart);
function drawChart() {
var areaData = new google.visualization.DataView(area.getDataTable());
var filters = [{
column: 2,
value: area.getState().selectedValues[0]
}
];
var selectedYear = year.getState().selectedValues;
if (typeof selectedYear !== 'undefined' && selectedYear.length > 0) {
filters.push({
column: 3,
test: function(value, row, column, table) {
return (selectedYear.indexOf(table.getValue(row, column)) > -1);
}
});
}
var selectedProducts = product.getState().selectedValues;
if (typeof selectedProducts !== 'undefined' && selectedProducts.length > 0) {
filters.push({
column: 4,
test: function(value, row, column, table) {
return (selectedProducts.indexOf(table.getValue(row, column)) > -1);
}
});
}
areaData.setRows(areaData.getFilteredRows(filters));
// group by 'Group' / 'Year'
var dataGroup = google.visualization.data.group(
areaData, [0, 3], [{
column: 1,
aggregation: google.visualization.data.sum,
type: 'number',
label: 'Sum'
}, {
column: 1,
aggregation: google.visualization.data.count,
type: 'number',
label: 'Count'
}]
);
dataGroup.sort([{
column: 0
}, {
column: 1
}]);
// build final data table
var monthOrder = [
'January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December'
];
var finalData = new google.visualization.DataTable({
cols: [{
label: 'Group',
type: 'string'
}, {
label: 'Amount',
type: 'number'
}, {
label: 'Count',
type: 'number'
}, {
label: 'Sort',
type: 'number'
}]
});
// add row for each month AMOUNT | COUNT
var rowMonth = null;
var rowIndex = null;
for (var i = 0; i < dataGroup.getNumberOfRows(); i++) {
if (rowMonth !== dataGroup.getValue(i, 0)) {
rowMonth = dataGroup.getValue(i, 0);
rowIndex = finalData.addRow();
finalData.setValue(rowIndex, 0, rowMonth);
}
for (var x = 1; x < finalData.getNumberOfColumns(); x++) {
switch (finalData.getColumnLabel(x)) {
case 'Amount':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 2).toString());
break;
case 'Count':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 3).toString());
break;
case 'Sort':
finalData.setValue(rowIndex, x, monthOrder.indexOf(rowMonth));
break;
}
}
}
finalData.sort([{column: 3}]);
var view = new google.visualization.DataView(finalData);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}, 2, {
calc: 'stringify',
sourceColumn: 2,
type: 'string',
role: 'annotation'
}]);
var ColumnChart = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'productssold_chart_div',
'dataTable': view
});
ColumnChart.draw();
}
area.draw();
year.draw();
product.draw();
},
packages: ['controls', 'corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="filter_productssold_area_div"></div>
<div id="filter_productssold_year_div"></div>
<div id="filter_productssold_product_div"></div>
<div id="productssold_chart_div"></div>