@@ -749,6 +749,23 @@ async function loadPlot(statistic, plotType, parameters = {}) {
749749 return ;
750750 }
751751
752+ // Validate plot data exists
753+ if (! response .plot_data || ! response .plot_data .data ) {
754+ console .error (' Invalid plot data, aborting render' );
755+ error = ' Plot data is missing or invalid' ;
756+ return ;
757+ }
758+
759+ // Cleanup existing plot if any (prevents memory leaks and rendering conflicts)
760+ if (plotDiv ._plotly ) {
761+ console .log (' Cleaning up existing Plotly instance' );
762+ try {
763+ Plotly .purge (plotDiv);
764+ } catch (purgeErr) {
765+ console .warn (' Plotly.purge warning:' , purgeErr);
766+ }
767+ }
768+
752769 // Ensure layout uses full width - don't set explicit width, use autosize
753770 const layout = {
754771 ... response .plot_data .layout ,
@@ -760,6 +777,12 @@ async function loadPlot(statistic, plotType, parameters = {}) {
760777
761778 console .log (' Calling Plotly.newPlot...' );
762779 try {
780+ // Final guard: verify element still valid and request not superseded
781+ if (! plotDiv || ! document .body .contains (plotDiv) || currentRequestId !== plotRequestId || ! componentMounted) {
782+ console .log (' Pre-render validation failed, aborting' );
783+ return ;
784+ }
785+
763786 // response.plot_data is the full Plotly figure JSON
764787 Plotly .newPlot (plotDiv, response .plot_data .data , layout, {
765788 responsive: true ,
@@ -1292,7 +1315,7 @@ async function loadPlot(statistic, plotType, parameters = {}) {
12921315 < div class = " font-semibold mb-2" > Error : < / div>
12931316 < pre class = " whitespace-pre-wrap text-sm font-mono overflow-x-auto" > {error}< / pre>
12941317 < / div>
1295- {: else if plotData}
1318+ {: else if plotData? . plot_data || plotData ? . multiplePlots }
12961319 < div class = " w-full space-y-6" >
12971320 {#if plotData .cache_hit }
12981321 < div class = " flex justify-end mb-2" >
@@ -1313,11 +1336,20 @@ async function loadPlot(statistic, plotType, parameters = {}) {
13131336 < / div>
13141337 {/ each}
13151338 {: else }
1316- < div class = " w-full rounded-lg border-2 border-border/50 shadow-md overflow-hidden bg-white h-[500px]" >
1317- < div bind: this = {plotDiv} class = " w-full h-full" >< / div>
1318- < / div>
1339+ {#key plotData .statistic + plotData .plotType + (plotData .cache_hit || ' ' )}
1340+ < div class = " w-full rounded-lg border-2 border-border/50 shadow-md overflow-hidden bg-white h-[500px]" >
1341+ < div bind: this = {plotDiv} class = " w-full h-full" >< / div>
1342+ < / div>
1343+ {/ key}
13191344 {/ if }
13201345 < / div>
1346+ {: else if plotData && ! plotData .plot_data && ! plotData .multiplePlots }
1347+ < div class = " text-center py-12" >
1348+ < div class = " bg-yellow-50 border border-yellow-300 text-yellow-800 px-4 py-3 rounded-lg inline-block" >
1349+ < div class = " font-semibold mb-2" > Invalid Plot Data< / div>
1350+ < p class = " text-sm" > The plot data received is incomplete or invalid.< / p>
1351+ < / div>
1352+ < / div>
13211353 {: else }
13221354 < div class = " text-center py-12" >
13231355 < div class = " flex flex-col items-center gap-3" >
@@ -1665,7 +1697,7 @@ async function loadPlot(statistic, plotType, parameters = {}) {
16651697 < div class = " font-semibold mb-2" > Error : < / div>
16661698 < pre class = " whitespace-pre-wrap text-sm font-mono overflow-x-auto" > {error}< / pre>
16671699 < / div>
1668- {: else if plotData}
1700+ {: else if plotData? . plot_data || plotData ? . multiplePlots }
16691701 < div class = " w-full space-y-6" >
16701702 {#if plotData .cache_hit }
16711703 < div class = " flex justify-end mb-2" >
@@ -1687,12 +1719,21 @@ async function loadPlot(statistic, plotType, parameters = {}) {
16871719 < / div>
16881720 {/ each}
16891721 {: else }
1690- <!-- Single merged plot -->
1691- < div class = " w-full rounded-lg border-2 border-border/50 shadow-md overflow-hidden bg-white h-[500px]" >
1692- < div bind: this = {plotDiv} class = " w-full h-full" >< / div>
1693- < / div>
1722+ <!-- Single merged plot - use key to force recreation when data changes -->
1723+ {#key plotData .statistic + plotData .plotType + (plotData .cache_hit || ' ' )}
1724+ < div class = " w-full rounded-lg border-2 border-border/50 shadow-md overflow-hidden bg-white h-[500px]" >
1725+ < div bind: this = {plotDiv} class = " w-full h-full" >< / div>
1726+ < / div>
1727+ {/ key}
16941728 {/ if }
16951729 < / div>
1730+ {: else if plotData && ! plotData .plot_data && ! plotData .multiplePlots }
1731+ < div class = " text-center py-12" >
1732+ < div class = " bg-yellow-50 border border-yellow-300 text-yellow-800 px-4 py-3 rounded-lg inline-block" >
1733+ < div class = " font-semibold mb-2" > Invalid Plot Data< / div>
1734+ < p class = " text-sm" > The plot data received is incomplete or invalid.< / p>
1735+ < / div>
1736+ < / div>
16961737 {: else }
16971738 < div class = " text-center py-12" >
16981739 < div class = " flex flex-col items-center gap-3" >
0 commit comments