diff --git a/frontend/src/DataContext.tsx b/frontend/src/DataContext.tsx index 21dadcbc..83c9c2bd 100644 --- a/frontend/src/DataContext.tsx +++ b/frontend/src/DataContext.tsx @@ -238,14 +238,21 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => { } ); + const faceUpScenarios = useMemo(() => { + return ( + Object.entries(scenariosState) + .filter(([_, value]) => value.visibility === 'faceUp') + .map(([key]) => key) ?? [] + ); + }, [scenariosState]); + const {data: lineChartData} = useGetMultiScenarioInfectionDataQuery( { - pathIds: activeScenarios, + pathIds: faceUpScenarios, query: { nodes: [selectedDistrict], compartments: [selectedCompartment!], groups: totalGroup ? [totalGroup.id] : [], - percentiles: ['50'], }, }, { diff --git a/frontend/src/components/LineChartComponents/LineChart.tsx b/frontend/src/components/LineChartComponents/LineChart.tsx index 0a22a91a..220d6fbe 100644 --- a/frontend/src/components/LineChartComponents/LineChart.tsx +++ b/frontend/src/components/LineChartComponents/LineChart.tsx @@ -400,11 +400,8 @@ export default function LineChart({ }); } else if (serie.openValueYField) { serie.values.forEach((entry) => { - dataMap.set(entry.day, {...dataMap.get(entry.day), [serie.valueYField]: (entry.value as number[])[1]}); - dataMap.set(entry.day, { - ...dataMap.get(entry.day), - [String(serie.openValueYField)]: (entry.value as number[])[0], - }); + dataMap.set(entry.day, {...dataMap.get(entry.day), [serie.valueYField]: entry.value as number}); + dataMap.set(entry.day, {...dataMap.get(entry.day), [serie.openValueYField!]: entry.openValue as number}); }); } else { serie.values.forEach((entry) => { diff --git a/frontend/src/components/LineChartContainer.tsx b/frontend/src/components/LineChartContainer.tsx index cbb28190..409d3473 100644 --- a/frontend/src/components/LineChartContainer.tsx +++ b/frontend/src/components/LineChartContainer.tsx @@ -21,6 +21,7 @@ export default function LineChartContainer() { const {lineChartData, scenarios, compartments} = useContext(DataContext); const scenariosState = useAppSelector((state) => state.dataSelection.scenarios); + const selectedScenario = useAppSelector((state) => state.dataSelection.scenario); const selectedCompartment = useAppSelector((state) => state.dataSelection.compartment); const selectedDate = useAppSelector((state) => state.dataSelection.date); const referenceDay = useAppSelector((state) => state.dataSelection.simulationStart); @@ -48,32 +49,35 @@ export default function LineChartContainer() { values: infectionDataToLineChartData(data), }); - const percentiles: Array<{lower: string; upper: string}> = []; + if (id === selectedScenario) { + const scenario = scenarios!.find((scenario) => scenario.id === id)!; + const percentiles: Array<{lower: number; upper: number}> = []; - if (data.length > 0) { - const bandLines = Object.keys(data[0]).filter((percentile) => percentile !== '50'); - for (let i = 0; i < bandLines.length / 2; i++) { - percentiles.push({lower: bandLines[i], upper: bandLines[bandLines.length - 1 - i]}); + if (scenario.percentiles.length > 0) { + const bandLines = scenario.percentiles.filter((percentile) => percentile !== 50); + for (let i = 0; i < bandLines.length / 2; i++) { + percentiles.push({lower: bandLines[i], upper: bandLines[bandLines.length - 1 - i]}); + } } - } - percentiles.forEach((percentile, index) => { - lines.push({ - seriesId: `${id}-${percentile.lower}-${percentile.upper}`, - name: scenarios?.find((scenario) => scenario.id === id)?.name, - visible: true, - fill: scenariosState[id]?.colors[0] ?? 'transparent', - fillOpacity: 0.2 + 0.6 * (index / percentiles.length), - valueYField: 'percentileUp', - openValueYField: 'percentileDown', - stroke: {strokeWidth: 0}, - values: infectionDataToLineChartData(data), + percentiles.forEach((percentile, index) => { + lines.push({ + seriesId: `${id}-${percentile.lower}-${percentile.upper}`, + name: `${scenariosState[id].name} (${percentile.lower} - ${percentile.upper})`, + visible: true, + fill: scenariosState[id]?.colors[0] ?? 'transparent', + fillOpacity: 0.2 + 0.6 * (index / percentiles.length), + valueYField: id + percentile.lower, + openValueYField: id + percentile.upper, + stroke: {strokeWidth: 0}, + values: percentileDataToLineChartData(data, percentile.lower, percentile.upper), + }); }); - }); + } return lines; }); - }, [lineChartData, scenarios, scenariosState]); + }, [lineChartData, scenariosState, selectedScenario]); // Set reference day in store useEffect(() => { @@ -101,12 +105,26 @@ export default function LineChartContainer() { ); } -function infectionDataToLineChartData( - data: InfectionData - // percentiles: Array -): Array<{day: string; value: number | Array}> { - return data.map((entry) => ({ +function infectionDataToLineChartData(data: InfectionData): Array<{day: string; value: number}> { + return data + .filter((entry) => entry.percentile === 50) + .map((entry) => ({ + day: entry.date!, + value: entry.value, + })); +} + +function percentileDataToLineChartData( + data: InfectionData, + lower: number, + upper: number +): Array<{day: string; value: number; openValue: number}> { + const lowerPs = data.filter((entry) => entry.percentile === lower).sort((a, b) => a.date!.localeCompare(b.date!)); + const upperPs = data.filter((entry) => entry.percentile === upper).sort((a, b) => a.date!.localeCompare(b.date!)); + + return lowerPs.map((entry, i) => ({ day: entry.date!, value: entry.value, + openValue: upperPs[i].value, })); } diff --git a/frontend/src/store/services/APITypes.ts b/frontend/src/store/services/APITypes.ts index eac361ae..631fdaa0 100644 --- a/frontend/src/store/services/APITypes.ts +++ b/frontend/src/store/services/APITypes.ts @@ -18,6 +18,7 @@ export type NewScenario = { modelParameters: Array; nodeListId: string; linkedInterventions: Array; + percentiles: Array; }; export type Scenario = Required & @@ -26,7 +27,7 @@ export type Scenario = Required & timestampSimulated: string; }; -export type ScenarioPreview = Pick; +export type ScenarioPreview = Pick; export type InfectionDataParameters = { path: { diff --git a/frontend/src/types/lineChart.ts b/frontend/src/types/lineChart.ts index 2850af5e..19b04dc5 100644 --- a/frontend/src/types/lineChart.ts +++ b/frontend/src/types/lineChart.ts @@ -8,7 +8,7 @@ export interface LineChartData { /** * The values for the line chart. */ - values: {day: string; value: number | number[]}[]; + values: {day: string; value: number | number[]; openValue?: number | number[]}[]; /** * The name of the line chart.