+// recompute values using aggregation mechanisms and custom statistics on raw data
+function recomputeAggregations(callback, errback) {
+ const attribute1 = "WAGES_TOTAL",
+ attribute2 = "POPULATION_TOTAL";
+ gsp.bi.stage.findStage(null, function(stage) {
+ // use BI aggregation mechanism. Here I'm using a weighted average of attribute1 by attribute2
+ let aggregationResult = stage.tryAggregation(`round($sum(${attribute1}*${attribute2})/$sum(${attribute2}))`);
+ if (!aggregationResult.success) return;
+ let value = aggregationResult.value.test;
+ // custom statistical operations on raw rows. I am using Array.prototype.reduce function
+ // but feel free to use plain for loop or whatever
+ let customAcc = stage.rows().reduce(function(accumulated, current) {
+ accumulated.min = Math.min(accumulated.min, current[attribute1]);
+ accumulated.max = Math.max(accumulated.max, current[attribute1]);
+ let output = `Weighted average of ${attribute1} by ${attribute2} is ${value} while min=${customAcc.min} and max=${customAcc.max}`;
+ if (typeof callback === "function")
+ if (typeof errback === "function")
+// recompute statistics and update the custom chart
+ recomputeAggregations(updateCustomChart);
+// update the custom chart
+function updateCustomChart(html) {
+ document.querySelector(".custom-chart > div.widget-chart > div.widget-content").innerHTML = html;
+function onRenderlet(chart, filter) {
+// wait for the pointmap layer, store reference to it and apply customizations
+waitFor("choropleth", function(widget) {
+ let geochart = widget.chart;
+ GLOBALS.geochart = geochart;
+ // attach an event to the choropleth so each time it is refreshed our onRenderlet function will execute
+ geochart.on("renderlet", onRenderlet);
+// waits until the widget of particular type is on stage
+// this is simplified and it should be used just once for particular chartType
+// @param {String} chartType - "choropleth", "pointmap", "table", "row", "bar", "pie", etc.
+// @param {Function} callback callback function
+// @param {Object} callback.widget first widget of particular type
+function waitFor(chartType, callback) {
+ gsp.bi.stage.findWidgets({
+ if (!widgets || !widgets[0]) {
+ TIMEOUTS[chartType] = setTimeout(function() {
+ waitFor(chartType, callback);
+ clearTimeout(TIMEOUTS[chartType]);