Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comparison chart settings options for TA3 operator #6112

Merged
merged 9 commits into from
Jan 17, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,75 @@
<Button :icon="`pi pi-times`" @click="$emit('close')" text rounded size="large" />
<h4 class="line-wrap">{{ activeSettings.name }}</h4>
</header>
<div class="content">
<div class="annotation-items">
<h5>Options</h5>
<tera-checkbox
label="Use log scale"
:model-value="Boolean(useLog)"
@update:model-value="toggleLogScale($event)"
/>
<tera-checkbox
v-if="comparison"
label="Small multiples"
:model-value="Boolean(isSmallMultiples)"
@update:model-value="toggleSmallMultiples($event)"
/>
<!-- TODO: we want this but it is under research for how to get it to work in vega-lite -->
<!-- <tera-checkbox
v-if="comparison && isSmallMultiples"
label="Share Y Axis"
:model-value="Boolean(isShareYAxis)"
@update:model-value="toggleShareYAxis($event)"
/> -->
</div>
<Divider />
<div v-if="chartAnnotations !== undefined" class="annotation-items">
<div class="content items-wrapper">
<section v-if="chartAnnotations !== undefined" class="annotation-items">
<h5>Annotations</h5>
<tera-input-text
v-model="generateAnnotationQuery"
:icon="'pi pi-sparkles'"
:placeholder="'What do you want to annotate?'"
:disabled="!!isGeneratingAnnotation"
@keyup.enter="createAnnotationDebounced"
@keyup.esc="cancelGenerateAnnotation"
class="annotation-input"
/>
<div v-for="annotation in chartAnnotations" :key="annotation.id" class="annotation-item">
{{ annotation.description }}
<span class="btn-wrapper">
<Button icon="pi pi-trash" rounded text @click="$emit('delete-annotation', annotation.id)" />
</span>
</div>
<Divider />
</section>
<section class="items-wrapper">
<h5>Options</h5>
<tera-checkbox
label="Use log scale"
:model-value="Boolean(useLog)"
@update:model-value="toggleLogScale($event)"
/>
<Divider />
</section>
<section v-if="isColorPickerEnabled">
<h5 class="mb-3">Color picker</h5>
<input type="color" :value="activeSettings?.primaryColor ?? ''" @change="onColorChange($event)" />
<Divider />
</section>
<section v-if="activeSettings?.type === ChartSettingType.VARIABLE_COMPARISON" class="items-wrapper">
<h5>Comparison method</h5>
<div>
<Button
v-if="!showAnnotationInput"
class="p-button-sm p-button-text"
icon="pi pi-plus"
label="Add annotation"
@click="showAnnotationInput = true"
<RadioButton
:model-value="smallMultiplesRadioValue"
@update:model-value="onSmallMultiplesRadioButtonChange"
inputId="all-charts"
value="all-charts"
/>
<tera-input-text
v-if="showAnnotationInput"
v-model="generateAnnotationQuery"
:icon="'pi pi-sparkles'"
:placeholder="'What do you want to annotate?'"
:disabled="!!isGeneratingAnnotation"
@keyup.enter="createAnnotationDebounced"
@keyup.esc="cancelGenerateAnnotation"
class="annotation-input"
<label for="all-charts" class="ml-2">All in one chart</label>
</div>
<div>
<RadioButton
:model-value="smallMultiplesRadioValue"
@update:model-value="onSmallMultiplesRadioButtonChange"
inputId="small-multiples"
value="small-multiples"
/>
<label for="small-multiples" class="ml-2">Small multiples</label>
</div>
</div>
<Divider />
<section v-if="isColorPickerEnabled">
<h5 class="mb-3">Color picker</h5>
<input type="color" :value="activeSettings?.primaryColor ?? ''" @change="onColorChange($event)" />
<div class="pl-5 items-wrapper">
<tera-checkbox
label="Same Y axis for all"
:disabled="!comparisonSettings?.smallMultiples"
:model-value="isShareYAxis"
@update:model-value="toggleShareYAxis($event)"
/>
<tera-checkbox
label="Show before and after"
:disabled="!comparisonSettings?.smallMultiples"
:model-value="showBeforeAfter"
@update:model-value="toggleShowBeforeAfter($event)"
/>
</div>
<Divider />
</section>
</div>
</div>
Expand All @@ -70,7 +84,8 @@
import _ from 'lodash';
import { ref, computed } from 'vue';
import Button from 'primevue/button';
import { ChartSetting, ChartSettingType } from '@/types/common';
import RadioButton from 'primevue/radiobutton';
import { ChartSetting, ChartSettingType, ChartSettingComparison } from '@/types/common';
import { ChartAnnotation } from '@/types/Types';
import Divider from 'primevue/divider';
import TeraInputText from '@/components/widgets/tera-input-text.vue';
Expand All @@ -79,7 +94,6 @@ import TeraCheckbox from '@/components/widgets/tera-checkbox.vue';
const props = defineProps<{
activeSettings: ChartSetting | null;
annotations?: ChartAnnotation[];
comparison?: boolean;
/**
* We receives generateAnnotation as a functor from the parent to access the parent scope directly. This allows us to utilize dependencies defined in the parent component without passing them all as props, which can be cumbersome.
* Additionally, it enables us to handle post-generation actions (like resetting loading state or clearing input) after function completion.
Expand All @@ -93,23 +107,23 @@ const emit = defineEmits(['close', 'update-settings', 'delete-annotation', 'crea

// Log scale
const useLog = computed(() => props.activeSettings?.scale === 'log');
const isSmallMultiples = computed(() => {
const { smallMultiples, selectedVariables } = <ChartSetting>props.activeSettings;
return smallMultiples || selectedVariables?.length > 5;
});
// const isShareYAxis = computed(() => props.activeSettings?.shareYAxis);

const toggleLogScale = (useLogScale: boolean) => {
emit('update-settings', { scale: useLogScale ? 'log' : '' });
};

const toggleSmallMultiples = (smallMultiples: boolean) => {
emit('update-settings', { smallMultiples: !!smallMultiples });
// Settings for comparison method
const comparisonSettings = computed(() => props.activeSettings as ChartSettingComparison | null);
const smallMultiplesRadioValue = computed(() =>
comparisonSettings.value?.smallMultiples ? 'small-multiples' : 'all-charts'
);
const onSmallMultiplesRadioButtonChange = (value: 'all-charts' | 'small-multiples') => {
emit('update-settings', { smallMultiples: value === 'small-multiples' });
};

// const toggleShareYAxis = (shareYAxis: boolean) => {
// emit('update-settings', { shareYAxis: !!shareYAxis });
// };
const isShareYAxis = computed(() => Boolean(comparisonSettings.value?.shareYAxis));
const showBeforeAfter = computed(() => Boolean(comparisonSettings.value?.showBeforeAfter));
const toggleShareYAxis = (value: boolean) => emit('update-settings', { shareYAxis: value });
const toggleShowBeforeAfter = (value: boolean) => emit('update-settings', { showBeforeAfter: value });
// ==============================

// Primary color
const isColorPickerEnabled = computed(() => {
Expand All @@ -132,7 +146,6 @@ const chartAnnotations = computed(() => {
});
const isGeneratingAnnotation = ref(false);
const generateAnnotationQuery = ref<string>('');
const showAnnotationInput = ref<Boolean>(false);

const createAnnotation = async () => {
if (props.generateAnnotation === undefined || props.activeSettings === null) {
Expand All @@ -141,7 +154,6 @@ const createAnnotation = async () => {
isGeneratingAnnotation.value = true;
const newAnnotation = await props.generateAnnotation(props.activeSettings, generateAnnotationQuery.value);
isGeneratingAnnotation.value = false;
showAnnotationInput.value = false;
generateAnnotationQuery.value = '';
emit('create-annotation', newAnnotation);
};
Expand All @@ -150,8 +162,8 @@ const createAnnotationDebounced = _.debounce(createAnnotation, 100);

const cancelGenerateAnnotation = () => {
generateAnnotationQuery.value = '';
showAnnotationInput.value = false;
};
// ==============================
</script>

<style scoped>
Expand Down Expand Up @@ -208,6 +220,12 @@ const cancelGenerateAnnotation = () => {
background: var(--surface-0);
}

.items-wrapper {
display: flex;
flex-direction: column;
gap: var(--gap-2);
}

.annotation-input:deep(main) {
padding: var(--gap-2-5) var(--gap-2);
}
Expand Down
31 changes: 22 additions & 9 deletions packages/client/hmi-client/src/composables/useChartSettings.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { cloneDeep } from 'lodash';
import { ref, computed, watch } from 'vue';
import { ChartSetting, ChartSettingEnsembleVariable, ChartSettingSensitivity, ChartSettingType } from '@/types/common';
import {
ChartSetting,
ChartSettingComparison,
ChartSettingEnsembleVariable,
ChartSettingSensitivity,
ChartSettingType
} from '@/types/common';
import {
EnsembleVariableChartSettingOption,
removeChartSettingById,
updateChartSettingsBySelectedVariables,
updateAllChartSettings,
updateSensitivityChartSettingOption,
CHART_SETTING_WITH_QUANTILES_OPTIONS,
createNewChartSetting
createNewChartSetting,
isChartSettingComparisonVariable
} from '@/services/chart-settings';
import { WorkflowNode } from '@/types/workflow';

Expand Down Expand Up @@ -52,9 +59,7 @@ export function useChartSettings(
const selectedErrorVariableSettings = computed(() =>
chartSettings.value.filter((setting) => setting.type === ChartSettingType.ERROR_DISTRIBUTION)
);
const selectedComparisonChartSettings = computed(() =>
chartSettings.value.filter((setting) => setting.type === ChartSettingType.VARIABLE_COMPARISON)
);
const selectedComparisonChartSettings = computed(() => chartSettings.value.filter(isChartSettingComparisonVariable));

const selectedSensitivityChartSettings = computed(
() =>
Expand Down Expand Up @@ -98,10 +103,18 @@ export function useChartSettings(
};

const updateComparisonChartSetting = (chartId: string, selectedVariables: string[]) => {
findAndUpdateChartSettingsById(chartId, {
name: selectedVariables.join(', '),
selectedVariables
});
const state = cloneDeep(props.node.state);
if (!state.chartSettings) return;
const setting = state.chartSettings.find(
(settings) => settings.id === chartId && settings.type === ChartSettingType.VARIABLE_COMPARISON
) as ChartSettingComparison | undefined;
if (!setting) return;
Object.assign(setting, { selectedVariables, name: selectedVariables.join(', ') });
if (setting.smallMultiples === undefined && selectedVariables.length > 5) {
// If there are more than 5 variables and the option isn't set yet, enable small multiples by default
setting.smallMultiples = true;
}
emit('update-state', state);
};

const updateEnsembleVariableSettingOption = (option: EnsembleVariableChartSettingOption, value: boolean) => {
Expand Down
Loading