Skip to content

Commit

Permalink
Bug fix and code cleanup
Browse files Browse the repository at this point in the history
- Fix bug with propagation of selected parameter from settings to view (useValidState in view)
- Minor code cleanup for readability
  • Loading branch information
jorgenherje committed Sep 26, 2023
1 parent 702865e commit 2a58ae1
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 144 deletions.
86 changes: 53 additions & 33 deletions frontend/src/modules/SimulationTimeSeriesMatrix/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Label } from "@lib/components/Label";
import { RadioGroup } from "@lib/components/RadioGroup";
import { SmartNodeSelectorSelection, TreeDataNode } from "@lib/components/SmartNodeSelector";
import { VectorSelector } from "@lib/components/VectorSelector";
import { useValidState } from "@lib/hooks/useValidState";
import { resolveClassNames } from "@lib/utils/resolveClassNames";
import { createVectorSelectorDataFromVectors } from "@lib/utils/vectorSelectorUtils";

Expand Down Expand Up @@ -45,11 +46,11 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
const [groupBy, setGroupBy] = moduleContext.useStoreState("groupBy");
const [colorRealizationsByParameter, setColorRealizationsByParameter] =
moduleContext.useStoreState("colorRealizationsByParameter");
const [parameterIdent, setParameterIdent] = moduleContext.useStoreState("parameterIdent");
const [visualizationMode, setVisualizationMode] = moduleContext.useStoreState("visualizationMode");
const [showHistorical, setShowHistorical] = moduleContext.useStoreState("showHistorical");
const [showObservations, setShowObservations] = moduleContext.useStoreState("showObservations");
const [statisticsSelection, setStatisticsSelection] = moduleContext.useStoreState("statisticsSelection");
const setParameterIdent = moduleContext.useSetStoreValue("parameterIdent");
const setVectorSpecifications = moduleContext.useSetStoreValue("vectorSpecifications");

// States
Expand All @@ -59,51 +60,52 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
const [vectorSelectorData, setVectorSelectorData] = React.useState<TreeDataNode[]>([]);
const [prevVisualizationMode, setPrevVisualizationMode] = React.useState<VisualizationMode>(visualizationMode);

