From 8baf276913d2720f480cd237b6cadd7bf4ec0b63 Mon Sep 17 00:00:00 2001 From: Rostyslav Zatserkovnyi Date: Wed, 14 Aug 2024 17:11:16 +0300 Subject: [PATCH 1/3] Improve handling for URL-based signals & support COVIDcast EpiWeeks (#53) * Improve handling for URL-based signals --- src/api/EpiData.ts | 25 ++++++++++++------- .../dialogs/dataSources/COVIDcast.svelte | 6 ++++- src/data/data.ts | 1 + src/deriveLinkDefaults.ts | 18 ++++++++++--- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/api/EpiData.ts b/src/api/EpiData.ts index 80e91fb..866063e 100644 --- a/src/api/EpiData.ts +++ b/src/api/EpiData.ts @@ -150,13 +150,17 @@ export function loadDataSet( }); } -export function fetchCOVIDcastMeta(): Promise<{ geo_type: string; signal: string; data_source: string }[]> { +export function fetchCOVIDcastMeta(): Promise< + { geo_type: string; signal: string; data_source: string; time_type?: string }[] +> { const url = new URL(ENDPOINT + `/covidcast_meta/`); url.searchParams.set('format', 'json'); - return fetchImpl<{ geo_type: string; signal: string; data_source: string }[]>(url).catch((error) => { - console.warn('failed fetching data', error); - return []; - }); + return fetchImpl<{ geo_type: string; signal: string; data_source: string; time_type?: string }[]>(url).catch( + (error) => { + console.warn('failed fetching data', error); + return []; + }, + ); } export function importCDC({ locations, auth }: { locations: string; auth?: string }): Promise { @@ -182,17 +186,20 @@ export function importCOVIDcast({ }: { data_source: string; signal: string; - time_type?: 'day'; + time_type?: string; geo_type: string; geo_value: string; }): Promise { - const title = `[API] Delphi CODIDcast: ${geo_value} ${signal} (${data_source})`; + const title = `[API] COVIDcast: ${data_source}:${signal} (${geo_type}:${geo_value})`; return loadDataSet( title, 'covidcast', { - time_type: 'day', - time_values: epiRange(firstDate.covidcast, currentDate), + time_type: time_type, + time_values: + time_type === 'day' + ? epiRange(firstDate.covidcast, currentDate) + : epiRange(firstEpiWeek.covidcast, currentEpiWeek), }, { data_source, signal, time_type, geo_type, geo_value }, ['value', 'stderr', 'sample_size'], diff --git a/src/components/dialogs/dataSources/COVIDcast.svelte b/src/components/dialogs/dataSources/COVIDcast.svelte index bfbeeff..10e9699 100644 --- a/src/components/dialogs/dataSources/COVIDcast.svelte +++ b/src/components/dialogs/dataSources/COVIDcast.svelte @@ -47,7 +47,11 @@ }); export function importDataSet() { - return importCOVIDcast({ data_source, signal, geo_type, geo_value }); + return fetchCOVIDcastMeta().then((res) => { + const meta = res.filter((row) => row.data_source === data_source && row.signal === signal); + const time_type = meta[0].time_type; + return importCOVIDcast({ data_source, signal, geo_type, geo_value, time_type }); + }); } diff --git a/src/data/data.ts b/src/data/data.ts index 549988b..f5ad543 100644 --- a/src/data/data.ts +++ b/src/data/data.ts @@ -385,6 +385,7 @@ export const firstEpiWeek = { quidel: 201535, sensors: 201030, nowcast: 200901, + covidcast: 202001, }; // first available date for each data source diff --git a/src/deriveLinkDefaults.ts b/src/deriveLinkDefaults.ts index e7ab79e..38f35a8 100644 --- a/src/deriveLinkDefaults.ts +++ b/src/deriveLinkDefaults.ts @@ -158,9 +158,21 @@ export function initialLoader(datasets: ILinkConfig['datasets']) { return Promise.all(resolvedDataSets).then((data) => { const cleaned = data.filter((d): d is DataSet => d != null); cleaned.forEach((d) => { - if (d.params && !Array.isArray(d.params) && d.params._endpoint && d.params.regions) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - d.title = `${d.params._endpoint} | ${d.params.regions} | ${d.title}`; + if (d.params && !Array.isArray(d.params) && d.params._endpoint) { + /* eslint-disable @typescript-eslint/restrict-template-expressions */ + const col_name = d.title; + d.title = `${d.params._endpoint}`; + if (d.params.data_source && d.params.signal) { + d.title += ` > ${d.params.data_source}:${d.params.signal}`; + } + if (d.params.geo_type && d.params.geo_value) { + d.title += ` > ${d.params.geo_type}:${d.params.geo_value}`; + } + if (d.params.regions) { + d.title += ` > ${d.params.regions}`; + } + d.title += ` > ${col_name}`; + /* eslint-enable @typescript-eslint/restrict-template-expressions */ } add(d); }); From 430a6b39b6835d615e2776f943b54a6c0227a14e Mon Sep 17 00:00:00 2001 From: Rostyslav Zatserkovnyi Date: Thu, 22 Aug 2024 20:35:33 +0300 Subject: [PATCH 2/3] Improve top panel elements & autofit mode (#54) * Tour changes --- src/components/Chart.svelte | 7 +- src/components/TopMenu.svelte | 127 ++++++++---------- src/components/chartUtils.ts | 7 +- src/components/dialogs/ImportAPIDialog.svelte | 4 + src/components/tree/TreeLeafNode.svelte | 7 +- src/deriveLinkDefaults.ts | 2 - src/store.ts | 3 +- src/tour.ts | 124 +++++++++-------- 8 files changed, 139 insertions(+), 142 deletions(-) diff --git a/src/components/Chart.svelte b/src/components/Chart.svelte index bf42e96..52ed214 100644 --- a/src/components/Chart.svelte +++ b/src/components/Chart.svelte @@ -134,7 +134,9 @@ setNavMode(NavMode.zoom); } } - if (navMode == NavMode.crop) { + if (navMode == NavMode.autofit) { + navMode = NavMode.pan; + } else if (navMode == NavMode.crop) { navBox = { x: m.x, y: m.y, w: 0, h: 0 }; } } @@ -268,6 +270,9 @@ dx = ((xMax - xMin) / 2) * fx; dy = ((yMax - yMin) / 2) * fy; setViewport(xMin - dx, yMin - dy, xMax - dx, yMax - dy); + if (navMode == NavMode.autofit) { + navMode = NavMode.pan; + } } function zoom(x: number, y: number): void { diff --git a/src/components/TopMenu.svelte b/src/components/TopMenu.svelte index c294cc6..878a698 100644 --- a/src/components/TopMenu.svelte +++ b/src/components/TopMenu.svelte @@ -10,12 +10,11 @@ faLink, faPaintBrush, faQuestion, - faReceipt, faSearchPlus, - faUpDown, + faShuffle, } from '@fortawesome/free-solid-svg-icons'; import Fa from 'svelte-fa'; - import { activeDatasets, isShowingPoints, navMode, randomizeColors, reset, scaleMean, autoFit } from '../store'; + import { activeDatasets, isShowingPoints, navMode, randomizeColors, reset, scaleMean } from '../store'; import type { IChart } from '../store'; import { NavMode } from './chartUtils'; import { tour } from '../tour'; @@ -55,6 +54,9 @@ chart.fitData(true); } break; + case 'a': + $navMode = NavMode.autofit; + break; case 'p': $navMode = NavMode.pan; break; @@ -70,9 +72,6 @@ case 's': $isShowingPoints = !$isShowingPoints; break; - case 'a': - $autoFit = !$autoFit; - break; case 'h': tour.cancel(); tour.start(); @@ -82,35 +81,57 @@