UNPKG

terriajs

Version:

Geospatial data visualization platform.

210 lines (174 loc) 8 kB
'use strict'; /*global require*/ var CatalogFunction = require('./CatalogFunction'); var defined = require('terriajs-cesium/Source/Core/defined'); var defineProperties = require('terriajs-cesium/Source/Core/defineProperties'); // var extendLoad = require('./extendLoad'); var GeoJsonCatalogItem = require('./GeoJsonCatalogItem'); var inherit = require('../Core/inherit'); var invokeTerriaAnalyticsService = require('./invokeTerriaAnalyticsService'); var TerriaError = require('../Core/TerriaError'); var RegionDataParameter = require('./RegionDataParameter'); var RegionParameter = require('./RegionParameter'); var RegionTypeParameter = require('./RegionTypeParameter'); // var updateRectangleFromRegion = require('./updateRectangleFromRegion'); var when = require('terriajs-cesium/Source/ThirdParty/when'); /** * A Terria Spatial Inference function to determines the characteristics by which a particular region is _most different_ * from all other regions. * * @alias WhyAmISpecialCatalogFunction * @constructor * @extends CatalogFunction * * @param {Terria} terria The Terria instance. */ var WhyAmISpecialCatalogFunction = function(terria) { CatalogFunction.call(this, terria); this.url = undefined; this.name = 'What makes this region unique or special?'; this.description = 'Determines the characteristics by which a particular region is _most different_ from all other regions.'; this._regionTypeParameter = new RegionTypeParameter({ terria: this.terria, catalogFunction: this, id: 'regionType', name: 'Region Type', description: 'The type of region to analyze.' }); this._regionParameter = new RegionParameter({ terria: this.terria, catalogFunction: this, id: 'region', name: 'Region', description: 'The region to analyze. The analysis will determine the characteristics by which this region is most different from all others.', regionProvider: this._regionTypeParameter }); this._dataParameter = new RegionDataParameter({ terria: this.terria, catalogFunction: this, id: 'data', name: 'Characteristics', description: 'The region characteristics to include in the analysis.', regionProvider: this._regionTypeParameter }); this._parameters = [ this._regionTypeParameter, this._regionParameter, this._dataParameter ]; }; inherit(CatalogFunction, WhyAmISpecialCatalogFunction); defineProperties(WhyAmISpecialCatalogFunction.prototype, { /** * Gets the type of data member represented by this instance. * @memberOf WhyAmISpecialCatalogFunction.prototype * @type {String} */ type : { get : function() { return 'why-am-i-special-function'; } }, /** * Gets a human-readable name for this type of data source, 'Why Am I Special?'. * @memberOf WhyAmISpecialCatalogFunction.prototype * @type {String} */ typeName : { get : function() { return 'Why Am I Special?'; } }, /** * Gets the parameters used to {@link CatalogProcess#invoke} to this function. * @memberOf WhyAmISpecialCatalogFunction * @type {CatalogProcessParameters[]} */ parameters : { get : function() { return this._parameters; } } }); WhyAmISpecialCatalogFunction.prototype._load = function() { }; /** * Invokes the function. * @return {AsyncProcessResultCatalogItem} The result of invoking this process. Because the process typically proceeds asynchronously, the result is a temporary * catalog item that resolves to the real one once the process finishes. */ WhyAmISpecialCatalogFunction.prototype.invoke = function() { var region = this._regionParameter.value; var data = this._dataParameter.getRegionDataValue(); if (!defined(region)) { throw new TerriaError({ title: 'Region not selected', message: 'You must select a Region.' }); } var regionProvider = this._regionTypeParameter.value; var request = { algorithm: 'whyamispecial', boundaries_name: regionProvider.regionType, region_codes: data.regionCodes, columns: data.columnHeadings, table: data.table, parameters: { query: region.id } }; var regionIndex = regionProvider.regions.indexOf(region); var regionName = region.id; if (regionIndex >= 0) { regionName = regionProvider.regionNames[regionIndex] || regionName; } var name = 'Why is ' + regionName + ' special?'; var geoJsonPromise = regionProvider.getRegionFeature(this.terria, region); var invocationPromise = invokeTerriaAnalyticsService(this.terria, name, this.url, request); var that = this; return when.all([geoJsonPromise, invocationPromise]).then(function(allResults) { var geoJson = allResults[0]; var invocationResult = allResults[1]; var result = invocationResult.result; var catalogItem = new GeoJsonCatalogItem(that.terria); catalogItem.name = name; catalogItem.data = geoJson; catalogItem.dataUrl = invocationResult.url; var description = 'This is the result of invoking "' + that.name + '" at ' + invocationResult.startDate + ' with these parameters:\n\n'; description += ' * ' + regionProvider.regionType + ' Region: ' + regionName + ' (' + region.id + ')\n'; description += ' * Characteristics: ' + data.columnHeadings.join(', ') + '\n'; catalogItem.description = description; var shortReport = '<p>These are the top characteristics that make ' + regionName + ' unique or special:</p>'; for (var i = 0; i < 5 && i < result.columns.length; ++i) { var columnName = data.columnHeadings[result.columns[i]]; var histogram = result.histograms[i]; var binCounts = histogram.bin_counts; var binEdges = histogram.bin_edges; var chartData = [['Value', 'Count']]; for (var j = 0; j < binCounts.length; ++j) { var leftEdge = binEdges[j]; var rightEdge = binEdges[j + 1]; if (!defined(rightEdge)) { // Assume equally-spaced bins. rightEdge = leftEdge + (binEdges[1] - binEdges[0]); } var center = (leftEdge + rightEdge) * 0.5; chartData.push([center, binCounts[j]]); } var percentile = result.percentiles[i]; var percentileDescription = 'lower'; if (percentile > 50) { percentile = 100 - percentile; percentileDescription = 'higher'; } shortReport += '<collapsible title="' + columnName + '" open="' + (i === 0 ? 'true' : 'false') + '">\n'; shortReport += '<p style="font-size: 0.8em">The value of ' + columnName + ' in ' + regionName + ' is ' + result.values[i] + '.</p>\n'; shortReport += '<p style="font-size: 0.8em">Only ' + percentile.toFixed(1) + '% of regions have an equal or ' + percentileDescription + ' value.</p>\n'; shortReport += '<chart title="Distribution of ' + columnName + ' across ' + regionProvider.regionType + ' regions" id="' + columnName + '" data=\'' + JSON.stringify(chartData) + '\' column-names="," y-column="1" styling="histogram" highlight-x="' + result.values[i] + '" hide-buttons="true"></chart>\n'; shortReport += '</collapsible>\n'; } catalogItem.shortReport = shortReport; catalogItem.isEnabled = true; }); }; module.exports = WhyAmISpecialCatalogFunction;