@@ -208,15 +208,15 @@ def run_interactive( # pylint: disable=too-many-locals,too-many-statements
208208 suppress_callback_exceptions = True ,
209209 )
210210
211- # Load first step to know dimensionality and initial range
211+ # Load first step to know dimensionality and available variables
212212 init = _load (steps [0 ], read_func )
213213 ndim = init .ndim
214- d0 = init .variables [varname ]
215- pos0 = d0 [d0 > 0 ] if np .any (d0 > 0 ) else d0
216- init_min = float (np .nanmin (pos0 ))
217- init_max = float (np .nanmax (d0 ))
214+ all_varnames = sorted (init .variables .keys ())
215+ if varname not in all_varnames :
216+ varname = all_varnames [0 ] if all_varnames else varname
218217
219218 step_opts = [{'label' : str (s ), 'value' : s } for s in steps ]
219+ var_opts = [{'label' : v , 'value' : v } for v in all_varnames ]
220220 cmap_opts = [{'label' : c , 'value' : c } for c in _CMAPS ]
221221
222222 if ndim == 3 :
@@ -241,10 +241,19 @@ def run_interactive( # pylint: disable=too-many-locals,too-many-statements
241241 'fontSize' : '16px' , 'fontWeight' : 'bold' , 'color' : _ACCENT ,
242242 }),
243243 html .Div (
244- f'var: { varname } · { ndim } D · { len (steps )} step{ "s" if len (steps ) != 1 else "" } ' ,
244+ f'{ ndim } D · { len (steps )} step{ "s" if len (steps ) != 1 else "" } ' ,
245245 style = {'fontSize' : '11px' , 'color' : _MUTED },
246246 ),
247247
248+ # ── Variable ──────────────────────────────────────────────────
249+ _section ('Variable' ,
250+ dcc .Dropdown (
251+ id = 'var-sel' , options = var_opts , value = varname , clearable = False ,
252+ style = {'fontSize' : '12px' , 'backgroundColor' : _OVER ,
253+ 'border' : f'1px solid { _BORD } ' },
254+ ),
255+ ),
256+
248257 # ── Timestep ──────────────────────────────────────────────────
249258 _section ('Timestep' ,
250259 dcc .Dropdown (
@@ -454,14 +463,16 @@ def _toggle_controls(mode):
454463 Output ('vmin-inp' , 'value' ),
455464 Output ('vmax-inp' , 'value' ),
456465 Input ('reset-btn' , 'n_clicks' ),
466+ Input ('var-sel' , 'value' ),
457467 prevent_initial_call = True ,
458468 )
459- def _reset_range (_ ):
469+ def _reset_range (_reset , _var ):
460470 return None , None
461471
462472 @app .callback ( # pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals,too-many-branches,too-many-statements
463473 Output ('viz-graph' , 'figure' ),
464474 Output ('status-bar' , 'children' ),
475+ Input ('var-sel' , 'value' ),
465476 Input ('step-sel' , 'value' ),
466477 Input ('mode-sel' , 'value' ),
467478 Input ('slice-axis' , 'value' ),
@@ -479,14 +490,15 @@ def _reset_range(_):
479490 Input ('vmin-inp' , 'value' ),
480491 Input ('vmax-inp' , 'value' ),
481492 )
482- def _update (step , mode ,
493+ def _update (var_sel , step , mode ,
483494 slice_axis , slice_pos ,
484495 iso_min_frac , iso_max_frac , iso_n , iso_caps ,
485496 vol_opacity , vol_nsurf , vol_min_frac , vol_max_frac ,
486497 cmap , log_chk , vmin_in , vmax_in ):
487498
499+ selected_var = var_sel or varname
488500 ad = _load (step , read_func )
489- raw = ad .variables [varname ]
501+ raw = ad .variables [selected_var ]
490502 log = bool (log_chk and 'log' in log_chk )
491503 cmap = cmap or 'viridis'
492504
@@ -508,18 +520,18 @@ def _tf(arr):
508520 return np .where (arr > 0 , np .log10 (np .maximum (arr , 1e-300 )), np .nan )
509521 cmin = float (np .log10 (max (vmin , 1e-300 )))
510522 cmax = float (np .log10 (max (vmax , 1e-300 )))
511- cbar_title = f'log\u2081 \u2080 ({ varname } )'
523+ cbar_title = f'log\u2081 \u2080 ({ selected_var } )'
512524 else :
513525 def _tf (arr ): return arr
514526 cmin , cmax = vmin , vmax
515- cbar_title = varname
527+ cbar_title = selected_var
516528
517529 fig = go .Figure ()
518530 title = ''
519531
520532 if ad .ndim == 3 :
521533 trace , title = _build_3d (
522- ad , raw , varname , step , mode , cmap , _tf , cmin , cmax , cbar_title ,
534+ ad , raw , selected_var , step , mode , cmap , _tf , cmin , cmax , cbar_title ,
523535 slice_axis or 'z' , float (slice_pos or 0.5 ),
524536 float (iso_min_frac or 0.2 ), float (iso_max_frac or 0.8 ),
525537 int (iso_n or 3 ), bool (iso_caps and 'caps' in iso_caps ),
@@ -557,21 +569,21 @@ def _tf(arr): return arr
557569 yaxis = dict (title = 'y' , color = _TEXT , gridcolor = _OVER ),
558570 plot_bgcolor = _BG ,
559571 )
560- title = f'{ varname } · step { step } '
572+ title = f'{ selected_var } · step { step } '
561573
562574 else : # 1D
563575 plot_y = _tf (raw ) if log else raw
564576 fig .add_trace (go .Scatter (
565577 x = ad .x_cc , y = plot_y , mode = 'lines' ,
566- line = dict (color = _ACCENT , width = 2 ), name = varname ,
578+ line = dict (color = _ACCENT , width = 2 ), name = selected_var ,
567579 ))
568580 fig .update_layout (
569581 xaxis = dict (title = 'x' , color = _TEXT , gridcolor = _OVER ),
570582 yaxis = dict (title = cbar_title , color = _TEXT , gridcolor = _OVER ,
571583 range = [cmin , cmax ] if (vmin_in or vmax_in ) else None ),
572584 plot_bgcolor = _BG ,
573585 )
574- title = f'{ varname } · step { step } '
586+ title = f'{ selected_var } · step { step } '
575587
576588 fig .update_layout (
577589 title = dict (text = title , font = dict (color = _TEXT , size = 13 , family = 'monospace' )),
0 commit comments