Get the data items of a Google Charts histogram bar or range of the bar - google-visualization

I'm trying to create an interactive histogram chart using Google Chart.
My code for generating the histogram can be found here.
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['pt_network_seg_id','speed'],
['9','32'],
['10','22'],
['13','23'],
['14','18'],
['15','34'],
['17','22'],
['18','30'],
['19','20'],
['20','33'],
['21','26'],
['22','33'],
['23','21'],
['24','19'],
['25','41'],
['26','23'],
['27','16'],
['28','39'],
['29','15'],
['30','25'],
['31','26'],
['32','29'],
['40','31'],
['41','9'],
['42','27'],
['44','25'],
['45','10'],
['46','25'],
['47','24'],
['48','20'],
['49','20'],
['50','25'],
['51','19'],
['52','34'],
['53','19'],
['54','27'],
['56','27'],
['58','10'],
['59','26'],
['60','54'],
['62','54'],
['64','17'],
['68','27'],
['74','43'],
['75','10'],
['76','32'],
['77','47'],
['78','31'],
['80','24'],
['84','20'],
['85','35'],
['86','33'],
['88','25'],
['89','26'],
['91','35'],
['93','25'],
['94','18'],
['95','24'],
['98','34'],
['100','23'],
['101','36'],
['102','18'],
['103','21'],
['105','16'],
['106','26'],
['107','29'],
['109','8'],
['111','16'],
['112','19'],
['113','33'],
['114','20'],
['115','18'],
['116','21'],
['117','14'],
['126','22'],
['127','26'],
['130','24'],
['131','10'],
['133','29'],
['134','26'],
['135','22'],
['136','16'],
['137','14'],
['139','23'],
['140','17'],
['141','18'],
['142','19'],
['143','15'],
['144','25'],
['145','19'],
['146','23'],
['147','18'],
['148','50'],
['150','47'],
['151','13'],
['152','37'],
['153','24'],
['156','22'],
['157','21'],
['158','40'],
['159','34'],
['160','12'],
['161','22'],
['165','18'],
['168','24'],
['169','23'],
['171','20'],
['172','22'],
['173','25'],
['175','30'],
['176','24'],
['177','15'],
['178','25'],
['179','0'],
['181','28'],
['182','21'],
['183','17'],
['184','22'],
['185','40'],
['187','24'],
['188','22'],
['189','21'],
['190','8'],
['191','18'],
['192','23'],
['193','33'],
['194','30'],
['195','32'],
['196','33'],
['197','31'],
['198','34'],
['199','34'],
['200','31'],
['201','31'],
['203','20'],
['204','34'],
['205','32'],
['206','19'],
['210','24'],
['211','32'],
['212','29'],
['213','19'],
['214','20'],
['215','19'],
['216','21'],
['217','24'],
['218','27'],
['219','22'],
['220','20'],
['221','17'],
['222','18'],
['223','34'],
['224','35'],
['229','19'],
['230','22'],
['231','21'],
['232','23'],
['234','27'],
['235','22'],
['236','12'],
['237','17'],
['238','16'],
['239','19'],
['240','33'],
['241','13'],
['242','24'],
['243','25'],
['244','19'],
['245','19'],
['246','17'],
['247','23'],
['248','22'],
['250','12'],
['252','10'],
['253','13'],
['254','17'],
['256','23'],
['257','16'],
['258','20'],
['259','24'],
['260','36'],
['263','15'],
['264','19'],
['266','24'],
['267','14'],
['270','17'],
['271','23'],
['272','14'],
['274','21'],
['277','26'],
['279','18'],
['280','27'],
['281','26'],
['282','19'],
['283','23'],
['284','19'],
['288','49'],
['289','37'],
['290','31'],
['291','50'],
['296','17'],
['297','29'],
['299','17'],
['301','32'],
['302','34'],
['304','17'],
['305','32'],
['306','23'],
['307','34'],
['309','27'],
['314','20'],
['316','39'],
['317','48'],
['318','34'],
['319','46'],
['326','16'],
['329','0'],
['330','17'],
['334','15'],
['338','4'],
['339','14'],
['341','23'],
['346','31'],
['347','27'],
['348','39'],
['349','20'],
['350','18'],
['351','16'],
['352','20'],
['353','20'],
['354','18'],
['355','29'],
['356','22'],
['360','18'],
['362','0'],
['363','27'],
['367','25'],
['368','15'],
['369','23'],
['370','31'],
['371','43'],
['373','13'],
['374','30'],
['375','43'],
['376','27'],
['377','44'],
['379','35'],
['380','23'],
['382','41'],
['383','31'],
['384','28'],
['385','23'],
['386','19'],
['387','22'],
['388','30'],
['389','31'],
['390','3'],
['391','38'],
['393','7'],
['394','34'],
['396','31'],
['397','31'],
['398','24'],
['399','39'],
['400','31'],
['401','31'],
['402','27'],
['403','12'],
['405','7'],
['406','23'],
['408','24'],
['409','35'],
['410','32'],
['411','31'],
['412','33'],
['415','0'],
['416','25'],
['417','17'],
['418','14'],
['420','9'],
['421','16'],
['422','24'],
['423','49'],
['424','31'],
['426','31'],
['427','25'],
['428','33'],
['429','23'],
['430','31'],
['431','29'],
['433','27'],
['434','14'],
['435','22'],
['436','48'],
['437','30'],
['438','17'],
['439','12'],
['442','18'],
['443','32'],
['444','26'],
['445','14'],
['446','17'],
['447','13'],
['450','20'],
['451','25'],
['452','24'],
['454','14'],
['455','19'],
['456','23'],
['457','15'],
['458','20'],
['459','23'],
['460','21'],
['461','30'],
['462','15'],
['463','26'],
['464','16'],
['465','22'],
['466','20'],
['467','28'],
['468','22'],
['469','27'],
['470','15'],
['476','8'],
['478','7'],
['479','14'],
['481','14'],
['482','8'],
['483','17'],
['484','16'],
['485','10'],
['487','10'],
['488','17'],
['492','12'],
['493','18'],
['496','22'],
['497','14'],
['498','19'],
['500','17'],
['501','13'],
['503','9'],
['504','16'],
['505','19'],
['506','19'],
['507','25'],
['508','27'],
['510','15'],
['512','12'],
['514','8'],
['515','18'],
['517','20'],
['518','14'],
['519','19'],
['520','16'],
['522','15'],
['523','18'],
['525','20'],
['526','21'],
['527','21'],
['528','21'],
['529','26'],
['531','21'],
['533','4'],
['535','16'],
['536','0'],
['537','16'],
['538','16'],
['539','19'],
['540','24'],
['541','17'],
['542','12'],
['543','16'],
['545','16'],
['546','15'],
['547','11'],
['549','8'],
['550','13'],
['551','26'],
['552','35'],
['553','20'],
['554','17'],
['556','0'],
['557','13'],
['558','14'],
['559','13'],
['561','13'],
['563','18'],
['564','19'],
['566','10'],
['567','23'],
['568','8'],
['570','49'],
['571','20'],
['572','36'],
['573','27'],
['574','0'],
['575','24'],
['576','13'],
['577','51'],
['578','0'],
['579','16'],
['582','13'],
['583','16'],
['584','17'],
['585','15'],
['586','19'],
['589','13'],
['590','20'],
['591','18'],
['593','21'],
['594','28'],
['595','35'],
['596','20'],
['597','9'],
['598','5'],
['599','12'],
['600','21'],
['601','16'],
['602','7'],
['604','22'],
['605','44'],
['607','40'],
['608','27'],
['609','16'],
['610','17'],
['612','15'],
['613','14'],
['614','39'],
['615','13'],
['618','7'],
['620','13'],
['621','13'],
['623','27'],
['624','13'],
['625','13'],
['628','16'],
['629','15'],
['630','28'],
['631','10'],
['633','18'],
['634','12'],
['636','14'],
['638','35'],
['639','6'],
['640','14'],
['641','14'],
['642','14'],
['643','28'],
['644','29'],
['645','21'],
['649','15'],
['650','21'],
['651','22'],
['652','20'],
['653','24'],
['654','19'],
['655','17'],
['656','15'],
['657','14'],
['659','11'],
['660','12'],
['663','29'],
['664','14'],
['666','6'],
['667','30'],
['669','7'],
['670','9'],
['671','29'],
['672','19'],
['676','19'],
['679','23'],
['680','16'],
['681','19'],
['682','16'],
['683','35'],
['684','17'],
['685','29'],
['687','35'],
['688','21'],
['689','22'],
['691','20'],
['692','19'],
['693','34'],
['694','26'],
['695','21'],
['697','25'],
['698','20'],
['700','24'],
['701','24'],
['702','25'],
['703','24'],
['704','18'],
['706','20'],
['707','15'],
['708','26'],
['711','9'],
['712','30'],
['713','28'],
['714','49'],
['716','23'],
['717','21'],
['718','33'],
['719','22'],
['720','22'],
['722','19'],
['723','47'],
['725','16'],
['726','12'],
['727','23'],
['728','18'],
['730','36'],
['731','17'],
['732','18'],
['733','31'],
['735','31'],
['737','17'],
['738','15'],
['739','18'],
['741','28'],
['742','28'],
['743','26'],
['744','24'],
['745','0'],
['746','25'],
['747','22'],
['748','24'],
['753','26'],
['755','35'],
['756','26'],
['757','36'],
['758','25'],
['759','23'],
['760','23'],
['761','13'],
['762','18'],
['763','22'],
['764','29'],
['765','20'],
['766','25'],
['767','20'],
['769','18'],
['770','21'],
['773','14'],
['774','21'],
['781','38'],
['783','29'],
['784','24'],
['785','31'],
['786','33'],
['790','30'],
['791','13'],
['792','19'],
['793','20'],
['794','20'],
['796','15'],
['797','23'],
['798','20'],
['799','16'],
['801','36'],
['802','40'],
['803','29'],
['805','33'],
['809','27'],
['810','23'],
['811','28'],
['812','22'],
['813','25'],
['815','4'],
['816','19'],
['817','30'],
['818','34'],
['819','20'],
['820','19'],
['821','20'],
['822','14'],
['823','20'],
['824','23'],
['827','14'],
['829','31'],
['830','14'],
['831','32'],
['832','38'],
['834','17'],
['835','32'],
['841','21'],
['845','40'],
['847','14'],
['848','13'],
['849','15'],
['850','10'],
['851','13'],
['852','14'],
['854','23'],
['855','22'],
['857','18'],
['858','16'],
['859','25'],
['860','15'],
['862','15'],
['863','13'],
['864','25'],
['865','22'],
['867','19'],
['868','19'],
['869','20'],
['870','18'],
['872','19'],
['873','7'],
['875','19'],
['876','19'],
['877','13'],
['878','19'],
['879','25'],
['880','26'],
['882','33'],
['883','21'],
['884','36'],
['888','27'],
['889','14'],
['891','22'],
['893','13'],
['894','14'],
['895','21'],
['898','6'],
['900','21'],
['901','31'],
['902','21'],
['903','15'],
['904','11'],
['913','21'],
['915','13'],
['916','14'],
['917','32'],
['918','32'],
['922','28'],
['923','19'],
['924','18'],
['926','26'],
['930','13'],
['931','10'],
['933','19'],
['934','27'],
['935','6'],
['937','4'],
['938','13'],
['940','27'],
['941','16'],
['945','16'],
['946','14'],
['948','0'],
['949','22'],
['952','17'],
['953','21'],
['954','25'],
['955','21'],
['956','21'],
['957','6'],
['958','8'],
['959','24'],
['960','28'],
['961','45'],
['962','23'],
['963','19'],
['964','13'],
['965','14'],
['966','40'],
['967','9'],
['968','22'],
['969','18'],
['970','24'],
['971','18'],
['973','37'],
['974','52'],
['976','17'],
['977','24'],
['978','14'],
['979','28'],
['980','32'],
['982','23'],
['983','24'],
['985','30'],
['986','13'],
['989','19'],
['990','23'],
['992','21'],
['993','22'],
['995','31'],
['996','27'],
['997','24'],
['999','25'],
['1000','27'],
['1002','10'],
['1003','19'],
['1004','29'],
['1005','6'],
['1006','10'],
]);
var options = {
title: 'Distribution of Bus Speeds on Beer Sheva PT Segments 7-10AM',
hAxis: {title: 'Bus Speeds (kph)',
titleTextStyle: {
italic: false
}},
vAxis: {title: 'PT Segments Count',
titleTextStyle: {
italic: false
}},
legend: { position: 'none' },
histogram: { bucketSize: 5 },
colors:['red','yellow']
};
var chart = new google.visualization.Histogram(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
</body>
</html>
On another part of my screen I have a map showing the data points separately.
I want to filter the map using the IDs of each data point of a selected bar. That is, if the user selects a bar in the histogram, I need to get all the IDs of data points in that bar.
I've been fishing around the web, but mostly found solutions for getting a specific item using chart.getSelection().
I tried to also get the column range, but got unclear results of min=0 and max=999.
Any help is appreciated!

for a Histogram, getSelection() only returns the index of the selected bar,
it does not return the row indexes from the data table,
as it does with other charts.
in this case, we need to use --> getChartLayoutInterface()
the layout interface is an object we can use to find the position of various chart elements.
first, we use getSelection() to determine which bar, and / or series, is selected.
getSelection() will return something similar to --> [{"row":3,"column":1}]
where row is the selected bar, and column is the data table column,
and column - 1 is the series index.
next, we use the layout interface method --> getBoundingBox(id)
where id is the id of the chart element, for a bar it takes the following format.
bar#series#row -- bar#0#3
as such, getBoundingBox('bar#0#3') will give us the dimensions of the fourth bar.
something like --> {"left":381,"top":60.5,"width":89,"height":103}
then we can use layout interface method --> getHAxisValue(position)
this will return the value on the x-axis for the given position
by providing the left and right coordinates of the bar,
we can determine the min and max values of the range
with the range, we can then filter the data table to determine which rows make up the bar.
here is the snippet...
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length > 0) {
// get position of selected bar
var chartLayout = chart.getChartLayoutInterface();
var barBounds = chartLayout.getBoundingBox('bar#' + (selection[0].column - 1) + '#' + selection[0].row);
// get rows for selected bar
var rows = data.getFilteredRows([{
column: selection[0].column,
minValue: chartLayout.getHAxisValue(barBounds.left),
maxValue: chartLayout.getHAxisValue(barBounds.left + barBounds.width)
}]);
// create data view for selected rows
var view = new google.visualization.DataView(data);
view.setRows(rows);
// get ids of selected bar
var ids = view.getDistinctValues(0);
console.log(JSON.stringify(ids));
}
});
EDIT
the number of items in the above snippet was off.
instead of using minValue & maxValue,
we need to use the test function.
where the value of each row is...
>= min value of the range
< max value of the range
the above was >= & <=
and we may also need to use Math.ceil on the min value,
and Math.floor on the max value.
the following snippet appears to sync with the chart...
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length > 0) {
// get position of selected bar
var chartLayout = chart.getChartLayoutInterface();
var barBounds = chartLayout.getBoundingBox('bar#' + (selection[0].column - 1) + '#' + selection[0].row);
// get rows for selected bar
var rows = data.getFilteredRows([{
column: selection[0].column,
test: function (value) {
return ((value >= Math.ceil(chartLayout.getHAxisValue(barBounds.left))) &&
(value < Math.floor(chartLayout.getHAxisValue(barBounds.left + barBounds.width))));
}
}]);
// create data view for selected rows
var view = new google.visualization.DataView(data);
view.setRows(rows);
// get ids of selected bar
var ids = view.getDistinctValues(0);
console.log(ids.length);
}
});
see following working example...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['pt_network_seg_id','speed'],
['9',32],
['10',22],
['13',23],
['14',18],
['15',34],
['17',22],
['18',30],
['19',20],
['20',33],
['21',26],
['22',33],
['23',21],
['24',19],
['25',41],
['26',23],
['27',16],
['28',39],
['29',15],
['30',25],
['31',26],
['32',29],
['40',31],
['41',9],
['42',27],
['44',25],
['45',10],
['46',25],
['47',24],
['48',20],
['49',20],
['50',25],
['51',19],
['52',34],
['53',19],
['54',27],
['56',27],
['58',10],
['59',26],
['60',54],
['62',54],
['64',17],
['68',27],
['74',43],
['75',10],
['76',32],
['77',47],
['78',31],
['80',24],
['84',20],
['85',35],
['86',33],
['88',25],
['89',26],
['91',35],
['93',25],
['94',18],
['95',24],
['98',34],
['100',23],
['101',36],
['102',18],
['103',21],
['105',16],
['106',26],
['107',29],
['109',8],
['111',16],
['112',19],
['113',33],
['114',20],
['115',18],
['116',21],
['117',14],
['126',22],
['127',26],
['130',24],
['131',10],
['133',29],
['134',26],
['135',22],
['136',16],
['137',14],
['139',23],
['140',17],
['141',18],
['142',19],
['143',15],
['144',25],
['145',19],
['146',23],
['147',18],
['148',50],
['150',47],
['151',13],
['152',37],
['153',24],
['156',22],
['157',21],
['158',40],
['159',34],
['160',12],
['161',22],
['165',18],
['168',24],
['169',23],
['171',20],
['172',22],
['173',25],
['175',30],
['176',24],
['177',15],
['178',25],
['179',0],
['181',28],
['182',21],
['183',17],
['184',22],
['185',40],
['187',24],
['188',22],
['189',21],
['190',8],
['191',18],
['192',23],
['193',33],
['194',30],
['195',32],
['196',33],
['197',31],
['198',34],
['199',34],
['200',31],
['201',31],
['203',20],
['204',34],
['205',32],
['206',19],
['210',24],
['211',32],
['212',29],
['213',19],
['214',20],
['215',19],
['216',21],
['217',24],
['218',27],
['219',22],
['220',20],
['221',17],
['222',18],
['223',34],
['224',35],
['229',19],
['230',22],
['231',21],
['232',23],
['234',27],
['235',22],
['236',12],
['237',17],
['238',16],
['239',19],
['240',33],
['241',13],
['242',24],
['243',25],
['244',19],
['245',19],
['246',17],
['247',23],
['248',22],
['250',12],
['252',10],
['253',13],
['254',17],
['256',23],
['257',16],
['258',20],
['259',24],
['260',36],
['263',15],
['264',19],
['266',24],
['267',14],
['270',17],
['271',23],
['272',14],
['274',21],
['277',26],
['279',18],
['280',27],
['281',26],
['282',19],
['283',23],
['284',19],
['288',49],
['289',37],
['290',31],
['291',50],
['296',17],
['297',29],
['299',17],
['301',32],
['302',34],
['304',17],
['305',32],
['306',23],
['307',34],
['309',27],
['314',20],
['316',39],
['317',48],
['318',34],
['319',46],
['326',16],
['329',0],
['330',17],
['334',15],
['338',4],
['339',14],
['341',23],
['346',31],
['347',27],
['348',39],
['349',20],
['350',18],
['351',16],
['352',20],
['353',20],
['354',18],
['355',29],
['356',22],
['360',18],
['362',0],
['363',27],
['367',25],
['368',15],
['369',23],
['370',31],
['371',43],
['373',13],
['374',30],
['375',43],
['376',27],
['377',44],
['379',35],
['380',23],
['382',41],
['383',31],
['384',28],
['385',23],
['386',19],
['387',22],
['388',30],
['389',31],
['390',3],
['391',38],
['393',7],
['394',34],
['396',31],
['397',31],
['398',24],
['399',39],
['400',31],
['401',31],
['402',27],
['403',12],
['405',7],
['406',23],
['408',24],
['409',35],
['410',32],
['411',31],
['412',33],
['415',0],
['416',25],
['417',17],
['418',14],
['420',9],
['421',16],
['422',24],
['423',49],
['424',31],
['426',31],
['427',25],
['428',33],
['429',23],
['430',31],
['431',29],
['433',27],
['434',14],
['435',22],
['436',48],
['437',30],
['438',17],
['439',12],
['442',18],
['443',32],
['444',26],
['445',14],
['446',17],
['447',13],
['450',20],
['451',25],
['452',24],
['454',14],
['455',19],
['456',23],
['457',15],
['458',20],
['459',23],
['460',21],
['461',30],
['462',15],
['463',26],
['464',16],
['465',22],
['466',20],
['467',28],
['468',22],
['469',27],
['470',15],
['476',8],
['478',7],
['479',14],
['481',14],
['482',8],
['483',17],
['484',16],
['485',10],
['487',10],
['488',17],
['492',12],
['493',18],
['496',22],
['497',14],
['498',19],
['500',17],
['501',13],
['503',9],
['504',16],
['505',19],
['506',19],
['507',25],
['508',27],
['510',15],
['512',12],
['514',8],
['515',18],
['517',20],
['518',14],
['519',19],
['520',16],
['522',15],
['523',18],
['525',20],
['526',21],
['527',21],
['528',21],
['529',26],
['531',21],
['533',4],
['535',16],
['536',0],
['537',16],
['538',16],
['539',19],
['540',24],
['541',17],
['542',12],
['543',16],
['545',16],
['546',15],
['547',11],
['549',8],
['550',13],
['551',26],
['552',35],
['553',20],
['554',17],
['556',0],
['557',13],
['558',14],
['559',13],
['561',13],
['563',18],
['564',19],
['566',10],
['567',23],
['568',8],
['570',49],
['571',20],
['572',36],
['573',27],
['574',0],
['575',24],
['576',13],
['577',51],
['578',0],
['579',16],
['582',13],
['583',16],
['584',17],
['585',15],
['586',19],
['589',13],
['590',20],
['591',18],
['593',21],
['594',28],
['595',35],
['596',20],
['597',9],
['598',5],
['599',12],
['600',21],
['601',16],
['602',7],
['604',22],
['605',44],
['607',40],
['608',27],
['609',16],
['610',17],
['612',15],
['613',14],
['614',39],
['615',13],
['618',7],
['620',13],
['621',13],
['623',27],
['624',13],
['625',13],
['628',16],
['629',15],
['630',28],
['631',10],
['633',18],
['634',12],
['636',14],
['638',35],
['639',6],
['640',14],
['641',14],
['642',14],
['643',28],
['644',29],
['645',21],
['649',15],
['650',21],
['651',22],
['652',20],
['653',24],
['654',19],
['655',17],
['656',15],
['657',14],
['659',11],
['660',12],
['663',29],
['664',14],
['666',6],
['667',30],
['669',7],
['670',9],
['671',29],
['672',19],
['676',19],
['679',23],
['680',16],
['681',19],
['682',16],
['683',35],
['684',17],
['685',29],
['687',35],
['688',21],
['689',22],
['691',20],
['692',19],
['693',34],
['694',26],
['695',21],
['697',25],
['698',20],
['700',24],
['701',24],
['702',25],
['703',24],
['704',18],
['706',20],
['707',15],
['708',26],
['711',9],
['712',30],
['713',28],
['714',49],
['716',23],
['717',21],
['718',33],
['719',22],
['720',22],
['722',19],
['723',47],
['725',16],
['726',12],
['727',23],
['728',18],
['730',36],
['731',17],
['732',18],
['733',31],
['735',31],
['737',17],
['738',15],
['739',18],
['741',28],
['742',28],
['743',26],
['744',24],
['745',0],
['746',25],
['747',22],
['748',24],
['753',26],
['755',35],
['756',26],
['757',36],
['758',25],
['759',23],
['760',23],
['761',13],
['762',18],
['763',22],
['764',29],
['765',20],
['766',25],
['767',20],
['769',18],
['770',21],
['773',14],
['774',21],
['781',38],
['783',29],
['784',24],
['785',31],
['786',33],
['790',30],
['791',13],
['792',19],
['793',20],
['794',20],
['796',15],
['797',23],
['798',20],
['799',16],
['801',36],
['802',40],
['803',29],
['805',33],
['809',27],
['810',23],
['811',28],
['812',22],
['813',25],
['815',4],
['816',19],
['817',30],
['818',34],
['819',20],
['820',19],
['821',20],
['822',14],
['823',20],
['824',23],
['827',14],
['829',31],
['830',14],
['831',32],
['832',38],
['834',17],
['835',32],
['841',21],
['845',40],
['847',14],
['848',13],
['849',15],
['850',10],
['851',13],
['852',14],
['854',23],
['855',22],
['857',18],
['858',16],
['859',25],
['860',15],
['862',15],
['863',13],
['864',25],
['865',22],
['867',19],
['868',19],
['869',20],
['870',18],
['872',19],
['873',7],
['875',19],
['876',19],
['877',13],
['878',19],
['879',25],
['880',26],
['882',33],
['883',21],
['884',36],
['888',27],
['889',14],
['891',22],
['893',13],
['894',14],
['895',21],
['898',6],
['900',21],
['901',31],
['902',21],
['903',15],
['904',11],
['913',21],
['915',13],
['916',14],
['917',32],
['918',32],
['922',28],
['923',19],
['924',18],
['926',26],
['930',13],
['931',10],
['933',19],
['934',27],
['935',6],
['937',4],
['938',13],
['940',27],
['941',16],
['945',16],
['946',14],
['948',0],
['949',22],
['952',17],
['953',21],
['954',25],
['955',21],
['956',21],
['957',6],
['958',8],
['959',24],
['960',28],
['961',45],
['962',23],
['963',19],
['964',13],
['965',14],
['966',40],
['967',9],
['968',22],
['969',18],
['970',24],
['971',18],
['973',37],
['974',52],
['976',17],
['977',24],
['978',14],
['979',28],
['980',32],
['982',23],
['983',24],
['985',30],
['986',13],
['989',19],
['990',23],
['992',21],
['993',22],
['995',31],
['996',27],
['997',24],
['999',25],
['1000',27],
['1002',10],
['1003',19],
['1004',29],
['1005',6],
['1006',10]
]);
var options = {
title: 'Distribution of Bus Speeds on Beer Sheva PT Segments 7-10AM',
hAxis: {
title: 'Bus Speeds (kph)',
titleTextStyle: {
italic: false
}
},
vAxis: {
title: 'PT Segments Count',
titleTextStyle: {
italic: false
}
},
legend: {
position: 'none'
},
histogram: {
bucketSize: 5
},
colors:['red', 'yellow']
};
var chart = new google.visualization.Histogram(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length > 0) {
// get position of selected bar
var chartLayout = chart.getChartLayoutInterface();
var barBounds = chartLayout.getBoundingBox('bar#' + (selection[0].column - 1) + '#' + selection[0].row);
// get rows for selected bar
var rows = data.getFilteredRows([{
column: selection[0].column,
test: function (value) {
return ((value >= Math.ceil(chartLayout.getHAxisValue(barBounds.left))) && (value < Math.floor(chartLayout.getHAxisValue(barBounds.left + barBounds.width))));
}
}]);
// create data view for selected rows
var view = new google.visualization.DataView(data);
view.setRows(rows);
// get ids of selected bar
var ids = view.getDistinctValues(0);
console.log(ids.length);
}
});
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

