covutils
Version:
Utilities for creating, transforming, and handling Coverage Data objects.
591 lines (529 loc) • 18.5 kB
JavaScript
;
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;