How to retain tooltip when pivoting Google Visualization DataTable - javascript

I'm using some great code from #asgallant to pivot a Google DataTable for use in a line chart. His code is here: http://jsfiddle.net/asgallant/HkjDe/
In my original DataTable I have a 4th column however that is a tooltip string. When I pivot the table with his code my tooltip if no longer available. I would like to use the tooltips provided and for the cells that are 'created' use some standard tooltip text. Here is what my version of the initial table setup looks like.
var data = new google.visualization.DataTable();
data.addColumn('number', 'A');
data.addColumn('string', 'B');
data.addColumn('number', 'C');
data.addColumn({type: 'string', role: 'tooltip'});
data.addRows([
[1, 'foo', 6, 't1'],
[2, 'foo', 2, 'hello'],
[3, 'foo', 1, 't2'],
[4, 'foo', 3, 'test'],
[1, 'bar', 7, 't3'],
[2, 'bar', 3, 'again'],
[1, 'baz', 8, 't4'],
[2, 'baz', 4, 'and'],
[2, 'cad', 5, 't5'],
[3, 'cad', 6, 'again'],
[1, 'qud', 9, 'x'],
[5, 'qud', 1, 'z']
]);
Can anyone provide some assistance?
-- UPDATE --
Edited the initial addRows statement to be more representative of my data model.

In order to preserve the tooltips, you need to add tooltip columns to the view and pivot data:
for (var i = 0; i < distinctValues.length; i++) {
viewColumns.push({
type: 'number',
label: distinctValues[i],
calc: (function (x) {
return function (dt, row) {
// return values of C only for the rows where B = distinctValues[i] (passed into the closure via x)
return (dt.getValue(row, 1) == x) ? dt.getValue(row, 2) : null;
}
})(distinctValues[i])
});
groupColumns.push({
column: (i * 2) + 1,
type: 'number',
label: distinctValues[i],
aggregation: google.visualization.data.sum
});
// add columns for the tooltips
viewColumns.push({
type: 'string',
calc: (function (x) {
return function (dt, row) {
// return values of the tooltip column only for the rows where B = distinctValues[i] (passed into the closure via x)
return (dt.getValue(row, 1) == x) ? dt.getValue(row, 3) : null;
}
})(distinctValues[i])
});
groupColumns.push({
column: (i * 2) + 2,
type: 'string',
aggregation: function (values) {
return values.join('');
}
});
}
The group function does not handle column roles properly, so you have to set them afterwards:
// fix the tooltip column roles, since the group function won't create them properly
for (var i = 1; i < pivotedData.getNumberOfColumns(); i++) {
if (pivotedData.getColumnType(i) == 'string') {
pivotedData.setColumnProperty(i, 'role', 'tooltip');
}
}
See example: http://jsfiddle.net/asgallant/HkjDe/23/

Related

Highcharts multiple series combined with linkedTo hover issue