if (prevVisualizationMode !== visualizationMode) {
if (visualizationMode !== prevVisualizationMode) {
setPrevVisualizationMode(visualizationMode);
}

if (!isEqual(ensembleSet, previousEnsembleSet)) {
const newSelectedEnsembleIdents = selectedEnsembleIdents.filter(
(ensemble) => ensembleSet.findEnsemble(ensemble) !== null
);
const validatedEnsembleIdents = fixupEnsembleIdents(newSelectedEnsembleIdents, ensembleSet) ?? [];
if (!isEqual(selectedEnsembleIdents, validatedEnsembleIdents)) {
setSelectedEnsembleIdents(validatedEnsembleIdents);
}

setPreviousEnsembleSet(ensembleSet);
}

// Queries
const vectorListQueries = useVectorListQueries(selectedEnsembleIdents);
const ensembleVectorListsHelper = new EnsembleVectorListsHelper(selectedEnsembleIdents, vectorListQueries);
const vectorsUnion = ensembleVectorListsHelper.vectorsUnion();
const selectedVectorNamesHasHistorical = ensembleVectorListsHelper.hasAnyHistoricalVector(selectedVectorNames);
const currentVectorSelectorData = createVectorSelectorDataFromVectors(vectorsUnion);
const currentVectorSelectorData = createVectorSelectorDataFromVectors(ensembleVectorListsHelper.vectorsUnion());

// Get union of continuous parameters for selected ensembles
const continuousParametersUnion: ParameterIdent[] = [];
// Get union of continuous and non-constant parameters for selected ensembles and set valid parameter ident str
const continuousAndNonConstantParametersUnion: ParameterIdent[] = [];
for (const ensembleIdent of selectedEnsembleIdents) {
const ensemble = ensembleSet.findEnsemble(ensembleIdent);
if (ensemble === null) continue;

for (const parameter of ensemble.getParameters().getParameterIdents(ParameterType.CONTINUOUS)) {
if (continuousParametersUnion.some((param) => param.equals(parameter))) continue;

// TODO: Check if parameter is constant?
if (continuousAndNonConstantParametersUnion.some((param) => param.equals(parameter))) continue;
if (ensemble.getParameters().getParameter(parameter).isConstant) continue;

continuousParametersUnion.push(parameter);
continuousAndNonConstantParametersUnion.push(parameter);
}
}
const [selectedParameterIdentStr, setSelectedParameterIdentStr] = useValidState<string | null>(null, [
continuousAndNonConstantParametersUnion,
(item: ParameterIdent) => item.toString(),
]);

// Only update if all vector lists are retrieved before updating vectorSelectorData has changed
// Await update of vectorSelectorData until all vector lists are retrieved
const hasVectorListQueriesErrorOrLoading = vectorListQueries.some((query) => query.isLoading || query.isError);
if (!hasVectorListQueriesErrorOrLoading && !isEqual(currentVectorSelectorData, vectorSelectorData)) {
setVectorSelectorData(currentVectorSelectorData);
}

if (!isEqual(ensembleSet, previousEnsembleSet)) {
const newSelectedEnsembleIdents = selectedEnsembleIdents.filter(
(ensemble) => ensembleSet.findEnsemble(ensemble) !== null
);
const validatedEnsembleIdents = fixupEnsembleIdents(newSelectedEnsembleIdents, ensembleSet) ?? [];
if (!isEqual(selectedEnsembleIdents, validatedEnsembleIdents)) {
setSelectedEnsembleIdents(validatedEnsembleIdents);
}

setPreviousEnsembleSet(ensembleSet);
}

React.useEffect(
function propagateVectorSpecsToView() {
const newVectorSpecifications: VectorSpec[] = [];
Expand All @@ -120,20 +122,36 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
});
}
}

setVectorSpecifications(newVectorSpecifications);
},
[selectedEnsembleIdents, selectedVectorNames, ensembleVectorListsHelper.numberOfQueriesWithData()]
);

React.useEffect(
function propagateParameterIdentToView() {
if (selectedParameterIdentStr === null) {
setParameterIdent(null);
return;
}

try {
const newParameterIdent = ParameterIdent.fromString(selectedParameterIdentStr);
continuousAndNonConstantParametersUnion.some((parameter) => parameter.equals(newParameterIdent))
? setParameterIdent(newParameterIdent)
: setParameterIdent(null);
} catch {
setParameterIdent(null);
}
},
[selectedParameterIdentStr]
);

function handleGroupByChange(event: React.ChangeEvent<HTMLInputElement>) {
setGroupBy(event.target.value as GroupBy);
}

function handleColorByParameterChange(parameterIdentStr: string) {
const parameterIdent = ParameterIdent.fromString(parameterIdentStr);
const newParameterIdent = continuousParametersUnion.find((elm) => elm.equals(parameterIdent)) ?? null;
setParameterIdent(newParameterIdent);
setSelectedParameterIdentStr(parameterIdentStr);
}

