UNPKG

covutils

Version:

Utilities for creating, transforming, and handling Coverage Data objects.

591 lines (529 loc) 18.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.withSimpleDerivedParameter = undefined; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.withParameters = withParameters; exports.withCategories = withCategories; exports.withDomainType = withDomainType; exports.asCovJSONDomainType = asCovJSONDomainType; exports.renameAxes = renameAxes; exports.mapRange = mapRange; exports.withDerivedParameter = withDerivedParameter; var _constants = require('../constants.js'); var _validate = require('../validate.js'); var _util = require('../util.js'); var _create = require('./create.js'); function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /** * Returns a copy of the given Coverage object with the parameters * replaced by the supplied ones. * * Note that this is a low-level function and no checks are done on the supplied parameters. */ function withParameters(cov, params) { var newcov = { type: _constants.COVERAGE, domainType: cov.domainType, parameters: params, loadDomain: function loadDomain() { return cov.loadDomain(); }, loadRange: function loadRange(key) { return cov.loadRange(key); }, loadRanges: function loadRanges(keys) { return cov.loadRanges(keys); }, subsetByIndex: function subsetByIndex(constraints) { return cov.subsetByIndex(constraints).then(function (sub) { return withParameters(sub, params); }); }, subsetByValue: function subsetByValue(constraints) { return cov.subsetByValue(constraints).then(function (sub) { return withParameters(sub, params); }); } }; return newcov; } /** * Returns a copy of the given Coverage object with the categories * of a given parameter replaced by the supplied ones and the encoding * adapted to the given mapping from old to new. * * @param {Coverage} cov The Coverage object. * @param {String} key The key of the parameter to work with. * @param {object} observedProperty The new observed property including the new array of category objects * that will be part of the returned coverage. * @param {Map<String,String>} mapping A mapping from source category id to destination category id. * @returns {Coverage} */ function withCategories(cov, key, observedProperty, mapping) { /* check breaks with Babel, see https://github.com/jspm/jspm-cli/issues/1348 if (!(mapping instanceof Map)) { throw new Error('mapping parameter must be a Map from/to category ID') } */ (0, _validate.checkCoverage)(cov); if (observedProperty.categories.some(function (c) { return !c.id; })) { throw new Error('At least one category object is missing the "id" property'); } var newparams = (0, _util.shallowcopy)(cov.parameters); var newparam = (0, _util.shallowcopy)(newparams.get(key)); newparams.set(key, newparam); newparams.get(key).observedProperty = observedProperty; var fromCatEnc = cov.parameters.get(key).categoryEncoding; var catEncoding = new Map(); var categories = observedProperty.categories; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = categories[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var category = _step.value; var vals = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = mapping[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _step2$value = _slicedToArray(_step2.value, 2); var fromCatId = _step2$value[0]; var toCatId = _step2$value[1]; if (toCatId === category.id && fromCatEnc.has(fromCatId)) { vals.push.apply(vals, _toConsumableArray(fromCatEnc.get(fromCatId))); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } if (vals.length > 0) { catEncoding.set(category.id, vals); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } newparams.get(key).categoryEncoding = catEncoding; var newcov = withParameters(cov, newparams); return newcov; } /** * Returns a new coverage where the domainType field of the coverage and the domain * is set to the given one. * * @param {Coverage} cov The Coverage object. * @param {String} domainType The new domain type. * @returns {Coverage} */ function withDomainType(cov, domainType) { (0, _validate.checkCoverage)(cov); var domainWrapper = function domainWrapper(domain) { var newdomain = { type: _constants.DOMAIN, domainType: domainType, axes: domain.axes, referencing: domain.referencing }; return newdomain; }; var newcov = { type: _constants.COVERAGE, domainType: domainType, parameters: cov.parameters, loadDomain: function loadDomain() { return cov.loadDomain().then(domainWrapper); }, loadRange: function loadRange(key) { return cov.loadRange(key); }, loadRanges: function loadRanges(keys) { return cov.loadRanges(keys); }, subsetByIndex: function subsetByIndex(constraints) { return cov.subsetByIndex(constraints).then(function (sub) { return withDomainType(sub, domainType); }); }, subsetByValue: function subsetByValue(constraints) { return cov.subsetByValue(constraints).then(function (sub) { return withDomainType(sub, domainType); }); } }; return newcov; } /** * Tries to transform the given Coverage object into a new one that * conforms to one of the CovJSON domain types. * If multiple domain types match, then the "smaller" one is preferred, * for example, Point instead of Grid. * * The transformation consists of: * - Setting domainType in coverage and domain object * - Renaming domain axes * * @see https://github.com/Reading-eScience-Centre/coveragejson/blob/master/domain-types.md * * @param {Coverage} cov The Coverage object. * @returns {Promise<Coverage>} * A Promise succeeding with the transformed coverage, * or failing if no CovJSON domain type matched the input coverage. */ function asCovJSONDomainType(cov) { return cov.loadDomain().then(function (domain) { // TODO implement me }); } /** * @example * var cov = ... * var mapping = new Map() * mapping.set('lat', 'y').set('lon', 'x') * var newcov = CovUtils.renameAxes(cov, mapping) * * @param {Coverage} cov The coverage. * @param {Map<String,String>} mapping * @returns {Coverage} */ function renameAxes(cov, mapping) { (0, _validate.checkCoverage)(cov); mapping = new Map(mapping); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = cov.axes.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var axisName = _step3.value; if (!mapping.has(axisName)) { mapping.set(axisName, axisName); } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var domainWrapper = function domainWrapper(domain) { var newaxes = new Map(); var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = mapping[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _step4$value = _slicedToArray(_step4.value, 2); var from = _step4$value[0]; var to = _step4$value[1]; var _domain$axes$get = domain.axes.get(from); var dataType = _domain$axes$get.dataType; var coordinates = _domain$axes$get.coordinates; var values = _domain$axes$get.values; var bounds = _domain$axes$get.bounds; var newaxis = { key: to, dataType: dataType, coordinates: coordinates.map(function (c) { return mapping.has(c) ? mapping.get(c) : c; }), values: values, bounds: bounds }; newaxes.set(to, newaxis); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var newreferencing = domain.referencing.map(function (_ref) { var coordinates = _ref.coordinates; var system = _ref.system; return { coordinates: coordinates.map(function (c) { return mapping.has(c) ? mapping.get(c) : c; }), system: system }; }); var newdomain = { type: _constants.DOMAIN, domainType: domain.domainType, axes: newaxes, referencing: newreferencing }; return newdomain; }; // pre-compile for efficiency // get({['lat']: obj['y'], ['lon']: obj['x']}) var getObjStr = [].concat(_toConsumableArray(mapping)).map(function (_ref2) { var _ref3 = _slicedToArray(_ref2, 2); var from = _ref3[0]; var to = _ref3[1]; return '[\'' + from + '\']:obj[\'' + to + '\']'; }).join(','); var rangeWrapper = function rangeWrapper(range) { var get = new Function('range', 'return function get (obj){return range.get({' + getObjStr + '})}')(range); // eslint-disable-line var newrange = { shape: new Map([].concat(_toConsumableArray(range.shape)).map(function (_ref4) { var _ref5 = _slicedToArray(_ref4, 2); var name = _ref5[0]; var len = _ref5[1]; return [mapping.get(name), len]; })), dataType: range.dataType, get: get }; return newrange; }; var loadRange = function loadRange(paramKey) { return cov.loadRange(paramKey).then(rangeWrapper); }; var loadRanges = function loadRanges(paramKeys) { return cov.loadRanges(paramKeys).then(function (ranges) { return new Map([].concat(_toConsumableArray(ranges)).map(function (_ref6) { var _ref7 = _slicedToArray(_ref6, 2); var paramKey = _ref7[0]; var range = _ref7[1]; return [paramKey, rangeWrapper(range)]; })); }); }; var newcov = { type: _constants.COVERAGE, domainType: cov.domainType, parameters: cov.parameters, loadDomain: function loadDomain() { return cov.loadDomain().then(domainWrapper); }, loadRange: loadRange, loadRanges: loadRanges, subsetByIndex: function subsetByIndex(constraints) { return cov.subsetByIndex(constraints).then(function (sub) { return renameAxes(sub, mapping); }); }, subsetByValue: function subsetByValue(constraints) { return cov.subsetByValue(constraints).then(function (sub) { return renameAxes(sub, mapping); }); } }; return newcov; } /** * @param {Coverage} cov The coverage. * @param {String} key The key of the parameter for which the mapping should be applied. * @param {Function} fn A function getting called as fn(obj, range) where obj is the axis indices object * and range is the original range object. * @param {String} [dataType] The new data type to use for the range. If omitted, the original type is used. * @returns {Coverage} */ function mapRange(cov, key, fn, dataType) { (0, _validate.checkCoverage)(cov); var rangeWrapper = function rangeWrapper(range) { var newrange = { shape: range.shape, dataType: dataType || range.dataType, get: function get(obj) { return fn(obj, range); } }; return newrange; }; var loadRange = function loadRange(paramKey) { return key === paramKey ? cov.loadRange(paramKey).then(rangeWrapper) : cov.loadRange(paramKey); }; var loadRanges = function loadRanges(paramKeys) { return cov.loadRanges(paramKeys).then(function (ranges) { return new Map([].concat(_toConsumableArray(ranges)).map(function (_ref8) { var _ref9 = _slicedToArray(_ref8, 2); var paramKey = _ref9[0]; var range = _ref9[1]; return [paramKey, key === paramKey ? rangeWrapper(range) : range]; })); }); }; var newcov = { type: _constants.COVERAGE, domainType: cov.domainType, parameters: cov.parameters, loadDomain: function loadDomain() { return cov.loadDomain(); }, loadRange: loadRange, loadRanges: loadRanges, subsetByIndex: function subsetByIndex(constraints) { return cov.subsetByIndex(constraints).then(function (sub) { return mapRange(sub, key, fn, dataType); }); }, subsetByValue: function subsetByValue(constraints) { return cov.subsetByValue(constraints).then(function (sub) { return mapRange(sub, key, fn, dataType); }); } }; return newcov; } /** * * @example * var cov = ... // has parameters 'NIR', 'red', 'green', 'blue' * var newcov = CovUtils.withDerivedParameter(cov, { * parameter: { * key: 'NDVI', * observedProperty: { * label: { en: 'Normalized Differenced Vegetation Index' } * } * }, * inputParameters: ['NIR','red'], * dataType: 'float', * fn: function (obj, nirRange, redRange) { * var nir = nirRange.get(obj) * var red = redRange.get(obj) * if (nir === null || red === null) return null * return (nir - red) / (nir + red) * } * }) */ function withDerivedParameter(cov, options) { (0, _validate.checkCoverage)(cov); var parameter = options.parameter; var inputParameters = options.inputParameters; var _options$dataType = options.dataType; var dataType = _options$dataType === undefined ? 'float' : _options$dataType; var fn = options.fn; var parameters = new Map(cov.parameters); parameters.set(parameter.key, parameter); var loadDerivedRange = function loadDerivedRange() { return cov.loadRanges(inputParameters).then(function (inputRanges) { var inputRangesArr = inputParameters.map(function (key) { return inputRanges.get(key); }); var shape = inputRangesArr[0].shape; var range = { shape: shape, dataType: dataType, get: function get(obj) { return fn.apply(undefined, [obj].concat(_toConsumableArray(inputRangesArr))); } }; return range; }); }; var loadRange = function loadRange(paramKey) { return parameter.key === paramKey ? loadDerivedRange() : cov.loadRange(paramKey); }; var newcov = { type: _constants.COVERAGE, domainType: cov.domainType, parameters: parameters, loadDomain: function loadDomain() { return cov.loadDomain(); }, loadRange: loadRange, subsetByIndex: function subsetByIndex(constraints) { return cov.subsetByIndex(constraints).then(function (sub) { return withDerivedParameter(sub, options); }); }, subsetByValue: function subsetByValue(constraints) { return cov.subsetByValue(constraints).then(function (sub) { return withDerivedParameter(sub, options); }); } }; (0, _create.addLoadRangesFunction)(newcov); return newcov; } /** * * @example * var cov = ... // has parameters 'NIR', 'red', 'green', 'blue' * var newcov = CovUtils.withSimpleDerivedParameter(cov, { * parameter: { * key: 'NDVI', * observedProperty: { * label: { en: 'Normalized Differenced Vegetation Index' } * } * }, * inputParameters: ['NIR','red'], * dataType: 'float', * fn: function (nir, red) { * return (nir - red) / (nir + red) * } * }) */ function withSimpleDerivedParameter(cov, options) { var parameter = options.parameter; var inputParameters = options.inputParameters; var dataType = options.dataType; var _fn = options.fn; var options_ = { parameter: parameter, inputParameters: inputParameters, dataType: dataType, // TODO pre-compile if too slow fn: function fn(obj) { for (var _len = arguments.length, ranges = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { ranges[_key - 1] = arguments[_key]; } var vals = inputParameters.map(function (_, i) { return ranges[i].get(obj); }); if (vals.some(function (val) { return val === null; })) { return null; } return _fn.apply(undefined, _toConsumableArray(vals)); } }; return withDerivedParameter(cov, options_); } exports.withSimpleDerivedParameter = withSimpleDerivedParameter;