I'm using linkedTo option to link multiple additional graphs (let's call them childs) to one main graph in order to get one group of graphs.
My issue is about hover highlighting. When I hover main graph all childs are highlighted as well as main graph itself. But when I hover any child graph only this one and main are highlighted, and other childs become blurred, that is not what I want.
Highcharts.chart('container', {
series: [{
id: 'main',
color: 'black',
name: 'Main',
type: 'line',
data: [[1, 3], [1.5, 2.5], [2, 2], [2.5, 1.5], [3, 1]]
}, {
linkedTo: 'main',
color: 'black',
name: 'Child 1',
type: 'line',
data: [[2, 3], [3, 2], [4, 1]]
}, {
linkedTo: 'main',
color: 'black',
name: 'Child 2',
type: 'line',
data: [[3, 3], [4, 2], [5, 1]]
}, {
linkedTo: 'main',
color: 'black',
name: 'Child 3',
type: 'line',
data: [[4, 3], [5, 2], [6, 1]]
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container"/>
Is there any workaround for this case?
That issue is reported here: https://github.com/highcharts/highcharts/issues/11810 and marked as an enhancement. Currently, as a workaround you can link sibling series in afterLinkSeries event:
(function(H) {
H.addEvent(H.Chart, 'afterLinkSeries', function(e) {
this.series.forEach(function(s) {
if (s.linkedParent) {
s.linkedParent.linkedSeries.forEach(function(linkedS) {
if (linkedS !== s) {
s.linkedSeries.push(linkedS);
}
});
}
});
});
}(Highcharts));
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4972/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
EDIT:
Due to the problem with legend item click, a better solution is to overwrite Pointer.prototype.applyInactiveState method.
Highcharts.Pointer.prototype.applyInactiveState = function(points) {
var activeSeries = [],
series;
// Get all active series from the hovered points
(points || []).forEach(function(item) {
series = item.series;
// Include itself
activeSeries.push(series);
// Include parent series
if (series.linkedParent) {
activeSeries.push(series.linkedParent);
// CHANGE
series.linkedParent.linkedSeries.forEach(function(linkedS) {
activeSeries.push(linkedS);
});
// END CHANGE
}
// Include all child series
if (series.linkedSeries) {
activeSeries = activeSeries.concat(series.linkedSeries);
}
// Include navigator series
if (series.navigatorSeries) {
activeSeries.push(series.navigatorSeries);
}
});
// Now loop over all series, filtering out active series
this.chart.series.forEach(function(inactiveSeries) {
if (activeSeries.indexOf(inactiveSeries) === -1) {
// Inactive series
inactiveSeries.setState('inactive', true);
} else if (inactiveSeries.options.inactiveOtherPoints) {
// Active series, but other points should be inactivated
inactiveSeries.setAllPointsToState('inactive');
}
});
};
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4974/

Add new column in google DataView dynamically

I'm using google chart datatable getting data from a Json, but I want to add a new column result of divide column 2 by 15000.
Using google.visualization.DataTable()
I'm getting something like this
Colum 1 | Column 2
First row 15.000.000€
Second row 20.000.000€
I want Column 3 like this
Colum 1 | Column 2 | Column 3
First row 15.000.000€ 1.000,00€
Second row 20.000.000€ 1.333,33€
you can use a DataView to add the new column, using a calculated column.
create a data view from the data table
var view = new google.visualization.DataView(data);
then use the setColumns method to change the view columns.
we use the column index of the first two columns,
then use a calculation for the third.
view.setColumns([0, 1, {
calc: function (dt, row) {
return dt.getValue(row, 1) / 15000;
},
label: 'Column 3',
type: 'number'
}]);
see following working snippet...
google.charts.load('current', {
packages: ['table']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Column 1', 'Column 2'],
['First Row', 15000000],
['Second Row', 20000000]
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: function (dt, row) {
return dt.getValue(row, 1) / 15000;
},
label: 'Column 3',
type: 'number'
}]);
var table = new google.visualization.Table(document.getElementById('chart_div'));
table.draw(view);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
to format the number,
use google's number formatter,
and object notation for the value.
var formatNumber = new google.visualization.NumberFormat({
pattern: '#,##0.00',
suffix: '€'
});
to format a data table column, use the format method.
formatNumber.format(data, 1);
to format a single value, use the formatValue method.
var value = dt.getValue(row, 1) / 15000;
return {
v: value,
f: formatNumber.formatValue(value)
};
see following working snippet..
google.charts.load('current', {
packages: ['table']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Column 1', 'Column 2'],
['First Row', 15000000],
['Second Row', 20000000]
]);
var formatNumber = new google.visualization.NumberFormat({
pattern: '#,##0.00',
suffix: '€'
});
formatNumber.format(data, 1);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: function (dt, row) {
var value = dt.getValue(row, 1) / 15000;
return {
v: value,
f: formatNumber.formatValue(value)
};
},
label: 'Column 3',
type: 'number'
}]);
var table = new google.visualization.Table(document.getElementById('chart_div'));
table.draw(view);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Google Column Chart with two columns

How to approach a column chart when having month and year.
My data is in this format
['Group','Count','Month','Year'],
['A',10,'February',2015],
['B',8,'February',2015],
['C',15,'February',2016]
Aim is to create a column chart which has X-axis as Month and Y-axis as Count. Now X-axis should have Count for years grouped by month.
Something like this -
I tried to simply pass the above data to see what I can get, but I get error.
Any way to assign Axis the values based on year grouped by month ?
JsFiddle of Google Chart Example
just need three columns, something like this...
['Month', '2015', '2016'],
['Jan', 10, 15],
['Feb', 12, 18],
['Mar', 14, 21],
['Apr', 16, 24]
then you can use a DataView to add the annotations, via calculated columns...
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}, 2, {
calc: 'stringify',
sourceColumn: 2,
type: 'string',
role: 'annotation'
}]);
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['Month', '2015', '2016'],
['Jan', 10, 15],
['Feb', 12, 18],
['Mar', 14, 21],
['Apr', 16, 24]
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}, 2, {
calc: 'stringify',
sourceColumn: 2,
type: 'string',
role: 'annotation'
}]);
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(view, {});
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
all google charts require a specific DataFormat
meaning, manipulation is required if your data does not already exist in this format
the visualization library does offer some Data Manipulation Methods, such as group()
which could be used to transform the data into the required format
1) group the data by Month and Year
2) create a new DataTable with the Month column
3) add a column for each Year from the grouped table
4) add the rows for each month
see following working snippet, using the data from the question...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['Group', 'Count', 'Month', 'Year'],
['A', 10, 'February', 2015],
['B', 8, 'February', 2015],
['C' , 15, 'February', 2016]
]);
// group by month / year
var dataGroup = google.visualization.data.group(
data,
[2, 3],
[{column: 1, aggregation: google.visualization.data.sum, type: 'number', label: 'Count'}]
);
dataGroup.sort([{column: 0},{column: 1}]);
// build final data table
var yearData = new google.visualization.DataTable({
cols: [
{label: 'Month', type: 'string'}
]
});
// add column for each year
var years = dataGroup.getDistinctValues(1);
for (var i = 0; i < years.length; i++) {
yearData.addColumn(
{label: years[i], type: 'number'}
);
}
// add row for each month
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 = yearData.addRow();
yearData.setValue(rowIndex, 0, rowMonth);
}
for (var x = 1; x < yearData.getNumberOfColumns(); x++) {
if (yearData.getColumnLabel(x) === dataGroup.getValue(i, 1).toString()) {
yearData.setValue(rowIndex, x, dataGroup.getValue(i, 2));
}
}
}
var view = new google.visualization.DataView(yearData);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}, 2, {
calc: 'stringify',
sourceColumn: 2,
type: 'string',
role: 'annotation'
}]);
var container = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(container);
chart.draw(view);
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Programmatically Pivoting the Google Visualization dataTable

