Skip to content

Commit 5b4f77c

Browse files
committed
Add option for historical data and projections in food insecurity chart
1 parent ced5e57 commit 5b4f77c

File tree

4 files changed

+132
-51
lines changed

4 files changed

+132
-51
lines changed

src/components/PieChart/styles.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
.pie-chart {
22
display: flex;
3+
align-items: center;
34
flex-wrap: wrap;
45
gap: var(--go-ui-spacing-md);
5-
align-items: center;
66

77
.legend {
88
display: flex;

src/views/CountryRiskWatch/RiskBarChart/FoodInsecurityChart/index.tsx

Lines changed: 102 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
Fragment,
32
useCallback,
43
useMemo,
54
useRef,
@@ -33,13 +32,13 @@ type CountryRiskResponse = RiskApiResponse<'/api/v1/country-seasonal/'>;
3332
type RiskData = CountryRiskResponse[number];
3433

3534
const colors = [
36-
'#cbcedb',
37-
'#a9adbf',
38-
'#878ea5',
39-
'#676f8a',
40-
'#475271',
41-
'#283759',
42-
'#011e41',
35+
'var(--go-ui-color-gray-30)',
36+
'var(--go-ui-color-gray-40)',
37+
'var(--go-ui-color-gray-50)',
38+
'var(--go-ui-color-gray-60)',
39+
'var(--go-ui-color-gray-70)',
40+
'var(--go-ui-color-gray-80)',
41+
'var(--go-ui-color-gray-90)',
4342
];
4443

4544
const X_AXIS_HEIGHT = 24;
@@ -66,12 +65,25 @@ const localeFormatDate = (date: Date) => date.toLocaleString(
6665
},
6766
);
6867

68+
const localeFormatMonth = (date: Date) => date.toLocaleString(
69+
navigator.language,
70+
{ month: 'short' },
71+
);
72+
73+
const currentYear = new Date().getFullYear();
74+
6975
interface Props {
7076
ipcData: RiskData['ipc_displacement_data'] | undefined;
77+
showHistoricalData?: boolean;
78+
showProjection?: boolean;
7179
}
7280

7381
function FoodInsecurityChart(props: Props) {
74-
const { ipcData } = props;
82+
const {
83+
ipcData,
84+
showHistoricalData,
85+
showProjection,
86+
} = props;
7587

7688
const chartContainerRef = useRef<HTMLDivElement>(null);
7789
const chartBounds = useSizeTracking(chartContainerRef);
@@ -141,6 +153,7 @@ function FoodInsecurityChart(props: Props) {
141153
y,
142154
value,
143155
dates,
156+
month: monthKey,
144157
};
145158
},
146159
);
@@ -161,17 +174,22 @@ function FoodInsecurityChart(props: Props) {
161174
const yearlyPathPoints = yearKeys.map(
162175
(year) => ({
163176
key: year,
177+
year,
164178
points: chartPoints.map((point) => ({
179+
key: `${year}-${point.key}`,
165180
x: point.x,
166181
y: point.y[year],
167182
v: point.value[year],
183+
date: point.dates[year],
168184
})),
169185
}),
170186
);
171187

172188
const averagePathPoints = chartPoints.map((point) => ({
173189
x: point.x,
174190
y: point.y.average,
191+
value: point.value.average,
192+
date: new Date(currentYear, point.month, 1),
175193
}));
176194

177195
return {
@@ -206,6 +224,14 @@ function FoodInsecurityChart(props: Props) {
206224
[],
207225
);
208226

227+
const predictionPointData = chartData.yearlyPathPoints.find(
228+
(pathPoints) => pathPoints.key === chartData.predictionYear,
229+
);
230+
231+
const historicalPointsData = chartData.yearlyPathPoints.filter(
232+
(pathPoints) => pathPoints.key !== chartData.predictionYear,
233+
);
234+
209235
return (
210236
<div
211237
className={styles.foodInsecurityChart}
@@ -221,16 +247,27 @@ function FoodInsecurityChart(props: Props) {
221247
xAxisTickSelector={xAxisTickSelector}
222248
yAxisTickSelector={yAxisTickSelector}
223249
/>
224-
{chartData.yearlyPathPoints.map(
250+
{showProjection && isDefined(predictionPointData) && (
251+
getDiscretePathDataList(predictionPointData.points)?.map(
252+
(discretePath) => (
253+
<path
254+
key={`prediction-${discretePath}`}
255+
className={styles.path}
256+
d={discretePath}
257+
stroke={COLOR_PRIMARY_RED}
258+
/>
259+
),
260+
)
261+
)}
262+
{showHistoricalData && historicalPointsData.map(
225263
(pathPoints, i) => (
226264
getDiscretePathDataList(pathPoints.points)?.map(
227265
(discretePath) => (
228266
<path
229267
className={styles.path}
230268
key={`${pathPoints.key}-${discretePath}`}
231269
d={discretePath}
232-
stroke={pathPoints.key === chartData.predictionYear
233-
? COLOR_PRIMARY_RED : colors[i]}
270+
stroke={colors[i]}
234271
/>
235272
),
236273
)
@@ -246,49 +283,64 @@ function FoodInsecurityChart(props: Props) {
246283
/>
247284
),
248285
)}
249-
{chartData.points.map(
286+
{showProjection && predictionPointData?.points.map(
287+
(point) => {
288+
if (isNotDefined(point.y) || isNotDefined(point.x)) {
289+
return null;
290+
}
291+
292+
return (
293+
<circle
294+
className={styles.averagePoint}
295+
cx={point.x}
296+
cy={point.y}
297+
fill={COLOR_PRIMARY_RED}
298+
>
299+
<title>
300+
{`${localeFormatMonth(point.date)}: ${formatNumber(point.v)}`}
301+
</title>
302+
</circle>
303+
);
304+
},
305+
)}
306+
{showHistoricalData && historicalPointsData.map(
307+
(pointData, i) => (
308+
pointData.points.map(
309+
(point) => (
310+
isDefined(point.y) ? (
311+
<circle
312+
key={point.key}
313+
className={styles.point}
314+
cx={point.x}
315+
cy={point.y}
316+
stroke={colors[i]}
317+
>
318+
<title>
319+
{`${localeFormatDate(point.date)}: ${formatNumber(point.v)}`}
320+
</title>
321+
</circle>
322+
) : null
323+
),
324+
)
325+
),
326+
)}
327+
{chartData.averagePathPoints.map(
250328
(point) => {
251-
if (isNotDefined(point.y.average)) {
329+
if (isNotDefined(point.y)) {
252330
return null;
253331
}
254332

255333
return (
256-
<Fragment key={point.key}>
257-
{chartData.yearKeys.map(
258-
(year, i) => {
259-
const y = point.y[year];
260-
261-
if (isNotDefined(y)) {
262-
return null;
263-
}
264-
265-
return (
266-
<circle
267-
key={year}
268-
className={styles.point}
269-
cx={point.x}
270-
cy={y}
271-
stroke={year === chartData.predictionYear
272-
? COLOR_PRIMARY_RED : colors[i]}
273-
>
274-
<title>
275-
{`${localeFormatDate(point.dates[year])}: ${formatNumber(point.value[year])}`}
276-
</title>
277-
</circle>
278-
);
279-
},
280-
)}
281-
<circle
282-
className={styles.averagePoint}
283-
cx={point.x}
284-
cy={point.y.average}
285-
fill={COLOR_HAZARD_FOOD_INSECURITY}
286-
>
287-
<title>
288-
{formatNumber(point.value.average)}
289-
</title>
290-
</circle>
291-
</Fragment>
334+
<circle
335+
className={styles.averagePoint}
336+
cx={point.x}
337+
cy={point.y}
338+
fill={COLOR_HAZARD_FOOD_INSECURITY}
339+
>
340+
<title>
341+
{`${localeFormatMonth(point.date)}: ${formatNumber(point.value)}`}
342+
</title>
343+
</circle>
292344
);
293345
},
294346
)}

src/views/CountryRiskWatch/RiskBarChart/index.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Container from '#components/Container';
1515
import SelectInput from '#components/SelectInput';
1616
import BlockLoading from '#components/BlockLoading';
1717
import LegendItem from '#components/LegendItem';
18+
import Checkbox from '#components/Checkbox';
1819
import useInputState from '#hooks/useInputState';
1920
import useTranslation from '#hooks/useTranslation';
2021
import { stringLabelSelector } from '#utils/selectors';
@@ -69,6 +70,8 @@ function RiskBarChart(props: Props) {
6970
selectedHazardType,
7071
setSelectedHazardType,
7172
] = useInputState<HazardType | undefined>(undefined);
73+
const [showFiHistoricalData, setShowFiHistoricalData] = useInputState<boolean>(false);
74+
const [showFiProjection, setShowFiProjection] = useInputState<boolean>(false);
7275

7376
const handleRiskMetricChange = useCallback(
7477
(riskMetric: RiskMetric) => {
@@ -286,12 +289,30 @@ function RiskBarChart(props: Props) {
286289
value={selectedHazardType}
287290
onChange={setSelectedHazardType}
288291
/>
292+
{selectedHazardType === 'FI' && (
293+
<div className={styles.fiFilters}>
294+
<Checkbox
295+
name={undefined}
296+
value={showFiHistoricalData}
297+
onChange={setShowFiHistoricalData}
298+
label="Show historical data"
299+
/>
300+
<Checkbox
301+
name={undefined}
302+
value={showFiProjection}
303+
onChange={setShowFiProjection}
304+
label="Show projections"
305+
/>
306+
</div>
307+
)}
289308
</>
290309
)}
291310
>
292311
{pending && <BlockLoading />}
293312
{!pending && selectedHazardType === 'FI' && (
294313
<FoodInsecurityChart
314+
showHistoricalData={showFiHistoricalData}
315+
showProjection={showFiProjection}
295316
ipcData={seasonalRiskData?.ipc_displacement_data}
296317
/>
297318
)}

src/views/CountryRiskWatch/RiskBarChart/styles.module.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
.risk-bar-chart {
2+
.fi-filters {
3+
display: flex;
4+
align-items: center;
5+
flex-wrap: wrap;
6+
gap: var(--go-ui-spacing-md);
7+
grid-column: span 2;
8+
}
9+
210
.legend {
311
display: flex;
412
gap: var(--go-ui-spacing-md);

0 commit comments

Comments
 (0)