function handleEnsembleSelectChange(ensembleIdentArr: EnsembleIdent[]) {
Expand Down Expand Up @@ -263,7 +281,6 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
>
<VectorSelector
data={vectorSelectorData}
selectedTags={selectedVectorNames}
placeholder="Add new vector..."
maxNumSelectedNodes={50}
numSecondsUntilSuggestionsAreShown={0.5}
Expand All @@ -273,9 +290,9 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
</ApiStatesWrapper>
</div>
</CollapsibleGroup>
<CollapsibleGroup expanded={true} title="Color selection">
<CollapsibleGroup expanded={true} title="Color realization by parameter">
<Checkbox
label="Color realizations by continuous parameter"
label="Enable"
checked={colorRealizationsByParameter}
disabled={visualizationMode !== VisualizationMode.INDIVIDUAL_REALIZATIONS}
onChange={(event) => {
Expand All @@ -291,10 +308,13 @@ export function settings({ moduleContext, workbenchSession }: ModuleFCProps<Stat
)}
>
<Dropdown
options={continuousParametersUnion.map((elm) => {
return { value: elm.toString(), label: elm.toString() };
options={continuousAndNonConstantParametersUnion.map((elm) => {
return {
value: elm.toString(),
label: elm.groupName ? `${elm.groupName}:${elm.name}` : elm.name,
};
})}
value={parameterIdent?.toString() ?? undefined}
value={selectedParameterIdentStr?.toString() ?? undefined}
onChange={handleColorByParameterChange}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
VectorStatisticData_api,
} from "@api";

import { type } from "os";

import { FanchartData, FreeLineData, LowHighData, MinMaxData } from "./fanchartPlotting";
import { createFanchartTraces } from "./fanchartPlotting";
import { LineData, StatisticsData, createStatisticsTraces } from "./statisticsPlotting";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,43 @@ import { ContinuousParameter, ParameterIdent, ParameterType } from "@framework/E
import { ColorScale } from "@lib/utils/ColorScale";
import { MinMax } from "@lib/utils/MinMax";

export class ContinuousParameterColorScaleHelper {
export class EnsemblesContinuousParameterColoring {
/**
* Helper class working with coloring according to selected continuous parameter across multiple ensembles
*
* Retrieves min/max parameter value across all ensembles and provides interface for retrieving parameter
* value within the min/max range for specific realization in ensemble.
*/

private _parameterIdent: ParameterIdent;
private _ensembleContinuousParameterSet: { [ensembleName: string]: ContinuousParameter };
private _minMax: MinMax;
private _colorScale: ColorScale;

constructor(parameterIdent: ParameterIdent, selectedEnsembles: Ensemble[], colorScale: ColorScale) {
constructor(selectedEnsembles: Ensemble[], parameterIdent: ParameterIdent, colorScale: ColorScale) {
this._parameterIdent = parameterIdent;
this._ensembleContinuousParameterSet = {};
this._minMax = MinMax.createInvalid();
let minMax = MinMax.createInvalid();
for (const ensemble of selectedEnsembles) {
const parameters = ensemble.getParameters();
if (!parameters.hasParameter(parameterIdent)) continue;

const parameter = parameters.getParameter(parameterIdent);
if (parameter.type === ParameterType.CONTINUOUS) {
this._ensembleContinuousParameterSet[ensemble.getEnsembleName()] = parameter;
this._minMax = this._minMax.extendedBy(parameters.getContinuousParameterMinMax(parameterIdent));
minMax = minMax.extendedBy(parameters.getContinuousParameterMinMax(parameterIdent));
}
}

// TODO: Set Range [0,0] if parameterMinMax is invalid?
// Consider: Set Range [0,0] if parameterMinMax is invalid?
this._colorScale = colorScale;
const midValue = this._minMax.min + (this._minMax.max - this._minMax.min) / 2;
this._colorScale.setRangeAndMidPoint(this._minMax.min, this._minMax.max, midValue);
const midValue = minMax.min + (minMax.max - minMax.min) / 2;
this._colorScale.setRangeAndMidPoint(minMax.min, minMax.max, midValue);
}

getColorScale(): ColorScale {
return this._colorScale;
}

getMinMax(): MinMax {
return this._minMax;
}

getParameterIdent(): ParameterIdent {
return this._parameterIdent;
}

hasEnsembleName(ensembleName: string): boolean {
return ensembleName in this._ensembleContinuousParameterSet;
}
Expand Down
Loading

0 comments on commit 2a58ae1

Please sign in to comment.