@@ -269,75 +269,60 @@ export function VerticalProfilePlot({
269269
270270 const showPlume = createMemo ( ( ) => isPlumeVariable ( classVariable ( ) ) ) ;
271271
272- const observations = ( ) =>
273- flatObservations ( ) . map ( ( o ) => observationsForProfile ( o , classVariable ( ) ) ) ;
274-
275- function extractLines < T extends Record < string , number [ ] > > (
276- data : T ,
277- xvar : keyof T ,
278- yvar : keyof T ,
279- ) {
280- const xs = data [ xvar ] ?? [ ] ;
281- const ys = data [ yvar ] ?? [ ] ;
282-
283- const n = Math . min ( xs . length , ys . length ) ;
284-
285- const result = new Array ( n ) ;
286- for ( let i = 0 ; i < n ; i ++ ) {
287- result [ i ] = { x : xs [ i ] , y : ys [ i ] } ;
288- }
289-
290- return result ;
291- }
292-
293- const profileData = ( ) =>
294- flatExperiments ( ) . map ( ( e ) => {
272+ // Precalculate profile lines for classVariable() for all times
273+ const allProfileLines = ( ) =>
274+ flatExperiments ( ) . flatMap ( ( e ) => {
295275 const { config, output, ...formatting } = e ;
296276
297- const targetTime = uniqueTimes ( ) [ analysis . time ] ;
298- const t = output ?. timeseries . utcTime . indexOf ( targetTime ) ;
299-
300- const profile =
301- ( t != null && t !== - 1 && output ?. profiles ?. [ t ] ) || noProfile ;
277+ return uniqueTimes ( ) . map ( ( time , tIndex ) => {
278+ const profile = output ?. profiles ?. [ tIndex ] ?? noProfile ;
302279
303- return {
304- ...formatting ,
305- data : extractLines ( profile , classVariable ( ) , "z" ) ,
306- } ;
280+ return {
281+ ...formatting ,
282+ time,
283+ tIndex,
284+ data : extractLine ( profile , classVariable ( ) , "z" ) ,
285+ } ;
286+ } ) ;
307287 } ) ;
308288
309- const firePlumes = ( ) =>
310- flatExperiments ( ) . map ( ( e ) => {
289+ // Also precalculate plume lines
290+ const allPlumeLines = ( ) =>
291+ flatExperiments ( ) . flatMap ( ( e ) => {
311292 const { config, output, ...formatting } = e ;
312293
313- const targetTime = uniqueTimes ( ) [ analysis . time ] ;
314- const t = output ?. timeseries . utcTime . indexOf ( targetTime ) ;
315-
316- const plume = ( t != null && t !== - 1 && output ?. plumes ?. [ t ] ) || noPlume ;
294+ return uniqueTimes ( ) . map ( ( time , tIndex ) => {
295+ const plume = output ?. plumes ?. [ tIndex ] ?? noPlume ;
317296
318- return {
319- ...formatting ,
320- linestyle : "4" ,
321- data : extractLines ( plume , classVariable ( ) as PlumeVariable , "z" ) ,
322- } ;
297+ return {
298+ ...formatting ,
299+ time,
300+ tIndex,
301+ linestyle : "4" ,
302+ data : extractLine ( plume , classVariable ( ) as PlumeVariable , "z" ) ,
303+ } ;
304+ } ) ;
323305 } ) ;
324-
325- const allX = ( ) => [
326- ...firePlumes ( ) . flatMap ( ( p ) => p . data . map ( ( d ) => d . x ) ) ,
327- ...profileDataForPlot ( ) . flatMap ( ( p ) => p . data . map ( ( d ) => d . x ) ) ,
328- ...observations ( ) . flatMap ( ( obs ) => obs . data . map ( ( d ) => d . x ) ) ,
329- ] ;
330- const allY = ( ) => [
331- ...firePlumes ( ) . flatMap ( ( p ) => p . data . map ( ( d ) => d . z ) ) ,
332- ...profileDataForPlot ( ) . flatMap ( ( p ) => p . data . map ( ( d ) => d . z ) ) ,
333- ...observations ( ) . flatMap ( ( obs ) => obs . data . map ( ( d ) => d . z ) ) ,
306+
307+ const observationLines = ( ) =>
308+ flatObservations ( ) . map ( ( o ) => observationsForProfile ( o , classVariable ( ) ) ) ;
309+
310+ const allLines = ( ) => [
311+ ...allPlumeLines ( ) ,
312+ ...allProfileLines ( ) ,
313+ ...observationLines ( ) ,
334314 ] ;
335315
336- const xLim = ( ) => getNiceAxisLimits ( allX ( ) , 0 ) ;
337- const yLim = ( ) => [ 0 , getNiceAxisLimits ( allY ( ) , 0 ) [ 1 ] ] as [ number , number ] ;
316+ const limits = ( ) => {
317+ const { xmin, xmax, ymin, ymax } = extractLimits ( allLines ( ) ) ;
318+ return { xLim : [ xmin , xmax ] , yLim : [ ymin , ymax ] } ;
319+ } ;
320+
321+ const xLim = ( ) => getNiceAxisLimits ( limits ( ) . xLim ) ;
322+ const yLim = ( ) => getNiceAxisLimits ( limits ( ) . yLim ) ;
338323
339324 function chartData ( ) {
340- return [ ...profileData ( ) , ...observations ( ) ] ;
325+ return [ ...allPlumeLines ( ) , ...observationLines ( ) ] ;
341326 }
342327
343328 const [ toggles , setToggles ] = createStore < Record < string , boolean > > ( { } ) ;
@@ -356,33 +341,43 @@ export function VerticalProfilePlot({
356341 setResetPlot ( analysis . id ) ;
357342 }
358343
344+ const profilesAtSelectedTime = ( ) => {
345+ const t = analysis . time ;
346+ return allProfileLines ( ) . filter ( ( line ) => line . tIndex === t ) ;
347+ } ;
348+
349+ const plumesAtSelectedTime = ( ) => {
350+ const t = analysis . time ;
351+ return allPlumeLines ( ) . filter ( ( line ) => line . tIndex === t ) ;
352+ } ;
353+
359354 return (
360355 < >
361356 < div class = "flex flex-col gap-2" >
362357 < ChartContainer >
363358 < Legend
364- entries = { ( ) => [ ...profileData ( ) , ...observations ( ) ] }
359+ entries = { ( ) => [ ...profilesAtSelectedTime ( ) , ...observationLines ( ) ] }
365360 toggles = { toggles }
366361 onChange = { toggleLine }
367362 />
368363 < Chart id = { analysis . id } title = "Vertical profile plot" >
369364 < AxisBottom domain = { xLim } label = { analysis . variable } />
370365 < AxisLeft domain = { yLim } label = "Height[m]" />
371- < For each = { profileDataForPlot ( ) } >
366+ < For each = { profilesAtSelectedTime ( ) } >
372367 { ( d ) => (
373368 < Show when = { toggles [ d . label ] } >
374369 < Line { ...d } />
375370 </ Show >
376371 ) }
377372 </ For >
378- < For each = { observations ( ) } >
373+ < For each = { observationLines ( ) } >
379374 { ( d ) => (
380375 < Show when = { toggles [ d . label ] } >
381376 < Line { ...d } />
382377 </ Show >
383378 ) }
384379 </ For >
385- < For each = { firePlumes ( ) } >
380+ < For each = { plumesAtSelectedTime ( ) } >
386381 { ( d ) => (
387382 < Show when = { toggles [ d . label ] } >
388383 < Show when = { showPlume ( ) } >
@@ -630,3 +625,41 @@ export function AnalysisCard(analysis: Analysis) {
630625 </ Card >
631626 ) ;
632627}
628+
629+ // Helper functions
630+
631+ function extractLine < T extends Record < string , number [ ] > > (
632+ data : T ,
633+ xvar : keyof T ,
634+ yvar : keyof T ,
635+ ) {
636+ const xs = data [ xvar ] ?? [ ] ;
637+ const ys = data [ yvar ] ?? [ ] ;
638+
639+ const n = Math . min ( xs . length , ys . length ) ;
640+
641+ const result = new Array ( n ) ;
642+ for ( let i = 0 ; i < n ; i ++ ) {
643+ result [ i ] = { x : xs [ i ] , y : ys [ i ] } ;
644+ }
645+
646+ return result ;
647+ }
648+
649+ function extractLimits ( lines : { data : { x : number ; y : number } [ ] } [ ] ) {
650+ let xmin = Number . POSITIVE_INFINITY ;
651+ let xmax = Number . NEGATIVE_INFINITY ;
652+ let ymin = Number . POSITIVE_INFINITY ;
653+ let ymax = Number . NEGATIVE_INFINITY ;
654+
655+ for ( const line of lines ) {
656+ for ( const p of line . data ) {
657+ if ( p . x < xmin ) xmin = p . x ;
658+ if ( p . x > xmax ) xmax = p . x ;
659+ if ( p . y < ymin ) ymin = p . y ;
660+ if ( p . y > ymax ) ymax = p . y ;
661+ }
662+ }
663+
664+ return { xmin, xmax, ymin, ymax } ;
665+ }
0 commit comments