Skip to content

Commit

Permalink
Merge pull request #365 from DLR-SC/feature/refactor-scenario-colors
Browse files Browse the repository at this point in the history
Fix and Refactor Scenario Colors
  • Loading branch information
JonasGilg authored Jun 13, 2024
2 parents 0e7d64d + 3df619a commit d7dd9b8
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 10 deletions.
1 change: 1 addition & 0 deletions frontend/docs/changelog/changelog-de.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ SPDX-License-Identifier: CC-BY-4.0
- Fehlende Übersetzungen wurden ergänzt.
- Die Auswahl der Farblegenden zeigt jetzt wieder eine Vorschau für alle Optionen.
- Die Parameter werden jetzt korrekt dem ausgewählten Szenario zugeordnet und eine Info wird angezeigt, wenn keine Parameter verfügbar sind.
- Die Farben der Szenarien wurden zum Teil falsch berechnet, was zu mehreren Szenarien mit den gleichen Farben führte.

---

Expand Down
1 change: 1 addition & 0 deletions frontend/docs/changelog/changelog-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ SPDX-License-Identifier: CC-BY-4.0
- Missing translations were fixed.
- The heat legend selection now shows a preview for all legends again.
- The Parameters will now correctly be associated with the selected scenario and an info will be displayed, when no parameters are available.
- The colors of the scenarios was calculated wrongly which could lead to multiple scenarios with the same colors.

---

Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/Scenario/DataCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import {setCompartments, setScenarios} from '../../store/ScenarioSlice';
import {useGetSimulationStartValues} from './hooks';
import {useGetCaseDataByDistrictQuery} from '../../store/services/caseDataApi';
import {getScenarioPrimaryColor} from '../../util/Theme';

export default function DataCardList(): JSX.Element {
const theme = useTheme();
Expand Down Expand Up @@ -139,13 +140,13 @@ export default function DataCardList(): JSX.Element {
onClick={() => dispatch(selectScenario(0))}
onToggle={() => dispatch(toggleScenario(0))}
/>
{Object.entries(scenarioList.scenarios).map(([, scenario], i) => (
{Object.entries(scenarioList.scenarios).map(([, scenario]) => (
<ScenarioCard
key={scenario.id}
scenario={scenario}
selected={selectedScenario === scenario.id}
active={!!activeScenarios && activeScenarios.includes(scenario.id)}
color={theme.custom.scenarios[(i + 1) % theme.custom.scenarios.length][0]}
color={getScenarioPrimaryColor(scenario.id, theme)}
startValues={startValues}
onClick={() => {
// set active scenario to this one and send dispatches
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/Scenario/ScenarioCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {useGetSingleSimulationEntryQuery} from 'store/services/scenarioApi';
import {Dictionary} from '../../util/util';
import {useTranslation} from 'react-i18next';
import {DataCard} from './DataCard';
import {getScenarioPrimaryColor} from '../../util/Theme';

/** Type definition for the ScenarioCard props */
interface ScenarioCardProps {
Expand Down Expand Up @@ -75,7 +76,7 @@ export function ScenarioCard(props: ScenarioCardProps): JSX.Element {
<DataCard
id={props.scenario.id}
label={tBackend(`scenario-names.${props.scenario.label}`)}
color={theme.custom.scenarios[props.scenario.id % theme.custom.scenarios.length][0]}
color={getScenarioPrimaryColor(props.scenario.id, theme)}
selected={props.selected}
active={props.active}
compartmentValues={compartmentValues}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/Sidebar/HeatLegendEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ export default function HeatLegendEdit(): JSX.Element {
return;
}

const scenarioDefault = defaultLegends[activeScenario % defaultLegends.length];
const scenarioDefault =
activeScenario === 0 ? defaultLegends[0] : defaultLegends[(activeScenario % (defaultLegends.length - 1)) + 1];
const legends = [...heatmapLegends];
legends.unshift(scenarioDefault);

Expand Down
11 changes: 6 additions & 5 deletions frontend/src/components/SimulationChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import LoadingContainer from './shared/LoadingContainer';
import {useGetMultipleGroupFilterDataQuery} from 'store/services/groupApi';
import {GroupData} from 'types/group';
import {setReferenceDayBottom} from '../store/LayoutSlice';
import {getScenarioPrimaryColor} from '../util/Theme';

/**
* React Component to render the Simulation Chart Section
Expand Down Expand Up @@ -288,7 +289,7 @@ export default function SimulationChart(): JSX.Element {
// Add fill color according to selected scenario (if selected scenario is set and it's not case data)
fill:
selectedScenario !== null && selectedScenario > 0
? color(theme.custom.scenarios[selectedScenario % theme.custom.scenarios.length][0])
? color(getScenarioPrimaryColor(selectedScenario, theme))
: undefined,
})
);
Expand All @@ -315,11 +316,11 @@ export default function SimulationChart(): JSX.Element {
// Fallback Tooltip (if HTML breaks for some reason)
// For text color: loop around the theme's scenario color list if scenario IDs exceed color list length, then pick first color of sub-palette which is the main color
tooltip: Tooltip.new(root, {
labelText: `[bold ${theme.custom.scenarios[scenario.id % theme.custom.scenarios.length][0]}]${tBackend(
labelText: `[bold ${getScenarioPrimaryColor(scenario.id, theme)}]${tBackend(
`scenario-names.${scenario.label}`
)}:[/] {${scenarioId}}`,
}),
stroke: color(theme.custom.scenarios[scenario.id % theme.custom.scenarios.length][0]),
stroke: color(getScenarioPrimaryColor(scenario.id, theme)),
})
);
series.strokes.template.setAll({
Expand Down Expand Up @@ -353,11 +354,11 @@ export default function SimulationChart(): JSX.Element {
// Fallback Tooltip (if HTML breaks for some reason)
// Use color of selected scenario (scenario ID is 1-based index, color list is 0-based index) loop if scenario ID exceeds length of color list; use first color of palette (main color)
tooltip: Tooltip.new(root, {
labelText: `[bold ${theme.custom.scenarios[selectedScenario % theme.custom.scenarios.length][0]}]${
labelText: `[bold ${getScenarioPrimaryColor(selectedScenario, theme)}]${
groupFilter.name
}:[/] {${groupFilter.name}}`,
}),
stroke: color(theme.custom.scenarios[selectedScenario % theme.custom.scenarios.length][0]),
stroke: color(getScenarioPrimaryColor(selectedScenario, theme)),
})
);
series.strokes.template.setAll({
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/util/Theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// add List Element typography using module augmentation
import React from 'react';
import {createTheme} from '@mui/material/styles';
import {createTheme, Theme} from '@mui/material/styles';

declare module '@mui/material/styles' {
interface TypographyVariants {
Expand Down Expand Up @@ -159,3 +159,17 @@ export default createTheme({
],
},
});

/**
* This function assigns a color palette to a scenario and consistently returns the same palette for the same id.
*/
export function getScenarioColorPalette(scenarioId: number, theme: Theme): Array<string> {
return theme.custom.scenarios[(scenarioId % (theme.custom.scenarios.length - 1)) + 1];
}

/**
* This function assigns a primary color to a scenario and consistently returns the same color for the same id.
*/
export function getScenarioPrimaryColor(scenarioId: number, theme: Theme): string {
return getScenarioColorPalette(scenarioId, theme)[0];
}

0 comments on commit d7dd9b8

Please sign in to comment.