Commit 27902e4c authored by Michael Auer's avatar Michael Auer
Browse files

add support for ratio queries (csv, json, GeoJSON, PostGIS, horizontal,...

add support for ratio queries (csv, json, GeoJSON, PostGIS, horizontal, vertical, removeZeros only if all values (value, value2 are 0 and thus ratio is not available)
add normalization of ohsomeapi responses with respect to document structure and ratio values ("NaN" and "Infinity" are converted to proper null type)
parent b4afb017
......@@ -15,6 +15,11 @@ export abstract class FeatureType {
*/
abstract async getFeatureCount(): Promise<number>
/**
* @return string the sourceIdType for usage in JS. Either 'number' or 'string'
*/
abstract async getIdJsType(): Promise<string>
/**
* @return GeoJSON<FeatureCollection>
**/
......
......@@ -54,6 +54,11 @@ export class GeoJsonFeatureType extends FeatureType {
}
};
async getIdJsType(): Promise<string> {
const geojson = await this.getFeatures();
return typeof geojson.features[0].properties!.id
}
/**
* returns the total number of features
*/
......@@ -134,21 +139,52 @@ export class GeoJsonFeatureType extends FeatureType {
return featureCollection;
}
static removeFeaturesByPropertyValues (featureCollection: FeatureCollection, propertyValueMap: {[property:string]: any}) {
let filteredFeatures = featureCollection.features.filter(
(feature) => {
if (feature.properties === null) {
return true; //keep features lacking the indicated property
} else {
const properties = feature.properties;
let allValuesTrue = true;
for (const property in propertyValueMap) {
if (property in properties){
allValuesTrue = allValuesTrue && properties[property] === propertyValueMap[property];
} else{
//not all properties exist, test cannot be made -> keep feature
return true;
}
}
return !allValuesTrue;
}
}
);
featureCollection.features = filteredFeatures;
return featureCollection;
}
/**
* Creates a GeoJSON Feature Collection with either geometry:null, with original geometries from the query if sourceFeatureCollection is provided or with reprojected geometries if sourceFeatureCollection AND transformToWebmercator is given
* @param ohsomeGroupByBoundaryResponse response from ohsome-API, either ohsomeJSON or ohsomeGroupByBoundaryCSV
* @param sourceIdType the data type of the source feature ids. Necessary because in the case that numbers are stored as stings this cannot inferred from the ohsome csv-response.
* @param horizontal boolean if the result featureType should have many or one timestamp column
* @param sourceFeatureCollection if not undefined, will be used to join input geometry (bpolys) and ohsome-API results
* @param transformToWebmercator if sourceFeatureCollection is provided, should output be reprojected from WGS84 to (EPSG:4326) to Webmercator (EPSG:3857)?
**/
static fromOhsome(ohsomeGroupByBoundaryResponse: any, horizontal: boolean, sourceFeatureCollection?: FeatureCollection, transformToWebmercator?: boolean): FeatureCollection {
static fromOhsome(ohsomeGroupByBoundaryResponse: any, sourceIdType: string, horizontal: boolean, sourceFeatureCollection?: FeatureCollection, transformToWebmercator?: boolean): FeatureCollection {
const ohsomeResults = ohsomeGroupByBoundaryResponse;
let ohsomeResults = ohsomeGroupByBoundaryResponse;
const isCSV = (typeof ohsomeResults == 'string');
let isContributionView: boolean = true;
const castId = function(id:number|string){
return (sourceIdType == typeof id)? id: (sourceIdType == 'number')? parseFloat(<string>id) : id.toString();
}
let isContributionView: boolean;
let isRatio: boolean;
if (isCSV) {
......@@ -160,24 +196,36 @@ export class GeoJsonFeatureType extends FeatureType {
// check columnheaders for contributionview column names
const columns = lines[i].trim().split(";");
isContributionView = columns.includes("fromTimestamp") && columns.includes("toTimestamp");
// check isRatio: for non-grouped columnName is "ratio", for grouped response columnName is <someId>_ratio
isRatio = columns.includes("ratio") || columns.some((e: string)=> e.includes("_ratio"));
break;
}
}
} else {
//JSON Response
// JSON Response
// check isContributionView
const hasFromTimestamps = ohsomeResults.groupByResult[0].result[0].fromTimestamp !== undefined;
const hasToTimestamps = ohsomeResults.groupByResult[0].result[0].toTimestamp !== undefined;
isContributionView = hasFromTimestamps && hasToTimestamps;
// check isRatio
isRatio = ohsomeResults.groupByResult[0].result[0].ratio !== undefined;
}
const ohsomeGroupByBoundaryCSV = {
delimiter: ';',
dynamicTyping: (isContributionView) ? (col: any) => (!(col == 0 || col == 1)) : (col: any) => (col != 0), //first (or first two) column is timestamp and should remain string not auto converted to Date
header: false,
skipEmptyLines: true,
comments: '#',
newline: '\n'
};
// PapaParse config
let ohsomeGroupByBoundaryCSV;
ohsomeGroupByBoundaryCSV = {
delimiter: ';',
dynamicTyping: (isContributionView!) ? (col: any) => (!(col == 0 || col == 1)) : (col: any) => (col != 0), //first (or first two) column is timestamp and should remain string not auto converted to Date
header: false,
skipEmptyLines: true,
comments: '#',
newline: '\n',
//harmonize "NaN" strings to propoer null types
transform: ( val: any ) => { return ( typeof val === 'string' && (val === 'NaN' || val === 'Infinity' || val.toLowerCase() ==='null') ) ? null : val; }
};
const shouldCreateGeometry = !!sourceFeatureCollection;
......@@ -224,9 +272,20 @@ export class GeoJsonFeatureType extends FeatureType {
to_timestamp: tv.toTimestamp,
value: tv.value
})
}
};
const getFeatureFromRatioResult = (tv: any) => {
return turfHelpers.feature(geom,
{
id: id,
timestamp: tv.timestamp,
value: tv.value,
value2: tv.value2,
ratio: tv.ratio
})
};
const getFeatureFromResult = (isContributionView)? getFeatureFromContributionViewResult : getFeatureFromSnapshotResult;
const getFeatureFromResult = (isContributionView)? getFeatureFromContributionViewResult : (isRatio)? getFeatureFromRatioResult : getFeatureFromSnapshotResult;
const idFeatures = item.result.map(getFeatureFromResult);
......@@ -237,15 +296,23 @@ export class GeoJsonFeatureType extends FeatureType {
if (isCSV) {
//csv
isContributionView = isContributionView!;
//for proper id parsing remove text-part from column names, e.g. 23_value;23_value2;23_ratio;24_value;....
if(isRatio!){
ohsomeResults = ohsomeResults.replace(/(\.*)_value(2)?/g, "$1");
}
let ohsomeCsv = Papa.parse(ohsomeResults, ohsomeGroupByBoundaryCSV).data;
const nrows = ohsomeCsv.length;
const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView) ? 2 : 1; // for snapshotView start reading values at column index 1, for contributionView start at column index 2
const ncols = (!!ohsomeCsv[0]) ? (isRatio!)? ((ohsomeCsv[0].length - firstValueColumnIndex)/3)+firstValueColumnIndex : ohsomeCsv[0].length : 0;
for (let col = firstValueColumnIndex; col < ncols; col++) {
for (let row = 1; row < nrows; row++) {
let properties;
let properties: any;
if (isContributionView) {
properties = {
id: undefined,
......@@ -255,8 +322,22 @@ export class GeoJsonFeatureType extends FeatureType {
};
properties.from_timestamp = ohsomeCsv[row][0];
properties.to_timestamp = ohsomeCsv[row][1];
properties.id = ohsomeCsv[0][col];
properties.id = castId(ohsomeCsv[0][col]);
properties.value = ohsomeCsv[row][col];
} else if(isRatio!){
properties = {
id: undefined,
timestamp: undefined,
value: undefined,
value2: undefined,
ratio: undefined
};
properties.timestamp = ohsomeCsv[row][0];
let valueIndex = ( ( col-firstValueColumnIndex ) *3 ) + firstValueColumnIndex;
properties.id = castId(ohsomeCsv[0][valueIndex]); //value column
properties.value = ohsomeCsv[row][valueIndex]; //value column
properties.value2 = ohsomeCsv[row][valueIndex+1]; //value2 column
properties.ratio = ohsomeCsv[row][valueIndex+2]; //ratio column
} else {
properties = {
id: undefined,
......@@ -264,7 +345,7 @@ export class GeoJsonFeatureType extends FeatureType {
value: undefined
};
properties.timestamp = ohsomeCsv[row][0];
properties.id = ohsomeCsv[0][col];
properties.id = castId(ohsomeCsv[0][col]);
properties.value = ohsomeCsv[row][col];
}
......@@ -283,7 +364,9 @@ export class GeoJsonFeatureType extends FeatureType {
if (!isCSV) {
//json
if (!isRatio!){
targetFeatures = ohsomeResults.groupByResult.map((item: any) => {
const id = item.groupByObject;
......@@ -300,35 +383,93 @@ export class GeoJsonFeatureType extends FeatureType {
});
return turfHelpers.feature(geom, properties);
});
} else {
//ratio
targetFeatures = ohsomeResults.groupByResult.flatMap((item:any) => {
const id = item.groupByObject;
const geom = (shouldCreateGeometry) ? idGeomMap.get(id) : null;
let propertiesValue: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value'};
let propertiesValue2: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value2'};
let propertiesRatio: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'ratio'};
item.result.forEach((tvv2r: any) => {
propertiesValue[tvv2r.timestamp] = tvv2r.value;
propertiesValue2[tvv2r.timestamp] = tvv2r.value2;
propertiesRatio[tvv2r.timestamp] = tvv2r.ratio;
})
return [
turfHelpers.feature(geom, propertiesValue),
turfHelpers.feature(geom, propertiesValue2),
turfHelpers.feature(geom, propertiesRatio)
];
} );
}
}
if (isCSV) {
//csv
//for proper id parsing remove text-part from column names, e.g. 23_value;23_value2;23_ratio;24_value;....
if(isRatio!){
ohsomeResults = ohsomeResults.replace(/(\.*)_value(2)?/g, "$1");
}
const ohsomeCsv = Papa.parse(ohsomeResults, ohsomeGroupByBoundaryCSV).data;
const nrows = ohsomeCsv.length;
const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView) ? 2 : 1; // for snapshotView start reading values at column indeex 1, for contributionView start at column index 2
// const ncols = (!!ohsomeCsv[0]) ? ohsomeCsv[0].length : 0;
const firstValueColumnIndex = (isContributionView!) ? 2 : 1; // for snapshotView start reading values at column indeex 1, for contributionView start at column index 2
const ncols = (!!ohsomeCsv[0]) ? (isRatio!)? ((ohsomeCsv[0].length - firstValueColumnIndex)/3)+firstValueColumnIndex : ohsomeCsv[0].length : 0;
for (let col = firstValueColumnIndex; col < ncols; col++) {
let properties: { id: number | string | undefined; [timestamp: string]: any } = {
id: undefined
};
properties.id = ohsomeCsv[0][col];
for (let row = 1; row < nrows; row++) {
if (isContributionView) {
properties[`${ohsomeCsv[row][0]}/${ohsomeCsv[row][1]}`] = ohsomeCsv[row][col]; // fromTimestamp/toTimestamp = value
} else {
properties[ohsomeCsv[row][0]] = ohsomeCsv[row][col]; // timestamp = value
if(!isRatio!){
const id = castId(ohsomeCsv[0][col]);
const geom = (shouldCreateGeometry) ? idGeomMap!.get(id) : null;
let properties: { id: number | string | undefined; [timestamp: string]: any } = {
id: id
};
for (let row = 1; row < nrows; row++) {
if (isContributionView!) {
properties[`${ohsomeCsv[row][0]}/${ohsomeCsv[row][1]}`] = ohsomeCsv[row][col]; // fromTimestamp/toTimestamp = value
} else {
properties[ohsomeCsv[row][0]] = ohsomeCsv[row][col]; // timestamp = value
}
}
targetFeatures.push(turfHelpers.feature(geom, properties));
} else {
//ratio
let valueIndex = ( ( col-firstValueColumnIndex ) *3 ) + firstValueColumnIndex;
const id = castId(ohsomeCsv[0][valueIndex]);
const geom = (shouldCreateGeometry) ? idGeomMap!.get(id) : null;
let propertiesValue: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value'};
let propertiesValue2: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'value2'};
let propertiesRatio: { id: number | string; attrName: string; [timestamp: string]: any } = {id: id, attrName: 'ratio'};
for (let row = 1; row < nrows; row++) {
propertiesValue[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex]; //timestamp = value
propertiesValue2[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex+1]; //timestamp = value2
propertiesRatio[ohsomeCsv[row][0]] = ohsomeCsv[row][valueIndex+2]; //timestamp = ratio
}
targetFeatures.push(turfHelpers.feature(geom, propertiesValue));
targetFeatures.push(turfHelpers.feature(geom, propertiesValue2));
targetFeatures.push(turfHelpers.feature(geom, propertiesRatio));
}
// @ts-ignore
const geom = (shouldCreateGeometry) ? idGeomMap.get(properties.id) : null;
targetFeatures.push(turfHelpers.feature(geom, properties));
}
}
......
import {
Ohsome2XConfig,
OhsomeQueryConfig,
OhsomeQueryConfigFormat,
OhsomeQueryConfigFormat, OhsomeQueryRatioConfig,
TargetPostgisFeatureTypeConfig
} from './config_types_interfaces';
import normalizeUrl from 'normalize-url';
......@@ -31,6 +31,9 @@ class Ohsome2X extends EventEmitter {
private log_start: Date;
private log_end: Date;
private isContributionView: boolean | undefined;
private isGroupByResponse: boolean | undefined;
private isRatio: boolean | undefined;
private sourceIdType: number | string | undefined;
private totalFeatureCount: number = 0;
private currentFeatureCount: number = 0;
......@@ -80,6 +83,7 @@ class Ohsome2X extends EventEmitter {
this.targetFeatureType = await FeatureTypeFactory.create(this.config.target);
this.totalFeatureCount = await this.sourceFeatureType.getFeatureCount();
this.sourceIdType = await this.sourceFeatureType.getIdJsType();
process.on('SIGINT', async ()=>{
console.log('\nSIGINT signal received. Closing existing connections.');
......@@ -129,7 +133,7 @@ class Ohsome2X extends EventEmitter {
this.targetFeatureType = <PgFeatureType>this.targetFeatureType;
//create iteratively
//check curser type: number or string?
const cursorType = await this.sourceFeatureType.getIdJsTypeFromPg();
const cursorType = this.sourceIdType;
console.log("cursorType", cursorType);
let cursor;
......@@ -155,7 +159,7 @@ class Ohsome2X extends EventEmitter {
this.emit('progress', {type:'progress', processed: this.currentFeatureCount, total: this.totalFeatureCount, cursor: cursor, fetchSize: fetchSize, timestamp: new Date().toISOString()});
const sourceFeatureCollection: any = await this.sourceFeatureType.getFeaturesByCursorAndLimit(cursor, fetchSize);
let targetFeatureCollection;
let targetFeatureCollection: any;
featureCount = sourceFeatureCollection.features.length;
......@@ -242,39 +246,56 @@ class Ohsome2X extends EventEmitter {
}
ohsomeResults = ohsomeResults!;
this.isContributionView = this.checkIsContributionView(ohsomeResults.data);
//temporary until ohsome-api changes
this.harmonizeResponseStructure(ohsomeResults);
let responseFormat = this.checkResponseFormat (ohsomeResults.data);
this.isContributionView = responseFormat.isContributionView;
this.isRatio = responseFormat.isRatio;
this.harmonizeRatio_NaN_and_Infinity(ohsomeResults);
console.log('Start conversion ohsome-result to GeoJSON');
console.time('convert');
if (shouldCreateGeometry) {
if (typeof ohsomeResults.data == 'string') {
console.log('-----------------------------------------');
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log(ohsomeResults.data.substring(0, 500) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
} else {
if (typeof ohsomeResults.data == 'string') {
console.log('-----------------------------------------');
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log(ohsomeResults.data.substring(0, 500) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps);
}
console.timeEnd('convert');
//remove features where value = 0 or ratio = 0
if (!shouldWriteHorizontalTimestamps && !this.storeZeroValues) {
//remove features where value = 0
console.log('Remove Zeros');
console.time('removeZero');
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
console.timeEnd('removeZero');
if(!this.isRatio){
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
} else {
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValues(targetFeatureCollection, {
'value':0,
'value2': 0,
'ratio': null
});
}
}
console.time('computeValuePerArea');
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea) {
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea && !this.isRatio) {
targetFeatureCollection.features.forEach(
// @ts-ignore
......@@ -330,7 +351,16 @@ class Ohsome2X extends EventEmitter {
const ohsomeResults = await this.getOhsomeResults(this.config.ohsomeQuery);
console.timeEnd('query');
this.isContributionView = this.checkIsContributionView(ohsomeResults.data);
// temporary solution until ohsome-api changes
this.harmonizeResponseStructure(ohsomeResults);
let responseFormat = this.checkResponseFormat (ohsomeResults.data);
this.isContributionView = responseFormat.isContributionView;
this.isRatio = responseFormat.isRatio;
if(responseFormat.isRatio){
this.harmonizeRatio_NaN_and_Infinity(ohsomeResults)
}
console.log('Start conversion ohsomeJSON or csv to GeoJSON');
console.time('convert');
......@@ -340,7 +370,7 @@ class Ohsome2X extends EventEmitter {
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps, sourceFeatureCollection, transformToWebmercator);
} else {
......@@ -349,26 +379,33 @@ class Ohsome2X extends EventEmitter {
console.log(ohsomeResults.data.substring(0, 400) + '...');
console.log('-----------------------------------------');
}
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, shouldWriteHorizontalTimestamps);
targetFeatureCollection = GeoJsonFeatureType.fromOhsome(ohsomeResults.data, this.sourceIdType, shouldWriteHorizontalTimestamps);
}
console.timeEnd('convert');
//remove features where value = 0 or ratio = NaN or null
if (!shouldWriteHorizontalTimestamps && !this.storeZeroValues) {
//remove features where value = 0
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
console.log('Remove Zeros...');
if(!this.isRatio){
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValue(targetFeatureCollection, 'value', 0);
} else {
targetFeatureCollection = GeoJsonFeatureType.removeFeaturesByPropertyValues(targetFeatureCollection, {'value':0, value2:0, 'ratio': null});
}
}
console.time('computeValuePerArea');
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea) {
if (!shouldWriteHorizontalTimestamps && this.computeValuePerArea && !this.isRatio) {
console.time('computeValuePerArea');
targetFeatureCollection.features.forEach(
// @ts-ignore
(feature) => feature.properties["value_per_area"] = feature.properties.value / idAreaMap.get(feature.properties.id)
);
console.timeEnd('computeValuePerArea');
}
console.timeEnd('computeValuePerArea');
// console.log(JSON.stringify(targetFeatureCollection, undefined, 2));
await this.targetFeatureType.writeFeatures(targetFeatureCollection);
......@@ -410,9 +447,15 @@ class Ohsome2X extends EventEmitter {
await this.targetFeatureType.clusterTable('timestamp');
}
await this.targetFeatureType.createIndex('value');
if (this.computeValuePerArea) {
if(this.isRatio){
await this.targetFeatureType.createIndex('value2');
await this.targetFeatureType.createIndex('ratio');
}
if (this.computeValuePerArea && !this.isRatio) {
await this.targetFeatureType.createIndex('value_per_area');
}
}
......@@ -452,10 +495,13 @@ class Ohsome2X extends EventEmitter {
///////////// methods
async getOhsomeResults(ohsomeQuery: OhsomeQueryConfig): Promise<AxiosResponse> {
async getOhsomeResults(ohsomeQuery: OhsomeQueryConfig | OhsomeQueryRatioConfig): Promise<AxiosResponse> {
const isRatio = ohsomeQuery.queryType.includes("/ratio");
// set empty strings to null
const filter = (ohsomeQuery.filter != null && ohsomeQuery.filter.trim() != '')? ohsomeQuery.filter.trim() : undefined;
// for ratio requests
const filter2 = (isRatio && ohsomeQuery.filter2 != null && ohsomeQuery.filter2.trim() != '')? ohsomeQuery.filter2.trim() : undefined;
const format: OhsomeQueryConfigFormat = (ohsomeQuery.format != null && ohsomeQuery.format.trim() != '')? ohsomeQuery.format.trim() as 'csv'|'json' : undefined;
try {
......@@ -469,6 +515,7 @@ class Ohsome2X extends EventEmitter {
let dataObject: {} = {
bpolys: bpolyString,
filter: filter,
filter2: filter2,
time: ohsomeQuery.time,
showMetadata: true,
format: format
......@@ -507,11 +554,12 @@ class Ohsome2X extends EventEmitter {
}
checkIsContributionView(ohsomeGroupByBoundaryResponse: any): boolean {
checkResponseFormat(ohsomeGroupByBoundaryResponse: any): { isCSV:boolean; isGroupBy: boolean; isContributionView: boolean; isRatio: boolean } {
const isCSV = (typeof ohsomeGroupByBoundaryResponse == 'string');
let isContributionView: boolean = true;
let isContributionView: boolean;
let isRatio: boolean;
if (isCSV) {
......@@ -523,17 +571,72 @@ class Ohsome2X extends EventEmitter {
// check columnheaders for contributionview column names
const columns = lines[i].trim().split(";");
isContributionView = columns.includes("fromTimestamp") && columns.includes("toTimestamp");
// check isRatio: for non-grouped columnName is "ratio", for grouped response columnName is <someId>_ratio
isRatio = columns.includes("ratio") || columns.some((e: string)=> e.includes("_ratio"));
break;
}
}
} else {
//JSON Response
// check isContributionView
const hasFromTimestamps = ohsomeGroupByBoundaryResponse.groupByResult[0].result[0].fromTimestamp !== undefined;
const hasToTimestamps = ohsomeGroupByBoundaryResponse.groupByResult[0].result[0].toTimestamp !== undefined;
isContributionView = hasFromTimestamps && hasToTimestamps;
// check isRatio
isRatio = ohsomeGroupByBoundaryResponse.groupByResult[0].result[0].ratio !== undefined;
}
return isContributionView;
// return isContributionView;
return {
isCSV: isCSV,
isGroupBy: true,
isContributionView: isContributionView!,
isRatio: isRatio!
}
}
harmonizeResponseStructure(ohsomeResults: AxiosResponse): AxiosResponse {
// HARMONIZE result structure as long as api does not change see: https://github.com/GIScience/ohsome-api/issues/16
if (this.config.ohsomeQuery.format === 'json'){
//plain ungrouped result: rename ratioResult into result
if (ohsomeResults.data.ratioResult){
delete Object.assign(ohsomeResults.data, {['result']: ohsomeResults.data['ratioResult'] })['ratioResult'];
}
//RatioGroupByBoundaryResponse into standard groupByResponse
else if(ohsomeResults.data.groupByBoundaryResult){
delete Object.assign(ohsomeResults.data, {['groupByResult']: ohsomeResults.data['groupByBoundaryResult'] })['groupByBoundaryResult'];