diff --git a/src/app/Services/API/Requests/index.ts b/src/app/Services/API/Requests/index.ts index 3cd5fb0..6b0d00b 100644 --- a/src/app/Services/API/Requests/index.ts +++ b/src/app/Services/API/Requests/index.ts @@ -61,29 +61,93 @@ export class RequestApi extends Http { )}&longitude=${lng.toFixed(4)}`, ); - public getMultiTimeseriesV2 = (id: string[], lat: number, lng: number) => { - const ret: Promise>[] = []; - for (let ids of id) { - ret.push(this.getTimeseriesV2(ids, lat, lng)); + private cartesianProduct = (input, current?) => { + if (!input || !input.length) { + return []; + } + + var head = input[0]; + var tail = input.slice(1); + var output: any[] = []; + + for (var key in head) { + for (var i = 0; i < head[key].length; i++) { + var newCurrent = this.copy(current); + newCurrent[key] = head[key][i]; + if (tail.length) { + var productOfTail = this.cartesianProduct(tail, newCurrent); + output = output.concat(productOfTail); + } else output.push(newCurrent); + } } - return Promise.all(ret); + return output; + }; + + private copy: any = obj => { + const res: any = {}; + for (const p in obj) res[p] = obj[p]; + return res; }; + public createIds(pattern: string, items: any) { + let ret: string[] = []; + let titems: any[] = []; + + for (let k of Object.keys(items)) { + titems.push({ [k]: items[k] }); + } + const combs = this.cartesianProduct(titems); + for (const c of combs) { + for (let j of Object.keys(c)) { + ret.push(pattern.replaceAll('{' + j + '}', c[j])); + } + } + return ret; + } public getTimeseriesV2 = ( + ids: string[], + lat: number, + lng: number, + withStation: boolean = true, + ) => { + const ret: Promise>[] = []; + for (let id of ids) { + ret.push(this.getTimeserieV2(id, lat, lng, withStation)); + if (withStation) { + withStation = false; + } + } + return Promise.all(ret).then(x => { + return this.merge.apply(this, x); + }); + }; + + private merge = (...objs) => + [...objs].reduce( + (acc, obj) => + Object.keys(obj).reduce((a, k) => { + acc[k] = acc.hasOwnProperty(k) + ? [].concat(acc[k]).concat(obj[k]) + : obj[k]; + return acc; + }, {}), + {}, + ); + + public getTimeserieV2 = ( measure: any, lat: number, lng: number, withStation: boolean = true, ) => { - measure = 'tas_annual_absolute_model_ensemble-rcp26'; let url = `https://arpav.geobeyond.dev/api/v2/coverages/time-series/${measure}?coords=POINT(${lng.toFixed( 4, )} ${lat.toFixed( 4, - )})&datetime=..%2F..&include_coverage_data=true&coverage_data_smoothing=NO_SMOOTHING&coverage_data_smoothing=LOESS_SMOOTHING&coverage_data_smoothing=MOVING_AVERAGE_11_YEARS&include_coverage_uncertainty=true&include_coverage_related_data=true&`; + )})&datetime=..%2F..&include_coverage_data=true&coverage_data_smoothing=NO_SMOOTHING&coverage_data_smoothing=LOESS_SMOOTHING&coverage_data_smoothing=MOVING_AVERAGE_11_YEARS&include_coverage_uncertainty=true&include_coverage_related_data=true`; if (withStation) { - url += `include_observation_data=true&observation_data_smoothing=NO_SMOOTHING&observation_data_smoothing=MOVING_AVERAGE_5_YEARS`; + url += `&include_observation_data=true&observation_data_smoothing=NO_SMOOTHING&observation_data_smoothing=MOVING_AVERAGE_5_YEARS`; } return this.instance.get(url); diff --git a/src/app/components/TimeSeriesDialog/TSDataContainer.tsx b/src/app/components/TimeSeriesDialog/TSDataContainer.tsx index d17cba6..0128678 100644 --- a/src/app/components/TimeSeriesDialog/TSDataContainer.tsx +++ b/src/app/components/TimeSeriesDialog/TSDataContainer.tsx @@ -133,23 +133,26 @@ const TSDataContainer = (props: TSDataContainerProps) => { ), ); // console.log(baseSelection) - const ids = models - .filter(x => x) - .map(model => { - return scenarios.map(scenario => { - const input = { - ...baseSelection, - data_series: 'yes', - forecast_model: model, - time_window: null, - scenario, - }; - const resItem = getItemByFilters(layers, input); - // @ts-ignore - return resItem ? resItem?.id : null; - }); - }) - .flat(); + //const ids = models + // .filter(x => x) + // .map(model => { + // return scenarios.map(scenario => { + // const input = { + // ...baseSelection, + // data_series: 'yes', + // forecast_model: model, + // time_window: null, + // scenario, + // }; + // const resItem = getItemByFilters(layers, input); + // // @ts-ignore + // return resItem ? resItem?.id : null; + // }); + // }) + // .flat(); + const ids = api.createIds('tas_annual_absolute_model_ensemble-{scenario}', { + scenario: ['rcp26', 'rcp45', 'rcp85'], + }); setIds(ids); api .getTimeseriesV2(ids, latLng.lat, latLng.lng, true) @@ -179,10 +182,16 @@ const TSDataContainer = (props: TSDataContainerProps) => { const { t } = useTranslation(); + let nfltr = 'MOVING_AVERAGE'; + let sfltr = 'NO_SMOOTHING'; + let mfltr = 'model_ensemble'; + const getLegend = () => { //TODO names lookup const legend = timeseries ?.filter(x => x.name.indexOf('_BOUND_') < 0) + .filter(x => x.name.indexOf(nfltr) >= 0) + .filter(x => x.name.indexOf(mfltr) >= 0 || x.name.length < 20) .map(item => item.name); return legend; }; @@ -192,7 +201,10 @@ const TSDataContainer = (props: TSDataContainerProps) => { let ret = {}; const legend = timeseries ?.filter(x => x.name.indexOf('_BOUND_') < 0) - .map(x => (ret[x.name] = x.info.smoothing === 'no_smoothing')); + .filter(x => x.name.indexOf(nfltr) >= 0) + .filter(x => x.name.indexOf(mfltr) >= 0 || x.name.length < 20) + .map(x => (ret[x.name] = true)); + //.map(x => (ret[x.name] = x.info.smoothing === 'no_smoothing')); return ret; }; @@ -223,7 +235,11 @@ const TSDataContainer = (props: TSDataContainerProps) => { }; const getChartData = (item, series) => { - if (item.name.indexOf('_BOUND_') >= 0) { + if ( + item.name.indexOf('_BOUND_') >= 0 && + item.name.indexOf(nfltr) < 0 && + item.name.indexOf(mfltr) < 0 + ) { if (item.name.indexOf('UPPER') >= 0) { let ret: number[] = []; let lbitem = series.filter( @@ -234,6 +250,16 @@ const TSDataContainer = (props: TSDataContainerProps) => { ret.push(item.values[i].value - lbitem[0].values[i].value); } return ret; + } else if (item.name.indexOf('LOWER') >= 0) { + let ret: number[] = []; + let lbitem = series.filter( + x => x.name === item.name.replace('LOWER', 'UPPER'), + ); + if (lbitem) + for (let i in item.values) { + ret.push(item.values[i].value - lbitem[0].values[i].value); + } + return ret; } } return item.values.map(x => x.value); @@ -270,7 +296,13 @@ const TSDataContainer = (props: TSDataContainerProps) => { return cats[0]; }; - const seriesObj = timeseries?.map(item => ({ + const pseriesObj = timeseries?.filter(item => { + return ( + //item.name.indexOf('_BOUND_') >= 0 && + item.name.indexOf(nfltr) >= 0 && item.name.indexOf(mfltr) >= 0 + ); + }); + const seriesObj = pseriesObj.map(item => ({ name: item.name .replace('_UNCERTAINTY_LOWER_BOUND_', '') .replace('_UNCERTAINTY_UPPER_BOUND_', ''), @@ -411,6 +443,9 @@ const TSDataContainer = (props: TSDataContainerProps) => { }, dataZoom: [ { + start: localStart, + end: localEnd, + realtime: false, type: 'slider', height: 40, }, @@ -487,7 +522,24 @@ const TSDataContainer = (props: TSDataContainerProps) => { setLocalStartYear(getXAxis()[0]); setLocalEndYear(getXAxis().slice(-1)[0]); } - }, [timeseries]); + }, [getXAxis, timeseries]); + + const setSensorSmoothing = v => { + if (v == 0) { + sfltr = 'NO_SMOOTHING'; + } else if (v == 1) { + sfltr = 'MOVING_AVERAGE'; + } + }; + const setModelSmoothing = v => { + if (v == 0) { + nfltr = 'NO_SMOOTHING'; + } else if (v == 1) { + nfltr = 'MOVING_AVERAGE'; + } else if (v == 2) { + nfltr = 'LOESS'; + } + }; return ( @@ -536,8 +588,18 @@ const TSDataContainer = (props: TSDataContainerProps) => { - - {t('app.map.timeSeriesDialog.smoothing')} + + {t('app.map.timeSeriesDialog.modelSmoothing')} { marks min={0} max={2} + //@ts-ignore + onChange={e => setModelSmoothing(e.target?.value)} /> - - {t('app.map.timeSeriesDialog.smoothing')} + + {t('app.map.timeSeriesDialog.sensorSmoothing')} { marks min={0} max={1} + //@ts-ignore + onChange={e => setSensorSmoothing(e.target?.value)} /> @@ -584,70 +660,68 @@ const TSDataContainer = (props: TSDataContainerProps) => { dataZoom: dataZoomHandle, }} /> - { - setLocalStartYear(event?.target?.value); - const startValue = chartRef.current - .getEchartsInstance() - .getOption() - .xAxis[0].data.findIndex( - (item: any) => item === event?.target?.value, - ); - const endValue = chartRef.current - .getEchartsInstance() - .getOption() - .xAxis[0].data.findIndex((item: any) => item === localEndYear); - //console.log('[STF]', startValue, endValue); - if (startValue !== -1 && endValue !== -1) { - chartRef.current.getEchartsInstance().dispatchAction({ - type: 'dataZoom', - dataZoomIndex: 0, - startValue: startValue, - endValue: endValue, - }); - } - }} - /> - { - setLocalEndYear(event?.target?.value); - const startValue = chartRef.current - .getEchartsInstance() - .getOption() - .xAxis[0].data.findIndex( - (item: any) => item === localStartYear, - ); - const endValue = chartRef.current - .getEchartsInstance() - .getOption() - .xAxis[0].data.findIndex( - (item: any) => item === event?.target?.value, - ); - //console.log('[STF]', startValue, endValue); - if (startValue !== -1 && endValue !== -1) { - chartRef.current.getEchartsInstance().dispatchAction({ - type: 'dataZoom', - dataZoomIndex: 0, - startValue: startValue, - endValue: endValue, - }); - } - }} - /> ) : ( )} + { + setLocalStartYear(event?.target?.value); + const startValue = chartRef.current + .getEchartsInstance() + .getOption() + .xAxis[0].data.findIndex( + (item: any) => item === event?.target?.value, + ); + const endValue = chartRef.current + .getEchartsInstance() + .getOption() + .xAxis[0].data.findIndex((item: any) => item === localEndYear); + //console.log('[STF]', startValue, endValue); + if (startValue !== -1 && endValue !== -1) { + chartRef.current.getEchartsInstance().dispatchAction({ + type: 'dataZoom', + dataZoomIndex: 0, + startValue: startValue, + endValue: endValue, + }); + } + }} + /> + { + setLocalEndYear(event?.target?.value); + const startValue = chartRef.current + .getEchartsInstance() + .getOption() + .xAxis[0].data.findIndex((item: any) => item === localStartYear); + const endValue = chartRef.current + .getEchartsInstance() + .getOption() + .xAxis[0].data.findIndex( + (item: any) => item === event?.target?.value, + ); + //console.log('[STF]', startValue, endValue); + if (startValue !== -1 && endValue !== -1) { + chartRef.current.getEchartsInstance().dispatchAction({ + type: 'dataZoom', + dataZoomIndex: 0, + startValue: startValue, + endValue: endValue, + }); + } + }} + /> ); }; diff --git a/src/locales/it/translation.json b/src/locales/it/translation.json index 0ad9274..1c5b180 100644 --- a/src/locales/it/translation.json +++ b/src/locales/it/translation.json @@ -55,7 +55,8 @@ "app.map.timeSeriesDialog.movingAverage": "Media mobile 11 anni", "app.map.timeSeriesDialog.noSmoothing": "Nessun livellamento", "app.map.timeSeriesDialog.loess": "LOESS", - "app.map.timeSeriesDialog.smoothing": "Elaborazione", + "app.map.timeSeriesDialog.modelSmoothing": "Aggregazione Modelli", + "app.map.timeSeriesDialog.sensorSmoothing": "Aggregazione Sensori", "app.map.timeSeriesDialog.saveAsImage": "Salva immagine", "app.map.timeSeriesDialog.xUnit": "Anno", "app.map.timeSeriesDialog.DLTimeSeries": "Scarica serie temporale",