Skip to content

Commit 604e94a

Browse files
authored
Merge pull request #1187 from cmu-delphi/sgratzl/latest
Fallback to latest in maps
2 parents 6e8dac5 + 43d88dc commit 604e94a

13 files changed

+170
-16
lines changed

src/blocks/HistoryLineChart.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,6 @@
383383
filterLine = signals.filter((_, i) => filterLineManaged[i]);
384384
}
385385
$: {
386-
console.log(filterLineManaged);
387386
updateFilteredLine(sensor, ageStratifictions, filterLineManaged);
388387
}
389388
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<script>
2+
import { formatDateYearDayOfWeekAbbr } from '../formats';
3+
import { getLevelInfo } from '../stores';
4+
5+
/**
6+
* @type {import("../data/sensor").Sensor}
7+
*/
8+
export let sensor;
9+
/**
10+
* @type {Date}
11+
*/
12+
export let date;
13+
/**
14+
* @type {import("../data/regions").RegionLevel}
15+
*/
16+
export let level;
17+
18+
/**
19+
* @type {import("../data/trend").SensorTrend }
20+
*/
21+
export let trend;
22+
23+
/**
24+
* two way binding
25+
*/
26+
export let suffix = '';
27+
28+
export let prefix = '*';
29+
30+
$: showWarning = trend.then((d) => {
31+
if (
32+
(d != null && (d.value == null || (d.date != null && d.date < date))) ||
33+
(d.date_value != null && d.date_value < date)
34+
) {
35+
suffix = '*';
36+
return d;
37+
}
38+
suffix = '';
39+
return null;
40+
});
41+
</script>
42+
43+
{#await showWarning then d}
44+
{#if d != null}
45+
<p>
46+
{prefix} The indicator "{sensor.name}" is not available for {formatDateYearDayOfWeekAbbr(date)} at the geographic level
47+
"{getLevelInfo(level).label}", yet. The data from {formatDateYearDayOfWeekAbbr(d.date ?? d.date_value)} is displayed
48+
instead.
49+
</p>
50+
{/if}
51+
{/await}

src/blocks/IndicatorWarning.svelte

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script>
2+
import { formatAPITime } from '../data';
23
import { formatDateYearDayOfWeekAbbr } from '../formats';
34
import { getLevelInfo } from '../stores';
45
@@ -22,6 +23,9 @@
2223
function checkSensorData(sensor, date, region) {
2324
return fetcher.fetch1Sensor1Region1DateDetails(sensor, region, date);
2425
}
26+
function switchDate() {
27+
date.set(sensor.timeFrame.max);
28+
}
2529
</script>
2630

2731
{#if !sensor.value.levels.includes(region.level)}
@@ -32,7 +36,11 @@
3236
{#await checkSensorData(sensor, date, region) then hasData}
3337
{#if !hasData}
3438
<div data-uk-alert class="uk-alert-warning">
35-
The indicator "{sensor.name}" is not available for {formatDateYearDayOfWeekAbbr(date.value)}, yet.
39+
The indicator "{sensor.name}" is not available for {formatDateYearDayOfWeekAbbr(date.value)}, yet. The latest
40+
known data is available on
41+
<a href="?date={formatAPITime(sensor.timeFrame.max)}" on:click={switchDate}
42+
>{formatDateYearDayOfWeekAbbr(sensor.timeFrame.max)}</a
43+
>.
3644
</div>
3745
{/if}
3846
{/await}

src/blocks/RegionCountyMap.svelte

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import DownloadMenu from '../components/DownloadMenu.svelte';
88
import RegionMapTooltip from './RegionMapTooltip.svelte';
99
import FullWidthWrapper from '../components/FullWidthWrapper.svelte';
10+
import IndicatorFallbackWarning from './IndicatorFallbackWarning.svelte';
1011
1112
/**
1213
* @type {import("../../stores/params").DateParam}
@@ -25,10 +26,15 @@
2526
*/
2627
export let fetcher;
2728
29+
/**
30+
* two way binding
31+
*/
32+
export let suffix = '';
33+
2834
$: spec = generateStateMapWithCountyDataSpec({
2935
...sensor.vegaSchemeDomain('county'),
3036
});
31-
$: data = fetcher.fetch1SensorNRegions1Date(sensor, 'county', date);
37+
$: data = fetcher.fetch1SensorNRegions1DateWithFallback(sensor, 'county', date);
3238
3339
function onClickHandler(evt) {
3440
const item = evt.detail.item;
@@ -61,3 +67,11 @@
6167
/>
6268
</div>
6369
</FullWidthWrapper>
70+
71+
<IndicatorFallbackWarning
72+
sensor={sensor.value}
73+
level="county"
74+
date={date.value}
75+
trend={data.then((rows) => rows[0])}
76+
bind:suffix
77+
/>

src/blocks/RegionMap.svelte

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import DownloadMenu from '../components/DownloadMenu.svelte';
88
import FullWidthWrapper from '../components/FullWidthWrapper.svelte';
99
import RegionMapTooltip from './RegionMapTooltip.svelte';
10+
import IndicatorFallbackWarning from './IndicatorFallbackWarning.svelte';
1011
1112
/**
1213
* @type {import("../../stores/params").DateParam}
@@ -59,20 +60,25 @@
5960
const hasCounty = sensor.value.levels.includes('county');
6061
if (region.level === 'state' && hasCounty) {
6162
const counties = getCountiesOfState(region.value);
62-
const countyData = fetcher.fetch1SensorNRegions1Date(
63+
const countyData = fetcher.fetch1SensorNRegions1DateWithFallback(
6364
sensor,
6465
[...counties, getInfoByName(`${region.id}000`)],
6566
date,
6667
);
67-
const stateData = fetcher.fetch1SensorNRegions1Date(sensor, 'state', date);
68+
const stateData = fetcher.fetch1SensorNRegions1DateWithFallback(sensor, 'state', date);
6869
return Promise.all([countyData, stateData]).then((r) => r.flat());
6970
}
7071
if (region.level === 'county' && hasCounty) {
7172
return fetcher.fetch1SensorNRegions1Date(sensor, 'county', date);
7273
}
73-
return fetcher.fetch1SensorNRegions1Date(sensor, 'state', date);
74+
return fetcher.fetch1SensorNRegions1DateWithFallback(sensor, 'state', date);
7475
}
7576
77+
$: fallbackLevel =
78+
region.level === 'county' || (region.level === 'state' && sensor.value.levels.includes('county'))
79+
? 'county'
80+
: 'state';
81+
7682
function generateFileName(sensor, date, region) {
7783
const hasCounty = sensor.value.levels.includes('county');
7884
let regionName = region.level === 'nation' || !hasCounty ? 'US States' : 'US Counties';
@@ -115,3 +121,19 @@
115121
<DownloadMenu {vegaRef} {data} {sensor} absolutePos {fileName} />
116122
</div>
117123
</FullWidthWrapper>
124+
125+
<IndicatorFallbackWarning
126+
sensor={sensor.value}
127+
level={fallbackLevel}
128+
date={date.value}
129+
trend={data.then((rows) => rows[0])}
130+
/>
131+
{#if fallbackLevel === 'county'}
132+
<IndicatorFallbackWarning
133+
prefix=""
134+
sensor={sensor.value}
135+
level={'state'}
136+
date={date.value}
137+
trend={data.then((rows) => rows.find((d) => d.level === 'state'))}
138+
/>
139+
{/if}

src/blocks/RegionMapWrapper.svelte

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*/
2323
export let fetcher;
2424
25+
let suffix = '';
26+
2527
$: hasCounties = sensor.value.levels.includes('county');
2628
let showChoropleth = false;
2729
</script>
@@ -34,11 +36,16 @@
3436
Click on a state to explore further
3537
</p>
3638
<div class="toggle-center-wrapper">
37-
<Toggle bind:checked={showChoropleth} before="Beehive Grid"><span>Choropleth Map</span></Toggle>
39+
<Toggle bind:checked={showChoropleth} before="Beehive Grid"
40+
><span>
41+
Choropleth Map
42+
{#if showChoropleth && hasCounties}{suffix}{/if}</span
43+
></Toggle
44+
>
3845
</div>
3946
{#if showChoropleth}
4047
{#if hasCounties}
41-
<RegionCountyMap {region} {date} {sensor} {fetcher} />
48+
<RegionCountyMap {region} {date} {sensor} {fetcher} bind:suffix />
4249
{:else}
4350
<RegionMap {region} {date} {sensor} {fetcher} />
4451
{/if}
@@ -64,7 +71,7 @@
6471
}
6572
6673
.toggle-center-wrapper :global(span) {
67-
width: 8em;
74+
width: 9em;
6875
}
6976
7077
.ux-hint {

src/components/KPI.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
export let sub = null;
1010
1111
export let loading = false;
12+
13+
export let asterisk = false;
1214
</script>
1315

1416
<span class="text" class:loading>{text || 'N/A'}</span>
1517
{#if sub}<span class="fraction">{sub}</span>{/if}
18+
{#if asterisk}<span class="text">*</span>{/if}
1619

1720
<style>
1821
.text {

src/components/KPIChange.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
export let value = null;
99
export let loading = false;
10+
export let asterisk = false;
1011
1112
$: scaled = value != null && !Number.isNaN(value) ? value * 100 : null;
1213
@@ -17,5 +18,5 @@
1718
{#if scaled == null}
1819
<KPI text={base.toString()} {loading} />
1920
{:else}
20-
<KPI text={sign(base, (v) => v.toLocaleString(), true)} sub={`.${fraction}%`} {loading} />
21+
<KPI text={sign(base, (v) => v.toLocaleString(), true)} sub={`.${fraction}%`} {loading} {asterisk} />
2122
{/if}

src/components/KPIValue.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
1212
export let loading = false;
1313
14+
export let asterisk = false;
15+
1416
$: scaled = value != null && !Number.isNaN(value) ? value * factor : null;
1517
$: digitsPow = Math.pow(10, digits);
1618
$: roundedValue = Math.round(Math.abs(scaled) * digitsPow);
@@ -20,4 +22,4 @@
2022
$: fraction = !loading && hasFraction ? roundedValue % digitsPow : 0;
2123
</script>
2224

23-
<KPI text={base.toLocaleString()} sub={hasFraction ? `.${fraction}` : null} {loading} />
25+
<KPI text={base.toLocaleString()} sub={hasFraction ? `.${fraction}` : null} {loading} {asterisk} />

src/modes/summary/CasesOverview.svelte

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script>
22
import KPIValue from '../../components/KPIValue.svelte';
33
import KPIChange from '../../components/KPIChange.svelte';
4-
import { SensorParam } from '../../stores/params';
4+
import { DateParam, SensorParam } from '../../stores/params';
55
import { formatDateDayOfWeek } from '../../formats';
66
import SensorUnit from '../../components/SensorUnit.svelte';
77
import IndicatorAnnotations from '../../components/IndicatorAnnotations.svelte';
88
import MaxDateHint from '../../blocks/MaxDateHint.svelte';
99
import IndicatorWarning from '../../blocks/IndicatorWarning.svelte';
1010
import { defaultDeathSensor, defaultCasesSensor, defaultHospitalSensor, metaDataManager } from '../../stores';
11+
import IndicatorFallbackWarning from '../../blocks/IndicatorFallbackWarning.svelte';
1112
1213
/**
1314
* @type {import("../../stores/params").DateParam}
@@ -26,9 +27,18 @@
2627
$: DEATHS = new SensorParam($defaultDeathSensor, $metaDataManager);
2728
$: HOSPITAL_ADMISSION = new SensorParam($defaultHospitalSensor, $metaDataManager);
2829
30+
function fetchFallback(fetcher, sensor, region, trend) {
31+
return trend.then((t) => {
32+
if (t && t.value != null) {
33+
return t;
34+
}
35+
return fetcher.fetch1Sensor1Region1DateTrend(sensor, region, DateParam.box(sensor.timeFrame.max));
36+
});
37+
}
38+
2939
$: trends = fetcher.fetchNSensors1Region1DateTrend([CASES, HOSPITAL_ADMISSION, DEATHS], region, date);
3040
$: casesTrend = trends[0];
31-
$: hospitalTrend = trends[1];
41+
$: hospitalTrend = fetchFallback(fetcher, HOSPITAL_ADMISSION, region, trends[1]);
3242
$: deathTrend = trends[2];
3343
</script>
3444

@@ -61,7 +71,7 @@
6171
{#await hospitalTrend}
6272
<KPIValue value={null} loading />
6373
{:then d}
64-
<KPIValue value={d ? d.value : null} />
74+
<KPIValue value={d ? d.value : null} asterisk={d != null && (d.value == null || d.date < date.value)} />
6575
{/await}
6676
</div>
6777
<div class="sub">
@@ -101,7 +111,10 @@
101111
{#await hospitalTrend}
102112
<KPIChange value={null} loading />
103113
{:then d}
104-
<KPIChange value={d && d.value != null && !Number.isNaN(d.value) ? d.change : null} />
114+
<KPIChange
115+
value={d && d.value != null && !Number.isNaN(d.value) ? d.change : null}
116+
asterisk={d != null && (d.value == null || d.date < date.value)}
117+
/>
105118
{/await}
106119
</div>
107120
<div class="sub">Relative change to 7 days ago</div>
@@ -117,3 +130,5 @@
117130
<div class="sub">Relative change to 7 days ago</div>
118131
</div>
119132
</div>
133+
134+
<IndicatorFallbackWarning trend={hospitalTrend} date={date.value} level={region.level} sensor={HOSPITAL_ADMISSION} />

0 commit comments

Comments
 (0)