I excited with this fiddle and I tried to create the same kind with reference to that fiddle. My modified sample is given in here and i'm trying to create a view as follows.
var distinctValues = data.getDistinctValues(2);
var viewColumns = [1];
var groupColumns = [];
// build column arrays for the view and grouping
for (var i = 0; i < distinctValues.length; i++) {
viewColumns.push({
type: 'number',
label: distinctValues[i],
aggregation: google.visualization.data.count
});
groupColumns.push({
column: i+1,
type: 'number',
//label: distinctValues[i],
aggregation: google.visualization.data.sum
});
}
But my aim is to create a pivot table something like as follows.
['Column1', 'Column2', 100, 200, 300, 400],
['A', 'bar', 0, 1, 1, 0],
['A', 'baz', 0, 0, 1, 0],
['A', 'foo', 3, 1, 0, 0],
['B', 'baz', 0, 1, 0, 0],
['B', 'cad', 1, 0, 1, 1],
['B', 'qud', 1, 1, 1, 2]
How can I proceed?
You have to change a few things in your code. First, the viewColumns needs to contain both columns 0 and 1 to start if you want Column1 and Column2 to both be in the output. Then, you need to adjust the columns you add to the viewColumns: each one needs a calc parameter which calculates the value in the column. In this case, you want to compare the value of the column to distinctValues[i] and return 1 when they match and 0 when they don't. In the aggregation function for groupColumns, use sum instead of count:
var distinctValues = data.getDistinctValues(2);
var viewColumns = [0, 1];
var groupColumns = [];
// build column arrays for the view and grouping
for (var i = 0; i < distinctValues.length; i++) {
viewColumns.push({
type: 'number',
label: distinctValues[i],
calc: (function (x) {
return function (dt, row) {
return (dt.getValue(row, 2) == x) ? 1 : 0;
}
})(distinctValues[i])
});
groupColumns.push({
column: i+2,
type: 'number',
//label: distinctValues[i],
aggregation: google.visualization.data.sum
});
}
Then, in the grouping function, pass columns 0 and 1 in the first array:
var pivotedData = google.visualization.data.group(view, [0, 1], groupColumns);
See these changes working here: http://jsfiddle.net/asgallant/DUn6B/1/

Google charts API scatter chart with legend and other colors

I have this one example:
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart1);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart1() {
var data = new google.visualization.DataTable(
{
cols: [
{id: 'A', label: 'A', type: 'number'},
{id: 'B', label: 'B', type: 'number'},
{id: 'C', label: 'C', type:'tooltip', p:{role:'tooltip'}}
],
rows: [
{c:[{v: 2}, {v: 3}, {v:'Allen'}]},
{c:[{v: 4}, {v: 2}, {v:'Tom'}]},
{c:[{v: 1}, {v: 3}, {v:'Sim'}]}
]
})
var options = {
title: 'Age vs. Weight comparison',
hAxis: {title: 'Age', minValue: 1, maxValue: 5},
vAxis: {title: 'Weight', minValue: 1, maxValue: 5},
legend: ''
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart_scatter_container'));
chart.draw(data, options);
}
http://jsfiddle.net/eAWcC/1/
when i hover once data, tooltip will see me label for this data. That is good.
But I want to see all the values ​​are different color and placed in the legend.
How to do it?
The columns in the datatable of a scatterchart are the ones that are shown in the legend, and are colored differently. In order to display them separately you need to rearrange your data so that each person has their own column.
For instance, replace your data table variable with this:
var data = google.visualization.arrayToDataTable([
['x', 'Allen', 'Tom', 'Sim'],
[1, null, null, 3],
[2, 3, null, null],
[4, null, 2, null],
]);
Doing this will give you the desired output (I believe, check here).
However, the issue with this method is that you end up with a lot of 'null' values in each series (since you just have single points). In order to simplify this process, you could write a loop to go through your data and format it appropriately for the new table. The basic code would be:
Add a column for your X values to a new table
For each row in column 2 (tooltips) create a new column in the new table
For each row in column 1 (Y values) fill diagonally down/right
This would look something like this:
var newTable = new google.visualization.DataTable();
newTable.addColumn('number', 'Age');
for (var i = 0; i < data.getNumberOfRows(); ++i) {
newTable.addColumn('string', data.getValue(i, 2));
newTable.addRow();
}
for (var j = 0; j < data.getNumberOfRows(); ++j) {
newTable.setValue(j, j + 1, data.getValue(j, j + 1));
}
(Above code has been tested but doesn't like the second for() loop for reasons beyond my comprehension).

Categories

Resources