If any row in range (G11:G25) contains boolean (true) then run function, else msgBox

The function I'm running (clearRowContents) in sheet 'Section 2' will clear contents and validation for any checked item (col H) in a list as well as the checkbox itself (col G). The remaining unchecked boxes and list items will then be sorted to clear any blank rows just created by the clearRowContents function. This functions works as tested.
However, if no item is checked (col G == false) and the "clear" button is pressed, how can I have a message pop up letting the user know that they must first check the box next to the item and then press the button to clear its contents from the list? I'm trying to figure out how to write the script for the clearItemMessage function.
Also, for script writing purposes, this sheet will be duplicated many times to create various validation menus for different topics... each sheet will be a different "chapter" in a manual with its own unique set of drop downs (in a MASTER DROPDOWN tab).
link to sheet: https://docs.google.com/spreadsheets/d/1ZdlJdhA0ZJOIwLA9dw5-y5v1FyLfRSywjmQ543EwMFQ/edit?usp=sharing
code:
function clearItemMessage(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var checkboxRange = ss.getRangeList("$G$11:$G$25").getValues();
if (checkboxRange == true){
clearRowContents (col);
} else (Browser.msgBox("To delete items, select the box next to the items and then press the delete button."));
}
function clearRowContents (col){ // col is the index of the column to check for checkbox being true
var col = 7; //col G
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = ss.getDataRange().getValues();
//Format font & size
var sheetFont = ss.getRange("A:Z");
var boxFont = ss.getRange("$G$11:$G$25");
var listFont = ss.getRange("$H$11:$H$25");
sheetFont.setFontFamily("Montserrat");
boxFont.setFontSize(8)
.setFontColor("#434343")
.setBackground("#ffffff");
listFont.setFontSize(12)
.setFontColor("#434343")
.setBackground("#ffffff");
//clear 'true' data validations
var deleteRanges = data.reduce(function(ar, e, i) {
if (e[col - 1] === true) {
return ar.concat(["H" + (i + 1), "G" + (i + 1)]);
}
return ar;
}, []);
if (deleteRanges.length > 0) {
ss.getRangeList(deleteRanges).clearContent().clearDataValidations();
}
//sort based on checkbox value
var range = ss.getRange("$G$11:$H$25");
range.sort({column: 7, ascending: false});
}
In your situation, how about modifying clearItemMessage() as follows?
Modified script:
function clearItemMessage(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var checkboxes = ss.getRange("$G$11:$G$25").getValues();
if (checkboxes.filter(([g]) => g === true).length > 0){ // or if (checkboxes.some(([g]) => g === true)) {
clearRowContents();
} else {
Browser.msgBox("To delete items, select the box next to the items and then press the delete button.");
}
}
From your question, I understood your clearRowContents works. So I proposed to modify clearItemMessage.
In your clearRowContents, var col = 7 is used. So I think that function clearRowContents (col){ can be modified to function clearRowContents (){.
Reference:
filter()

How can I scale my dataset values as a percentage of the index in chart.js?

Sorry if the question is poorly worded.Here is my chart
I am looking into scaling the chart's display of dataset(s) values as a percentage such as:
//input
data:{
datasets[{
label: 'data1',
data: [15, 22, 18, 35, 16, 29, 40]
},
{
label: 'data2',
data: [20, 21, 20, 19, 21, 22, 35]
}]
data1's points on the chart would be displayed as [42.9, 51.2, 47.4, 64.8, 43.2, 56.9, 57.1]
data2's points on the chart would be displayed as [57.1, 48.8, 52.6, 35.2, 56.8, 43.1, 42.9]
It should look like this. All visible lines should stack up to 100%. If a dataset is hidden, how can I recalculate the percentage and update the chart so that everything stays stacked up to 100%?
I thought about doing a plugin where I do the calculation using myLine.data.datasets but then I don't know how to remove a hidden dataset's values from the calculation and I'm not sure how to display it unless I overwrite the original datasets. I'm pretty sure this is the wrong approach.
Any help would be greatly appreciated.
So, I figured it out. I needed to write a function to calculate the percentage area of the points in the index and then update the datasets with the calculated percentage values.
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* DS_update calculates the percentage area of the input datasets
*
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function DS_update(dataset_in, ds_vis){
// make a deep copy (no references to the source)
var temp = jQuery.extend(true, [], dataset_in);
// gets the sum of all datasets at a given index
function getTotal(index){
total = 0;
// step through the datasets
dataset_in.forEach(function(e, i){
// inc total if the dataset is visible
if(ds_vis[i]){
total += e[index];
}
// do nothing if the dataset is hidden
});
return total;
}
// update temp array with calculated percentage values
temp.forEach(function(el, ind){
var j = ind;
el.forEach(function(e, i){
// calculate percentage to the hundredths place
temp[j][i] = Math.round((e / getTotal(i))*10000)/100;
});
});
return temp;
}
Once I tested the functions I had to run them before initial load of the chart or else the user would see the datasets as non area-percent (raw data). which looks something like this:
// Keep source array to use in the tool tips
var Src_ary = Input_data; // multidimensional array of input data
// holds the percent-area calculations as datapoints
var Prod_ary = DS_update(Src_ary, Init_visible(Src_ary));
Next up was updating the onClick for the legend. I need this to update the calculations every time an item's visibility is toggled:
legend: {
position: 'bottom',
usePointStyle: true,
onClick:
function(e, legendItem){
var index = legendItem.datasetIndex;
var ci = this.chart;
var meta = ci.getDatasetMeta(index);
var vis_ary = [];
var updatedSet = [];
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// load the visible array
for(var i = 0; i < (ci.data.datasets || []).length; i++){
switch (ci.getDatasetMeta(i).hidden){
case null:
vis_ary.push(true);
break;
default:
vis_ary.push(false);
break;
}
}
// update datasets using vis_ary to tell us which sets are visible
updatedSet = DS_update(Prod_ary, vis_ary);
myLine.data.datasets.forEach(function (e,i){
e.data = updatedSet[i];
});
// We did stuff ... rerender the chart
ci.update();
}
}
END RESULT
This is what I was trying to do: highchart fiddle
This is what I ended up with:fiddle
It took a few days and a lot of reading through chartjs.org's documentation to put this together. In the end I think it came out pretty good considering I am new to chart.js and borderline illiterate with javascript.

jQuery Cycle2 per-slide speed option

I can change timeout using the timeoutFn. How can I do the same for speed? I seached and could not find any way other that having the data-speed attribute on the slide elements. Is there any way to change that programmatically?
$('.slideshow').cycle({
speed: 100,
timeoutFn: calculateTimeout,
slides: "li",
fx: 'scrollLeft,scrollDown,scrollRight'
});
function calculateTimeout(currElement, nextElement, opts, isForward) {
var currentElementTransition = $(currElement).attr('data-timeout');
return parseInt(currentElementTransition, 10) || 0;
}

LineChart with certain columns

i am displaying a line chart and have data toggle on/off set up based on the answer (given by Abinaya Selvaraju) here:
Show/hide lines/data in Google Chart
it works great.
now i want to certain columns to be automatically grayed out when the chart first displays.
i think i need to do something like what's shown in the answer and came up with this:
for (var regionCol=0; regionCol<chartData.getNumberOfColumns();regionCol++){
if ((regionCol >= 2) && (regionCol <=7)){
columns[regionCol] = {
label: chartData.getColumnLabel(regionCol),
type: chartData.getColumnType(regionCol),
calc: function () {
return null;
}
};
// grey out the legend entry
//series[col - 1].color = '#CCCCCC';
series[Math.floor(regionCol/3)].color = '#CCCCCC';
}
else{
// show the data series
columns[regionCol] = regionCol;
//series[col - 1].color = null;
series[Math.floor(regionCol/3)].color = null;
}
}
var viewToHideRegions = new google.visualization.DataView(chartData);
viewToHideRegions.setColumns(columns);
chart.draw(viewToHideRegions, options);
/* code to set regions to be hidden */
This is how my chart data is defined:
chartData.addColumn('string', 'Date'); // Implicit series 1 data col.
chartData.addColumn('number', colIdxName); // Implicit domain label col.
chartData.addColumn({type:'string', role:'annotation'});
chartData.addColumn({type:'string', role:'annotationText'});
chartData.addColumn('number', dpndata[colGenIdx]['name']); // Implicit domain label col.
chartData.addColumn({type:'string', role:'annotation'});
chartData.addColumn({type:'string', role:'annotationText'});
When I run all of this, i get the message "All series on a given axis must be of the same data type"
I can't spot what I've got wrong.
Can anyone help?
There are a couple things you need to fix here. First, you only have 7 columns, and the column indices start at 0, so checking column indices 2-7 will start too late and overflow the end of the column list. Second, you always want your domain column (index 0) to be included, but you don't want to list it in the series option. Third, the "annotation" and "annotationText" columns need to have their roles specified in the view.
Your code should look something like this (to grey out all series by default):
var columns = [0];
for (var regionCol = 1; regionCol < chartData.getNumberOfColumns(); regionCol++) {
columns[regionCol] = {
label: chartData.getColumnLabel(regionCol),
type: chartData.getColumnType(regionCol),
role: chartData.getColumnProperty(regionCol, 'role'),
calc: function () {
return null;
}
};
// grey out the legend entry
if (regionCol % 3 == 1) {
series[Math.floor(regionCol / 3) - 1].color = '#CCCCCC';
}
}
var viewToHideRegions = new google.visualization.DataView(chartData);
viewToHideRegions.setColumns(columns);
chart.draw(viewToHideRegions, options);
/* code to set regions to be hidden */

google charts, tooltip replace column value

I'm using a combo chart from the google graph api (combo chart type). I want to add custom tooltips to add information about each point in the graph, but one of the value is replaced by the tooltip.
Here a very similar example graphic:
adding tooltip to graphs
Supposing that I'm using that graph. In my case, the value 106 (for the year 2011), is replaced by Growth 14% (the tooltip value)
Here the code that generates the data:
function gcomboChart () {
var data = new google.visualization.DataTable();
var dataVal =
[
["January",37903,655396,3411359,"Tooltip January"],
["February",33813,559595,3035931,"Tooltip February"],
["March",54073,725638,4561690,"Tooltip March"]
];
data.addColumn('string','month');
data.addColumn('number','Value1');
data.addColumn('number','Value2');
data.addColumn('number','Value3');
data.addColumn({type:'string', role:'tooltip'});
data.addRows(dataVal);
return(data);
}
//Here the code that generates the graph:
function drawChartComboChartID14cc19be5eef() {
var data = gcomboChart();
var options = { focusTarget: 'category'};
options["allowHtml"] = true;
options["seriesType"] = "bars";
options["series"] = {0: {targetAxisIndex:1,type:"line"}};
options["series"] = {0: {targetAxisIndex:2,type:"line"}};
options["vAxes"] = [{title:'Left Axis',format:'#,###',titleTextStyle:{color: 'orange'},textStyle:{color: 'orange'},textPosition:'out'},
{title:'Right Axis',format:'#,###',titleTextStyle:{color: 'blue'},textStyle:{color: 'blue'},textPosition:'out'}];
options["width"] = 1000;
options["height"] = 600;
options["pointSize"] = 9;
var chart = new google.visualization.ComboChart(
document.getElementById('ComboChart'));
chart.draw(data,options);
}
If you use the code, you'll see that the value of the third variable (Value3), is overwritten by the tooltip. I don't know hoy to get rid of that problem.
I want to show the three values of 'Value1-3' plus the tooltip
Can you please give me a hand?
Thanks!
Tooltips by default will replace the tooltip for that data point. It will not add an additional tooltip. To get around this, you need to add an additional series, and format the tooltip manually within that data value. You can then hide it from the legend, and have it display all nice as follows:
Here is the code:
function gcomboChart () {
var data = new google.visualization.DataTable();
//{v: x, f: y} allows you to set a manual format for each data point
var dataVal =
[
["January",37903,655396,3411359,{v: 0, f:"Tooltip January"}],
["February",33813,559595,3035931,{v: 0, f:"Tooltip February"}],
["March",54073,725638,4561690,{v: 0, f:"Tooltip March"}]
];
data.addColumn('string','month');
data.addColumn('number','Value1');
data.addColumn('number','Value2');
data.addColumn('number','Value3');
// Changed to standard data rather than tooltip role
data.addColumn('number','');
data.addRows(dataVal);
return(data);
}
//Here the code that generates the graph:
function drawVisualization() {
var data = gcomboChart();
var options = { focusTarget: 'category'};
options["allowHtml"] = true;
options["seriesType"] = "bars";
// the below line makes sure the tooltip is not shown in the legend
options["series"] = {0: {targetAxisIndex:0,type:"line"},3: {visibleInLegend:false}};
options["vAxes"] = [{title:'Left Axis',format:'#,###',titleTextStyle:{color: 'orange'},textStyle:{color: 'orange'},textPosition:'out'},
{title:'Right Axis',format:'#,###',titleTextStyle:{color: 'blue'},textStyle:{color: 'blue'},textPosition:'out'}];
options["width"] = 1000;
options["height"] = 600;
options["pointSize"] = 9;
var chart = new google.visualization.ComboChart(
document.getElementById('visualization'));
chart.draw(data,options);
}
Note: I should have switched series 3 to a line as well so that it doesn't push the bars over one. Change the series setting as follows to make it look nicer: options["series"] = {0: {targetAxisIndex:0,type:"line"},3: {visibleInLegend:false,type:"line"}};