Skip to content

Commit

Permalink
5965 task compare datasets node thumbnail should be one of the charts (
Browse files Browse the repository at this point in the history
…#6082)

Co-authored-by: Jaehwan Ryu <[email protected]>
Co-authored-by: Tom Szendrey <[email protected]>
  • Loading branch information
3 people authored Jan 17, 2025
1 parent fc4318b commit 254b452
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
</section>
<section class="items-wrapper">
<h5>Options</h5>
<tera-checkbox label="Use log scale" :model-value="useLog" @update:model-value="toggleLogScale($event)" />
<tera-checkbox
label="Use log scale"
:model-value="Boolean(useLog)"
@update:model-value="toggleLogScale($event)"
label="Hide in node"
:model-value="isHiddenInNode"
@update:model-value="toggleHideInNode($event)"
/>
<Divider />
</section>
Expand Down Expand Up @@ -106,11 +107,17 @@ const props = defineProps<{
const emit = defineEmits(['close', 'update-settings', 'delete-annotation', 'create-annotation']);
// Log scale
const useLog = computed(() => props.activeSettings?.scale === 'log');
const useLog = computed<boolean>(() => props.activeSettings?.scale === 'log');
const isHiddenInNode = computed<boolean>(() => !!props.activeSettings?.hideInNode);
const toggleLogScale = (useLogScale: boolean) => {
emit('update-settings', { scale: useLogScale ? 'log' : '' });
};
const toggleHideInNode = (hideInNode: boolean) => {
emit('update-settings', { hideInNode: !!hideInNode });
};
// Settings for comparison method
const comparisonSettings = computed(() => props.activeSettings as ChartSettingComparison | null);
const smallMultiplesRadioValue = computed(() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,16 @@
<template
v-if="!inProgressCalibrationId && runResult && csvAsset && runResultPre && selectedVariableSettings.length"
>
<vega-chart
v-for="setting of selectedVariableSettings"
:key="setting.id"
:are-embed-actions-visible="false"
:visualization-spec="variableCharts[setting.id]"
:interactive="false"
/>
<vega-chart
v-for="setting of selectedInterventionSettings"
:key="setting.id"
expandable
:are-embed-actions-visible="true"
:visualization-spec="interventionCharts[setting.id]"
:interactive="false"
<tera-node-preview
:node="node"
:is-loading="!!inProgressCalibrationId"
:prepared-charts="[variableCharts, interventionCharts]"
:chart-settings="[selectedVariableSettings, selectedInterventionSettings]"
:progress="node.state.currentProgress + '%'"
/>
</template>
<vega-chart v-else-if="lossChartSpec" :are-embed-actions-visible="false" :visualization-spec="lossChartSpec" />

<tera-progress-spinner v-if="inProgressCalibrationId" :font-size="2" is-centered style="height: 100%">
{{ node.state.currentProgress }}%
</tera-progress-spinner>

<Button v-if="areInputsFilled" label="Open" @click="emit('open-drilldown')" severity="secondary" outlined />
<tera-operator-placeholder v-else :node="node">
Connect a model configuration and dataset
Expand All @@ -36,8 +24,8 @@
import _ from 'lodash';
import { computed, watch, ref, shallowRef, onMounted, toRef } from 'vue';
import Button from 'primevue/button';
import TeraOperatorPlaceholder from '@/components/operator/tera-operator-placeholder.vue';
import TeraProgressSpinner from '@/components/widgets/tera-progress-spinner.vue';
import {
getRunResultCSV,
pollAction,
Expand Down Expand Up @@ -76,6 +64,7 @@ import { useCharts } from '@/composables/useCharts';
import { filterChartSettingsByVariables } from '@/services/chart-settings';
import { ChartSettingType } from '@/types/common';
import { parseCsvAsset } from '@/utils/csv';
import TeraNodePreview from '../tera-node-preview.vue';
import type { CalibrationOperationStateCiemss } from './calibrate-operation';
import { CalibrationOperationCiemss } from './calibrate-operation';
import { renameFnGenerator, usePreparedChartInputs, getSelectedOutputMapping } from './calibrate-utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
:visualization-spec="lossChartSpec"
/>
<div v-if="outputData">
<vega-chart
v-for="(chart, index) of ensembleVariableCharts"
:key="index"
:interactive="false"
:visualization-spec="chart"
/>
<vega-chart v-for="(chart, index) of ensembleVariableCharts" :key="index" :visualization-spec="chart" />
</div>
<tera-progress-spinner
v-if="inProgressCalibrationId || inProgressForecastId"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { isEmpty } from 'lodash';
import { Dataset } from '@/types/Types';
import { WorkflowPortStatus } from '@/types/workflow';
import { renameFnGenerator } from '@/components/workflow/ops/calibrate-ciemss/calibrate-utils';

import { createRankingInterventionsChart } from '@/services/charts';
import { DATASET_VAR_NAME_PREFIX, getDatasetResultCSV, mergeResults, getDataset } from '@/services/dataset';
import {
DataArray,
getRunResultCSV,
parsePyCiemssMap,
processAndSortSamplesByTimepoint
processAndSortSamplesByTimepoint,
getRunResultCSV
} from '@/services/models/simulation-service';
import { DATASET_VAR_NAME_PREFIX, getDatasetResultCSV, mergeResults } from '@/services/dataset';
import { getInterventionPolicyById } from '@/services/intervention-policy';
import { getModelConfigurationById } from '@/services/model-configurations';

import { ChartData } from '@/composables/useCharts';
import { PlotValue } from './compare-datasets-operation';

import { PlotValue, TimepointOption, RankOption } from './compare-datasets-operation';

interface DataResults {
results: DataArray[];
Expand Down Expand Up @@ -169,3 +177,161 @@ export function buildChartData(
numComparableDatasets: datasets.length
};
}

export function generateRankingCharts(
rankingCriteriaCharts,
rankingResultsChart,
props,
modelConfigIdToInterventionPolicyIdMap,
chartData,
interventionPolicies
) {
// Reset charts
rankingCriteriaCharts.value = [];
rankingResultsChart.value = null;

// Might be uneccessary
const commonInterventionPolicyIds = props.node.state.criteriaOfInterestCards
.map(({ selectedConfigurationId }) => {
if (!selectedConfigurationId) return [];
return modelConfigIdToInterventionPolicyIdMap.value?.[selectedConfigurationId] ?? [];
})
.flat();
const allRankedCriteriaValues: { score: number; name: string }[][] = [];

props.node.state.criteriaOfInterestCards.forEach((card) => {
if (!card.selectedConfigurationId || !chartData.value) return;

const pointOfComparison =
card.timepoint === TimepointOption.FIRST
? chartData.value.resultSummary[0]
: chartData.value.resultSummary[chartData.value.resultSummary.length - 1];

const rankingCriteriaValues: { score: number; name: string }[] = [];
interventionPolicies.value.forEach((policy, index) => {
// Skip this intervention policy if a configuration is not using it
if (!policy.id || !policy.name || !commonInterventionPolicyIds.includes(policy.id) || !card.selectedVariable) {
return;
}

rankingCriteriaValues.push({
score: pointOfComparison[`${chartData.value?.pyciemssMap[card.selectedVariable]}_mean:${index}`] ?? 0,
name: policy.name ?? ''
});
});

const sortedRankingCriteriaValues =
card.rank === RankOption.MAXIMUM
? rankingCriteriaValues.sort((a, b) => b.score - a.score)
: rankingCriteriaValues.sort((a, b) => a.score - b.score);

sortedRankingCriteriaValues.forEach((value, index) => {
value.score = index + 1;
});

rankingCriteriaCharts.value.push(createRankingInterventionsChart(sortedRankingCriteriaValues, card.name));
allRankedCriteriaValues.push(sortedRankingCriteriaValues);
});

// Sum up the scores of the same intervention policy
const scoreMap: Record<string, number> = {};
allRankedCriteriaValues.flat().forEach(({ score, name }) => {
if (scoreMap[name]) {
scoreMap[name] += score;
} else {
scoreMap[name] = score;
}
});

const rankingResultsValues = Object.keys(scoreMap)
.map((name) => ({
name,
score: scoreMap[name]
}))
.sort((a, b) => a.score - b.score);

rankingResultsChart.value = createRankingInterventionsChart(rankingResultsValues, '');
}

export async function generateImpactCharts(
chartData,
datasets,
datasetResults,
baselineDatasetIndex,
selectedPlotType
) {
chartData.value = buildChartData(
datasets.value,
datasetResults.value,
baselineDatasetIndex.value,
selectedPlotType.value
);
}

// TODO: this should probably be split up into smaller functions but for now it's at least not duplicated in the node and drilldown
export async function initialize(
props,
isFetchingDatasets,
datasets,
datasetResults,
modelConfigIdToInterventionPolicyIdMap,
chartData,
baselineDatasetIndex,
selectedPlotType,
modelConfigurations,
interventionPolicies,
rankingCriteriaCharts,
rankingResultsChart
) {
const { inputs } = props.node;
const datasetInputs = inputs.filter(
(input) => input.type === 'datasetId' && input.status === WorkflowPortStatus.CONNECTED
);
const datasetPromises = datasetInputs.map((input) => getDataset(input.value![0]));
isFetchingDatasets.value = true;
await Promise.all(datasetPromises).then((ds) => {
ds.forEach((dataset) => {
// Add dataset
if (!dataset) return;
datasets.value.push(dataset);

// Collect model configuration id and intervention policy id
const modelConfigurationId: string | undefined = dataset.metadata?.simulationAttributes?.modelConfigurationId;
const interventionPolicyId: string | undefined = dataset.metadata?.simulationAttributes?.interventionPolicyId;

if (!modelConfigurationId) return;
if (!modelConfigIdToInterventionPolicyIdMap.value[modelConfigurationId]) {
modelConfigIdToInterventionPolicyIdMap.value[modelConfigurationId] = [];
}
if (!interventionPolicyId) return;
modelConfigIdToInterventionPolicyIdMap.value[modelConfigurationId].push(interventionPolicyId);
});
});
// Fetch the results
datasetResults.value = await fetchDatasetResults(datasets.value);
isFetchingDatasets.value = false;

await generateImpactCharts(chartData, datasets, datasetResults, baselineDatasetIndex, selectedPlotType);
const modelConfigurationIds = Object.keys(modelConfigIdToInterventionPolicyIdMap.value);
if (isEmpty(modelConfigurationIds)) return;
const modelConfigurationPromises = modelConfigurationIds.map((id) => getModelConfigurationById(id));
await Promise.all(modelConfigurationPromises).then((configs) => {
modelConfigurations.value = configs.filter((config) => config !== null);
});

const interventionPolicyIds = Object.values(modelConfigIdToInterventionPolicyIdMap.value).flat();
if (isEmpty(interventionPolicyIds)) return;
const interventionPolicyPromises = interventionPolicyIds.map((id) => getInterventionPolicyById(`${id}`));
await Promise.all(interventionPolicyPromises).then((policies) => {
interventionPolicies.value = policies.filter((policy) => policy !== null);
});

generateRankingCharts(
rankingCriteriaCharts,
rankingResultsChart,
props,
modelConfigIdToInterventionPolicyIdMap,
chartData,
interventionPolicies
);
}
Loading

0 comments on commit 254b452

Please sign in to comment.