Skip to content

Commit

Permalink
feat(frontend): aggregated risk map layer (risk hotspots)
Browse files Browse the repository at this point in the history
New raster layer showing aggregated risk values for:
- variables: "total value", "economic use", "population use", "total risk", EAD, EAEL.
- hazards: "none", cyclone, "all flooding".

Includes:
- New aggregated risk map layer and params in `src/state/layers/modules/risks`.
- New config in `src/config/risks`. Parameters defined in `src/config/risks/domains`.
- New sidebar controls in `src/sidebar/risks`.
- New legends and tooltips in `src/config/risks`.
  • Loading branch information
eatyourgreens committed Jul 1, 2024
1 parent 6d6d8f1 commit f8cf8e7
Show file tree
Hide file tree
Showing 15 changed files with 390 additions and 19 deletions.
19 changes: 0 additions & 19 deletions frontend/src/config/color-maps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,6 @@ import * as d3Scale from 'd3-scale';
import { ColorSpec } from 'lib/data-map/view-layers';
import { valueType } from 'lib/helpers';

export const RASTER_COLOR_MAPS = {
fluvial: {
scheme: 'blues',
range: [0, 10],
},
coastal: {
scheme: 'greens',
range: [0, 10],
},
surface: {
scheme: 'purples',
range: [0, 10],
},
cyclone: {
scheme: 'reds',
range: [0, 75],
},
};

function invertColorScale<T>(colorScale: (t: number) => T) {
return (i: number) => colorScale(1 - i);
}
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/config/interaction-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { HazardHoverDescription } from './hazards/HazardHoverDescription';
import { SolutionHoverDescription } from './solutions/SolutionHoverDescription';
import { RegionHoverDescription } from './regions/RegionHoverDescription';
import { DroughtHoverDescription } from './drought/DroughtHoverDescription';
import { RiskHoverDescription } from './risks/RiskHoverDescription';

