Skip to content

Commit 143638a

Browse files
authored
Fixed some issues with plots.
2 parents 90c3cc7 + c2f2de6 commit 143638a

File tree

4 files changed

+90
-17
lines changed

4 files changed

+90
-17
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"url": "git+https://github.com/opencor/webapp.git"
2424
},
2525
"type": "module",
26-
"version": "0.20260319.1",
26+
"version": "0.20260319.2",
2727
"engines": {
2828
"bun": ">=1.2.0"
2929
},

src/renderer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
},
4343
"./style.css": "./dist/opencor.css"
4444
},
45-
"version": "0.20260319.1",
45+
"version": "0.20260319.2",
4646
"scripts": {
4747
"build": "vite build && bun scripts/generate.version.js",
4848
"build:lib": "vite build --config vite.lib.config.ts && bun scripts/copy.indexdts.js",

src/renderer/src/components/views/SimulationExperimentView.vue

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
</div>
143143
<div class="flex flex-col gap-2">
144144
<div v-for="(run, index) in interactiveRuns"
145-
:key="run.isLiveRun ? 'live' : `run_${index}`"
145+
:key="run.id"
146146
class="run-card rounded-lg p-1 pl-2 opacity-75 hover:opacity-100"
147147
:class="{ 'run-card-live': run.isLiveRun, 'opacity-50': !run.isVisible }"
148148
>
@@ -262,6 +262,7 @@ import GraphPanelWidget from '../widgets/GraphPanelWidget.vue';
262262
import type { IGraphPanelData, IGraphPanelPlotTrace, IGraphPanelMargins } from '../widgets/GraphPanelWidget.vue';
263263
264264
interface ISimulationRun {
265+
id: string;
265266
inputParameters: Record<string, number>;
266267
isVisible: boolean;
267268
data: IGraphPanelData[];
@@ -579,6 +580,7 @@ const interactiveShowInput = vue.ref<boolean[]>([]);
579580
const interactiveIdToInfo: Record<string, locCommon.ISimulationDataInfo> = {};
580581
const interactiveRuns = vue.ref<ISimulationRun[]>([
581582
{
583+
id: 'live',
582584
inputParameters: {},
583585
isVisible: true,
584586
data: [],
@@ -587,6 +589,7 @@ const interactiveRuns = vue.ref<ISimulationRun[]>([
587589
isLiveRun: true
588590
}
589591
]);
592+
let interactiveTrackedRunId = 0;
590593
const interactiveRunColorPopoverIndex = vue.ref<number>(-1);
591594
const interactiveRunColorPopoverRefs = vue.ref<Record<number, InstanceType<typeof Popover> | undefined>>({});
592595
const interactiveGraphPanelRefs = vue.ref<Record<number, InstanceType<typeof GraphPanelWidget> | undefined>>({});
@@ -634,6 +637,7 @@ const interactiveCompData = vue.computed<IGraphPanelData[]>(() => {
634637
635638
traces.push({
636639
...dataTrace,
640+
traceId: `${interactiveRun.id}::${dataTrace.traceId ?? `${dataTrace.xValue}::${dataTrace.yValue}::${String(dataTraceIndex)}`}`,
637641
name: dataTrace.name + suffix,
638642
color: paletteColors[(baseColorIndex + dataTraceIndex) % paletteColorsLength] ?? colors.DEFAULT_COLOR,
639643
zorder: interactiveRun.isLiveRun ? 1 : undefined
@@ -806,10 +810,6 @@ const updateInteractiveSimulation = (forceUpdate: boolean = false): void => {
806810
return;
807811
}
808812
809-
// Reset our interactive margins.
810-
811-
onResetMargins();
812-
813813
// Run the instance and update the plots.
814814
815815
interactiveInstance.run();
@@ -898,13 +898,26 @@ const updateInteractiveSimulation = (forceUpdate: boolean = false): void => {
898898
try {
899899
const newInteractiveData: IGraphPanelData[] = [];
900900
901-
for (const plot of interactiveUiJson.value.output.plots) {
901+
for (let plotIndex = 0; plotIndex < interactiveUiJson.value.output.plots.length; ++plotIndex) {
902+
const plot = interactiveUiJson.value.output.plots[plotIndex];
903+
904+
if (!plot) {
905+
newInteractiveData[plotIndex] = {
906+
xAxisTitle: '',
907+
yAxisTitle: '',
908+
traces: []
909+
};
910+
911+
continue;
912+
}
913+
902914
const xMain = evaluate(plot.xValue);
903915
const yMain = evaluate(plot.yValue);
904916
const normalisedMain = normaliseFloat64Arrays(xMain, yMain);
905917
906918
const traces: IGraphPanelPlotTrace[] = [
907919
{
920+
traceId: `plot_${String(plotIndex)}::trace_0`,
908921
name: traceName(plot.name, plot.xValue, plot.yValue),
909922
xValue: plot.xValue,
910923
x: normalisedMain.x,
@@ -914,12 +927,23 @@ const updateInteractiveSimulation = (forceUpdate: boolean = false): void => {
914927
}
915928
];
916929
917-
for (const additionalTrace of plot.additionalTraces ?? []) {
930+
for (
931+
let additionalTraceIndex = 0;
932+
additionalTraceIndex < (plot.additionalTraces ?? []).length;
933+
++additionalTraceIndex
934+
) {
935+
const additionalTrace = plot.additionalTraces?.[additionalTraceIndex];
936+
937+
if (!additionalTrace) {
938+
continue;
939+
}
940+
918941
const xAdditional = evaluate(additionalTrace.xValue);
919942
const yAdditional = evaluate(additionalTrace.yValue);
920943
const normalisedAdditional = normaliseFloat64Arrays(xAdditional, yAdditional);
921944
922945
traces.push({
946+
traceId: `plot_${String(plotIndex)}::trace_${String(additionalTraceIndex + 1)}`,
923947
name: traceName(additionalTrace.name, additionalTrace.xValue, additionalTrace.yValue),
924948
xValue: additionalTrace.xValue,
925949
x: normalisedAdditional.x,
@@ -929,11 +953,11 @@ const updateInteractiveSimulation = (forceUpdate: boolean = false): void => {
929953
});
930954
}
931955
932-
newInteractiveData.push({
956+
newInteractiveData[plotIndex] = {
933957
xAxisTitle: plot.xAxisTitle,
934958
yAxisTitle: plot.yAxisTitle,
935959
traces
936-
});
960+
};
937961
}
938962
939963
interactiveLiveData.value = newInteractiveData;
@@ -1083,6 +1107,7 @@ const onTrackRun = (): void => {
10831107
// Add the new run.
10841108
10851109
interactiveRuns.value.push({
1110+
id: `run_${String(++interactiveTrackedRunId)}`,
10861111
inputParameters,
10871112
isVisible: true,
10881113
data: interactiveLiveData.value,
@@ -1200,6 +1225,8 @@ const onInteractiveSettingsOk = (settings: ISimulationExperimentViewSettings): v
12001225
// Resize our graph panels if the number of plots has changed.
12011226
12021227
if (interactiveUiJson.value.output.plots.length !== oldNbOfGraphPanelWidgets) {
1228+
onResetMargins();
1229+
12031230
interactiveGraphPanelRefs.value = {};
12041231
12051232
vue.nextTick().then(() => {

src/renderer/src/components/widgets/GraphPanelWidget.vue

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface IPlotlyLayout {
3434
3535
export interface IGraphPanelPlotTrace {
3636
name: string;
37+
traceId?: string;
3738
xValue: string;
3839
x: Float64Array;
3940
yValue: string;
@@ -42,6 +43,16 @@ export interface IGraphPanelPlotTrace {
4243
zorder?: number;
4344
}
4445
46+
type PlotlyTraceVisible = boolean | 'legendonly';
47+
48+
interface IPlotlyTraceState {
49+
name?: string;
50+
traceId?: string;
51+
xValue?: string;
52+
yValue?: string;
53+
visible?: PlotlyTraceVisible;
54+
}
55+
4556
export interface IGraphPanelData {
4657
xAxisTitle?: string;
4758
yAxisTitle?: string;
@@ -594,11 +605,13 @@ const updateMarginsAsync = (): void => {
594605
595606
updatingMargins = true;
596607
597-
// Use requestAnimationFrame for optimal timing (after render, before next paint).
608+
// Use requestAnimationFrame for optimal timing.
598609
599610
requestAnimationFrame(() => {
600611
const newMargins = compMargins();
601612
613+
// Emit an update if our margins have changed.
614+
602615
if (!sameMargins(trackedMargins, newMargins)) {
603616
trackedMargins = newMargins;
604617
@@ -643,11 +656,40 @@ const updatePlot = (): void => {
643656
644657
// Update the plots.
645658
646-
const traces = props.data.traces.map((trace) => ({
647-
...trace,
648-
line: { color: trace.color },
649-
legendrank: trace.zorder
650-
}));
659+
const traceVisibilityKey = (trace: IPlotlyTraceState): string | undefined => {
660+
if (trace.traceId) {
661+
return `id::${trace.traceId}`;
662+
}
663+
664+
if (trace.name && trace.xValue && trace.yValue) {
665+
return `expr::${trace.xValue}::${trace.yValue}::${trace.name}`;
666+
}
667+
668+
return undefined;
669+
};
670+
671+
const previousTraceVisibilityByKey: Record<string, PlotlyTraceVisible> = {};
672+
const previousPlotlyData = (mainDivRef.value as unknown as { data?: IPlotlyTraceState[] })?.data;
673+
674+
for (const plotlyTrace of previousPlotlyData ?? []) {
675+
const plotlyTraceKey = traceVisibilityKey(plotlyTrace);
676+
677+
if (plotlyTraceKey && plotlyTrace.visible !== undefined) {
678+
previousTraceVisibilityByKey[plotlyTraceKey] = plotlyTrace.visible;
679+
}
680+
}
681+
682+
const traces = props.data.traces.map((trace) => {
683+
const traceKey = traceVisibilityKey(trace);
684+
const visible = traceKey ? previousTraceVisibilityByKey[traceKey] : undefined;
685+
686+
return {
687+
...trace,
688+
visible,
689+
line: { color: trace.color },
690+
legendrank: trace.zorder
691+
};
692+
});
651693
652694
dependencies._plotlyJs
653695
.react(
@@ -813,6 +855,10 @@ vue.watch(
813855
})
814856
.then(() => {
815857
if (!props.margins) {
858+
// When shared margins are unset, we need to clear our tracked margins so that we can emit them.
859+
860+
trackedMargins = undefined;
861+
816862
updateMarginsAsync();
817863
}
818864
});

0 commit comments

Comments
 (0)