diff --git a/api/app/googleflood.py b/api/app/googleflood.py index 286c36257..8b2b20ca8 100644 --- a/api/app/googleflood.py +++ b/api/app/googleflood.py @@ -53,6 +53,7 @@ def make_google_floods_request(url, method="get", data=None, retries=1, timeout= raise HTTPException( status_code=500, detail="Error fetching data from Google API" ) + return response_data diff --git a/frontend/src/components/Common/Chart/index.tsx b/frontend/src/components/Common/Chart/index.tsx index 4779cf1c7..c7d43c518 100644 --- a/frontend/src/components/Common/Chart/index.tsx +++ b/frontend/src/components/Common/Chart/index.tsx @@ -32,14 +32,14 @@ function downloadChartPng(ref: React.RefObject, filename: string) { const useStyles = makeStyles(() => ({ firstIcon: { position: 'absolute', - top: 0, - right: 0, + top: '8px', + right: '0rem', padding: '0.25rem', }, secondIcon: { position: 'absolute', - top: 0, - right: '2rem', + top: '8px', + right: '1.75rem', padding: '0.25rem', }, })); @@ -58,6 +58,7 @@ export type ChartProps = { iconStyles?: React.CSSProperties; downloadFilenamePrefix?: string[]; units?: string; + yAxisLabel?: string; }; const Chart = memo( @@ -75,6 +76,7 @@ const Chart = memo( iconStyles, downloadFilenamePrefix = [], units, + yAxisLabel, }: ChartProps) => { const { t } = useSafeTranslation(); const classes = useStyles(); @@ -191,7 +193,7 @@ const Chart = memo( fill: config.fill || false, backgroundColor: colors[i], borderColor: colors[i], - borderWidth: 2, + borderWidth: 4, data: tableRows.map(row => (row[indiceKey] as number) || null), pointRadius: configureIndicePointRadius(indiceKey), pointHitRadius: 10, @@ -302,7 +304,7 @@ const Chart = memo( data: dataset.data.map((point, index) => isFutureDate(labels[index] as string) ? point : null, ), - borderDash: [5, 2], + borderDash: [5, 5], })); return { labels, @@ -351,6 +353,8 @@ const Chart = memo( scaleLabel: { labelString: xAxisLabel, display: true, + lineHeight: 1.5, + fontColor: '#AAA', }, } : {}), @@ -370,6 +374,23 @@ const Chart = memo( gridLines: { display: false, }, + afterDataLimits: axis => { + // Increase y-axis by 20% for Google Flood charts to make space for the annotation label + if (isGoogleFloodChart) { + const range = axis.max - axis.min; + axis.max += range * 0.25; // eslint-disable-line no-param-reassign, fp/no-mutation + } + }, + ...(yAxisLabel + ? { + scaleLabel: { + display: true, + labelString: yAxisLabel, + lineHeight: 1.5, + fontColor: '#AAA', + }, + } + : {}), }, ], }, @@ -377,10 +398,41 @@ const Chart = memo( mode: 'index', callbacks: { label: (tooltipItem, labelData) => { - const label = + const datasetLabel = labelData.datasets?.[tooltipItem.datasetIndex as number] ?.label || ''; - return `${label}: ${tooltipItem.yLabel}${units ? ` ${units}` : ''}`; + const value = tooltipItem.yLabel; + const unitLabel = units ? ` ${units}` : ''; + + // Get the data point for the current tooltip item + const dataPoint = + labelData.datasets?.[tooltipItem.datasetIndex as number] + ?.data?.[tooltipItem.index as number]; + + // Check if any label is present in the tooltip + const labelPresent = labelData.datasets?.some(dataset => { + const { label } = dataset; + if (tooltipItem.index !== undefined) { + const indexData = dataset.data?.[tooltipItem.index]; + return ( + label === datasetLabel.replace(' (Future)', '') && + indexData !== null + ); + } + return false; + }); + + // Hide "{label} (Future)" if "{label}" is present + if (labelPresent && datasetLabel.includes(' (Future)')) { + return null; + } + + // Only show labels with non-null data points + if (dataPoint !== null) { + return `${datasetLabel}: ${value}${unitLabel}`; + } + + return null; }, }, }, @@ -397,9 +449,17 @@ const Chart = memo( type: 'line', mode: 'vertical', scaleID: 'x-axis-0', - value: today.toISOString().split('T')[0], // Assuming your labels are date strings + value: today.toISOString().split('T')[0], borderColor: 'rgba(255, 255, 255, 0.8)', borderWidth: 2, + label: { + content: t('Today'), + enabled: true, + position: 'top', + yAdjust: -6, + fontColor: '#CCC', + fontSize: 10, + }, }, ], }, @@ -418,8 +478,10 @@ const Chart = memo( legendAtBottom, isGoogleFloodChart, today, + t, isEWSChart, units, + yAxisLabel, ], ); diff --git a/frontend/src/components/MapView/MapTooltip/PointDataChart/PopupPointDataChart.tsx b/frontend/src/components/MapView/MapTooltip/PointDataChart/PopupPointDataChart.tsx index 2e2bfaf44..5ed35a3f4 100644 --- a/frontend/src/components/MapView/MapTooltip/PointDataChart/PopupPointDataChart.tsx +++ b/frontend/src/components/MapView/MapTooltip/PointDataChart/PopupPointDataChart.tsx @@ -18,7 +18,7 @@ const useStyles = makeStyles(() => display: 'flex', flexDirection: 'column', gap: '8px', - paddingTop: '20px', // leave room for the close icon + paddingTop: '8px', // leave room for the close icon }, chartSection: { paddingTop: '16px', // leave room for the download icons @@ -49,6 +49,13 @@ const PopupPointDataChart = memo(() => { return null; } + const xAxisLabel = isAdminBoundary(datasetParams) + ? undefined + : t('Timestamps reflect local time in region'); + const yAxisLabel = (datasetParams as GoogleFloodParams).yAxisLabel + ? t((datasetParams as GoogleFloodParams).yAxisLabel) + : undefined; + return (
@@ -56,11 +63,8 @@ const PopupPointDataChart = memo(() => { title={t(title, datasetParams)} config={config} data={dataset} - xAxisLabel={ - isAdminBoundary(datasetParams) - ? undefined - : t('Timestamps reflect local time in region') - } + xAxisLabel={xAxisLabel} + yAxisLabel={yAxisLabel} showDownloadIcons iconStyles={{ color: 'white', marginTop: '20px' }} units={t((datasetParams as GoogleFloodParams).unit)} diff --git a/frontend/src/config/cambodia/layers.json b/frontend/src/config/cambodia/layers.json index 93510d04a..badd8e1f5 100644 --- a/frontend/src/config/cambodia/layers.json +++ b/frontend/src/config/cambodia/layers.json @@ -1990,7 +1990,8 @@ "legend_text": "Index meausring a household’s social and economic capacities and resilience to cope with, adapt to and recover from the floods and droughts. Aggregated at Commune level" }, "google_flood_status_at_gauges": { - "title": "Flood Status at Gauges (Google AI)", + "title": "Current Flood Status (Google AI)", + "loader": "google_flood", "type": "point_data", "loader": "google_flood", "hex_display": false, @@ -2006,7 +2007,7 @@ { "label": "Danger", "value": "SEVERE", "color": "#ea250a" }, { "label": "Warning", "value": "ABOVE_NORMAL", "color": "#fba705" }, { "label": "Normal", "value": "NO_FLOODING", "color": "#089180" }, - { "label": "Unknown", "value": "UNKNOWN", "color": "#858585" } + { "label": "No data", "value": "UNKNOWN", "color": "#858585" } ], "feature_info_title": { "siteName": { @@ -2044,7 +2045,7 @@ "SEVERE": "Danger", "ABOVE_NORMAL": "Warning", "NO_FLOODING": "Normal", - "UNKNOWN": "Unknown" + "UNKNOWN": "No data" } }, "gaugeId": { diff --git a/frontend/src/config/mozambique/layers.json b/frontend/src/config/mozambique/layers.json index 40aac1170..00f7d8baa 100644 --- a/frontend/src/config/mozambique/layers.json +++ b/frontend/src/config/mozambique/layers.json @@ -2963,7 +2963,7 @@ { "label": "Danger", "value": "SEVERE", "color": "#ea250a" }, { "label": "Warning", "value": "ABOVE_NORMAL", "color": "#fba705" }, { "label": "Normal", "value": "NO_FLOODING", "color": "#089180" }, - { "label": "Unknown", "value": "UNKNOWN", "color": "#858585" } + { "label": "No data", "value": "UNKNOWN", "color": "#858585" } ], "feature_info_title": { "siteName": { @@ -3001,7 +3001,7 @@ "SEVERE": "Danger", "ABOVE_NORMAL": "Warning", "NO_FLOODING": "Normal", - "UNKNOWN": "Unknown" + "UNKNOWN": "No data" } }, "gaugeId": { diff --git a/frontend/src/config/rbd/layers.json b/frontend/src/config/rbd/layers.json index ac330679b..d081b80e1 100644 --- a/frontend/src/config/rbd/layers.json +++ b/frontend/src/config/rbd/layers.json @@ -6549,7 +6549,7 @@ { "label": "Danger", "value": "SEVERE", "color": "#ea250a" }, { "label": "Warning", "value": "ABOVE_NORMAL", "color": "#fba705" }, { "label": "Normal", "value": "NO_FLOODING", "color": "#089180" }, - { "label": "Unknown", "value": "UNKNOWN", "color": "#858585" } + { "label": "No data", "value": "UNKNOWN", "color": "#858585" } ], "feature_info_title": { "siteName": { @@ -6587,7 +6587,7 @@ "SEVERE": "Danger", "ABOVE_NORMAL": "Warning", "NO_FLOODING": "Normal", - "UNKNOWN": "Unknown" + "UNKNOWN": "No data" } }, "gaugeId": { diff --git a/frontend/src/context/datasetStateSlice.ts b/frontend/src/context/datasetStateSlice.ts index c97ca1aa8..c2fdcff44 100644 --- a/frontend/src/context/datasetStateSlice.ts +++ b/frontend/src/context/datasetStateSlice.ts @@ -407,11 +407,25 @@ export const datasetResultStateSlice = createSlice({ state, { payload }: PayloadAction, ): DatasetState => { - const { gaugeId, triggerLevels, detailUrl, chartTitle, unit } = payload; + const { + gaugeId, + triggerLevels, + detailUrl, + chartTitle, + unit, + yAxisLabel, + } = payload; return { ...state, - datasetParams: { gaugeId, triggerLevels, chartTitle, detailUrl, unit }, + datasetParams: { + gaugeId, + triggerLevels, + chartTitle, + detailUrl, + unit, + yAxisLabel, + }, title: chartTitle, }; }, diff --git a/frontend/src/utils/google-flood-utils.ts b/frontend/src/utils/google-flood-utils.ts index 116fb31f2..2845cb233 100644 --- a/frontend/src/utils/google-flood-utils.ts +++ b/frontend/src/utils/google-flood-utils.ts @@ -11,6 +11,7 @@ export type GoogleFloodParams = { detailUrl: string; chartTitle: string; unit: string; + yAxisLabel: string; }; const GOOGLE_FLOOD_UNITS = { @@ -19,6 +20,12 @@ const GOOGLE_FLOOD_UNITS = { CUBIC_METERS_PER_SECOND: 'm³/s', }; +const GOOGLE_FLOOD_Y_AXIS_LABEL = { + GAUGE_VALUE_UNIT_UNSPECIFIED: '', + METERS: 'Unit = water depth in m', + CUBIC_METERS_PER_SECOND: 'Unit = discharge in m³/s', +}; + export const GoogleFloodTriggersConfig: FloodChartConfigObject = { normal: { label: 'Normal', @@ -95,13 +102,19 @@ export const createGoogleFloodDatasetParams = ( }; const unit = GOOGLE_FLOOD_UNITS[gaugeValueUnit as keyof typeof GOOGLE_FLOOD_UNITS]; + const yAxisLabel = t( + GOOGLE_FLOOD_Y_AXIS_LABEL[ + gaugeValueUnit as keyof typeof GOOGLE_FLOOD_Y_AXIS_LABEL + ], + ); return { gaugeId, triggerLevels, chartTitle, detailUrl, - unit, + unit: t(unit), + yAxisLabel: t(yAxisLabel), }; };