export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
[
Expand All @@ -31,6 +32,14 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
pickMultiple: true,
},
],
[
'risks',
{
id: 'risks',
type: 'raster',
pickMultiple: false,
},
],
[
'regions',
{
Expand Down Expand Up @@ -70,6 +79,7 @@ export const tooltipLayers: Map<string, FC<{ hoveredObject: MapDataLayer }>> = n
>([
['assets', AssetHoverDescription],
['hazards', HazardHoverDescription],
['risks', RiskHoverDescription],
['regions', RegionHoverDescription],
['solutions', SolutionHoverDescription],
['drought', DroughtHoverDescription],
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/config/risks/RiskHoverDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { FC } from 'react';

import { InteractionTarget, RasterTarget } from 'state/interactions/use-interactions';
import { RasterHoverDescription } from 'map/tooltip/content/RasterHoverDescription';

import { RISKS_METADATA, RISKS_COLOR_MAPS } from './metadata';

export const RiskHoverDescription: FC<{ hoveredObject: InteractionTarget<RasterTarget> }> = ({
hoveredObject,
}) => {
const { target, viewLayer } = hoveredObject;

const { label, dataUnit } = RISKS_METADATA[viewLayer.id];
const { scheme, range } = RISKS_COLOR_MAPS[viewLayer.id];
return (
<RasterHoverDescription
color={target.color}
label={label}
dataUnit={dataUnit}
scheme={scheme}
range={range}
/>
);
};
13 changes: 13 additions & 0 deletions frontend/src/config/risks/RiskLegend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FC } from 'react';

import { RasterLegend } from 'map/legend/RasterLegend';
import { ViewLayer } from 'lib/data-map/view-layers';

import { RISKS_COLOR_MAPS, RISKS_METADATA } from './metadata';

export const RiskLegend: FC<{ viewLayer: ViewLayer }> = ({ viewLayer }) => {
const { id } = viewLayer;
const { label, dataUnit } = RISKS_METADATA[id];
const { scheme, range } = RISKS_COLOR_MAPS[id];
return <RasterLegend label={label} dataUnit={dataUnit} scheme={scheme} range={range} />;
};
66 changes: 66 additions & 0 deletions frontend/src/config/risks/domains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { DataParamGroupConfig } from 'lib/controls/data-params';

export interface RiskParams {
hazard: string;
returnPeriod: number;
epoch: number;
rcp: string;
confidence: string | number;
}

/*
Default parameter ranges for each hazard type.
These are used to define ranges for input controls in the sidebar.
*/
const hazardParamDomains = {
none: {
returnPeriod: [0],
epoch: [2010],
rcp: ['baseline'],
confidence: ['None'],
},
cyclone: {
returnPeriod: [0],
epoch: [2010],
rcp: ['baseline'],
confidence: ['None'],
},
fluvial: {
returnPeriod: [0],
epoch: [2010],
rcp: ['baseline'],
confidence: ['None'],
},
};

export const RISK_DOMAINS: DataParamGroupConfig<RiskParams> = {
/*
Default parameter ranges for each risk type.
*/
paramDomains: {
hazard: ['none', 'cyclone', 'fluvial'],
returnPeriod: [0],
epoch: [2010],
rcp: ['baseline'],
confidence: ['None'],
},
/*
Default parameter values for each risk type.
*/
paramDefaults: {
hazard: 'none',
returnPeriod: 0,
epoch: 2010,
rcp: 'baseline',
confidence: 'None',
},
/*
Callback functions to define custom parameter ranges based on selected hazard etc.
*/
paramDependencies: {
rcp: ({ hazard }) => hazardParamDomains[hazard].rcp,
epoch: ({ hazard }) => hazardParamDomains[hazard].epoch,
returnPeriod: ({ hazard }) => hazardParamDomains[hazard].returnPeriod,
confidence: ({ hazard }) => hazardParamDomains[hazard].confidence,
},
};
63 changes: 63 additions & 0 deletions frontend/src/config/risks/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export const HAZARDS_METADATA = {
none: { label: 'None' },
cyclone: { label: 'Cyclone' },
fluvial: { label: 'All Flooding' },
};

export const HAZARDS = Object.keys(HAZARDS_METADATA);

export const RISKS_METADATA = {
totalValue: {
label: 'Total value',
dataUnit: '',
},
economicUse: {
label: 'Economic use',
dataUnit: '',
},
populationUse: {
label: 'Population use',
dataUnit: '',
},
totalRisk: {
label: 'Total risk',
dataUnit: '',
},
ead: {
label: 'Expected Annual Damages (EAD)',
dataUnit: '',
},
eael: {
label: 'Expected Annual Economic Losses (EAEL)',
dataUnit: '',
},
};

export const RISKS_COLOR_MAPS = {
totalValue: {
scheme: 'reds',
range: [0, 10],
},
economicUse: {
scheme: 'blues',
range: [0, 10],
},
populationUse: {
scheme: 'purples',
range: [0, 10],
},
totalRisk: {
scheme: 'greens',
range: [0, 10],
},
ead: {
scheme: 'oranges',
range: [0, 10],
},
eael: {
scheme: 'purples',
range: [0, 10],
},
};

export const RISKS = Object.keys(RISKS_METADATA);
87 changes: 87 additions & 0 deletions frontend/src/config/risks/risk-view-layer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { createElement } from 'react';
import GL from '@luma.gl/constants';
import { RiskParams } from 'config/risks/domains';

import { rasterTileLayer } from 'lib/deck/layers/raster-tile-layer';
import { ViewLayer } from 'lib/data-map/view-layers';
import { InteractionTarget, RasterTarget } from 'state/interactions/use-interactions';

import { RiskLegend } from './RiskLegend';
import { RiskHoverDescription } from './RiskHoverDescription';
import { RISKS_COLOR_MAPS } from './metadata';
import { RISK_SOURCE } from './source';

export function getRiskId<
F extends string, // risk variable
RP extends number,
RCP extends string,
E extends number,
C extends number | string,
>({
riskType,
hazard,
returnPeriod,
rcp,
epoch,
confidence,
}: {
riskType: F;
hazard: string;
returnPeriod: RP;
rcp: RCP;
epoch: E;
confidence: C;
}) {
return `${riskType}__${hazard}__rp_${returnPeriod}__rcp_${rcp}__epoch_${epoch}__conf_${confidence}` as const;
}

export function riskViewLayer(riskType: string, riskParams: RiskParams): ViewLayer {
const { hazard, returnPeriod, rcp, epoch, confidence } = riskParams;

const deckId = getRiskId({ riskType, hazard, returnPeriod, rcp, epoch, confidence });

return {
id: riskType,
group: 'risks',
spatialType: 'raster',
interactionGroup: 'risks',
params: { riskType, riskParams },
fn: ({ deckProps }) => {
const { scheme, range } = RISKS_COLOR_MAPS[riskType];
const dataURL = RISK_SOURCE.getDataUrl(
{
riskType,
riskParams: { hazard, returnPeriod, rcp, epoch, confidence },
},
{ scheme, range },
);

return rasterTileLayer(
{
textureParameters: {
[GL.TEXTURE_MAG_FILTER]: GL.LINEAR,
// [GL.TEXTURE_MAG_FILTER]: zoom < 12 ? GL.NEAREST : GL.NEAREST_MIPMAP_LINEAR,
},
opacity: riskType === 'cyclone' ? 0.6 : 1,
},
deckProps,
{
id: `${riskType}@${deckId}`, // follow the convention viewLayerId@deckLayerId
data: dataURL,
refinementStrategy: 'no-overlap',
},
);
},
renderLegend() {
return createElement(RiskLegend, {
key: riskType,
viewLayer: this,
});
},
renderTooltip(hover: InteractionTarget<RasterTarget>) {
return createElement(RiskHoverDescription, {
hoveredObject: hover,
});
},
};
}
12 changes: 12 additions & 0 deletions frontend/src/config/risks/source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const RISK_SOURCE = {
getDataUrl(
{ riskType, riskParams: { hazard, returnPeriod, rcp, epoch, confidence } },
{ scheme, range },
) {
const sanitisedRcp = rcp?.replace('.', 'x');
console.log({ riskType, hazard, returnPeriod, sanitisedRcp, epoch, confidence });

return `/raster/singleband/fluvial/100/baseline/2010/None/{z}/{x}/{y}.png?colormap=${scheme}&stretch_range=[${range[0]},${range[1]}]`;
return `/raster/singleband/${riskType}/${hazard}/${returnPeriod}/${sanitisedRcp}/${epoch}/${confidence}/{z}/{x}/{y}.png?colormap=${scheme}&stretch_range=[${range[0]},${range[1]}]`;
},
};
1 change: 1 addition & 0 deletions frontend/src/config/sections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const SECTIONS_CONFIG: Record<string, { styles?: Record<string, StyleSele
styles: DROUGHT_STYLES,
},
hazards: {},
risks: {},
buildings: {
styles: BUILDING_STYLES,
},
Expand Down
1 change: 1 addition & 0 deletions frontend/src/config/view-layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const VIEW_LAYERS = [
'terrestrial',
'marine',
'hazards',
'risks',
'buildings',
'networks',
'droughtOptions',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/sidebar/SidebarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { NetworksSection } from './networks/NetworksSection';
import { RegionsSection } from './regions/RegionsSection';
import { MarineSection } from './solutions/MarineSection';
import { TerrestrialSection } from './solutions/TerrestrialSection';
import { RisksSection } from './risks/RisksSection';
import { ErrorBoundary } from 'lib/react/ErrorBoundary';
import { MobileTabContentWatcher } from 'pages/map/layouts/mobile/tab-has-content';

Expand All @@ -29,6 +30,7 @@ const SidebarContent: FC = () => {
return (
<>
<NetworksSection />
<RisksSection />
<HazardsSection />
<BuildingsSection />
<RegionsSection />
Expand Down
Loading

0 comments on commit f8cf8e7

Please sign in to comment.