Skip to content

Commit 0de0666

Browse files
committed
fix : Adding UI fixes for arbitrary dimension selections
1 parent 3fbd8fc commit 0de0666

File tree

8 files changed

+199
-172
lines changed

8 files changed

+199
-172
lines changed

src/e3sm_quickview/app.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from e3sm_quickview.assets import ASSETS
1515
from e3sm_quickview.components import doc, file_browser, css, toolbars, dialogs, drawers
1616
from e3sm_quickview.pipeline import EAMVisSource
17-
from e3sm_quickview.utils import compute, js, constants, cli
17+
from e3sm_quickview.utils import compute, cli
1818
from e3sm_quickview.view_manager import ViewManager
1919

2020

@@ -45,6 +45,8 @@ def __init__(self, server=None):
4545
"variables_selected": [],
4646
# Control 'Load Variables' button availability
4747
"variables_loaded": False,
48+
# Dynamic type-color mapping (populated when data loads)
49+
"variable_types": [],
4850
# Dimension arrays (will be populated dynamically)
4951
"midpoints": [],
5052
"interfaces": [],
@@ -205,6 +207,7 @@ def _build_ui(self, **_):
205207
@property
206208
def selected_variables(self):
207209
from collections import defaultdict
210+
208211
vars_per_type = defaultdict(list)
209212
for var in self.state.variables_selected:
210213
type = self.source.varmeta[var].dimensions
@@ -365,18 +368,39 @@ async def data_loading_open(self, simulation, connectivity):
365368
self.state.variables_filter = ""
366369
self.state.variables_listing = [
367370
*(
368-
{"name": var.name, "type": str(var.dimensions), "id": f"{var.name}"}
371+
{
372+
"name": var.name,
373+
"type": str(var.dimensions),
374+
"id": f"{var.name}",
375+
}
369376
for _, var in self.source.varmeta.items()
370377
),
371378
]
372379

380+
# Build dynamic type-color mapping
381+
from e3sm_quickview.utils.colors import get_type_color
382+
383+
dim_types = sorted(
384+
set(str(var.dimensions) for var in self.source.varmeta.values())
385+
)
386+
self.state.variable_types = [
387+
{"name": t, "color": get_type_color(i)}
388+
for i, t in enumerate(dim_types)
389+
]
390+
373391
# Update Layer/Time values and ui layout
374392
n_cols = 0
375393
available_tracks = []
376394
for name, dim in self.source.dimmeta.items():
377395
values = dim.data
378396
# Convert to list for JSON serialization
379-
self.state[name] = values.tolist() if hasattr(values, 'tolist') else list(values) if values is not None else []
397+
self.state[name] = (
398+
values.tolist()
399+
if hasattr(values, "tolist")
400+
else list(values)
401+
if values is not None
402+
else []
403+
)
380404
if values is not None and len(values) > 1:
381405
n_cols += 1
382406
available_tracks.append({"title": name, "value": name})
@@ -387,8 +411,9 @@ async def data_loading_open(self, simulation, connectivity):
387411
if available_tracks
388412
else None
389413
)
390-
414+
391415
from functools import partial
416+
392417
# Initialize dynamic index variables for each dimension
393418
for track in available_tracks:
394419
dim_name = track["value"]
@@ -397,7 +422,9 @@ async def data_loading_open(self, simulation, connectivity):
397422
self.state[index_var] = 50
398423
else:
399424
self.state[index_var] = 0
400-
self.state.change(index_var)(partial(self._on_slicing_change, dim_name, index_var))
425+
self.state.change(index_var)(
426+
partial(self._on_slicing_change, dim_name, index_var)
427+
)
401428

402429
@controller.set("file_selection_cancel")
403430
def data_loading_hide(self):
@@ -414,10 +441,8 @@ async def _data_load_variables(self):
414441

415442
# Flatten the list of lists
416443
flattened_vars = [var for var_list in vars_to_show.values() for var in var_list]
417-
418-
self.source.LoadVariables(
419-
flattened_vars
420-
)
444+
445+
self.source.LoadVariables(flattened_vars)
421446

422447
# Trigger source update + compute avg
423448
with self.state:
@@ -461,7 +486,7 @@ def _on_toolbar_change(self, active_tools, **_):
461486
if name == "select-slice-time":
462487
track_count = len(self.state.animation_tracks or [])
463488
rows_needed = max(1, (track_count + 2) // 3) # 3 sliders per row
464-
top_padding += 65 * rows_needed
489+
top_padding += 70 * rows_needed
465490
else:
466491
top_padding += toolbars.SIZES.get(name, 0)
467492

src/e3sm_quickview/components/drawers.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,26 @@ def __init__(self, load_variables=None):
6868

6969
with self:
7070
with html.Div(style="position:fixed;top:0;width: 500px;"):
71-
with v3.VCardActions(key="variables_selected.length"):
72-
for name, color in [
73-
("surfaces", "success"),
74-
("interfaces", "info"),
75-
("midpoints", "warning"),
76-
]:
77-
v3.VChip(
78-
js.var_title(name),
79-
color=color,
80-
v_show=js.var_count(name),
81-
size="small",
82-
closable=True,
83-
click_close=js.var_remove(name),
84-
)
71+
with v3.VCardActions(
72+
key="variables_selected.length",
73+
classes="flex-wrap",
74+
style="overflow-y: auto; max-height: 100px;",
75+
):
76+
v3.VChip(
77+
"{{ variables_selected.filter(id => variables_listing.find(v => v.id === id)?.type === vtype.name).length }} {{ vtype.name }}",
78+
v_for="(vtype, idx) in variable_types",
79+
key="idx",
80+
color=("vtype.color",),
81+
v_show=(
82+
"variables_selected.filter(id => variables_listing.find(v => v.id === id)?.type === vtype.name).length",
83+
),
84+
size="small",
85+
closable=True,
86+
click_close=(
87+
"variables_selected = variables_selected.filter(id => variables_listing.find(v => v.id === id)?.type !== vtype.name)",
88+
),
89+
classes="ma-1",
90+
)
8591

8692
v3.VSpacer()
8793
v3.VBtn(

src/e3sm_quickview/components/toolbars.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from trame.widgets import html, vuetify3 as v3, client
66

77

8-
from e3sm_quickview.utils import js, constants
8+
from e3sm_quickview.utils import js
99

1010
DENSITY = {
1111
"adjust-layout": "compact",
@@ -17,7 +17,7 @@
1717
SIZES = {
1818
"adjust-layout": 49,
1919
"adjust-databounds": 65,
20-
"select-slice-time": 65,
20+
"select-slice-time": 70,
2121
"animation-controls": 49,
2222
}
2323

@@ -236,24 +236,30 @@ def __init__(self):
236236
class DataSelection(html.Div):
237237
def __init__(self):
238238
style = to_kwargs("select-slice-time")
239-
style["classes"] = style["classes"] # + " d-flex align-center"
239+
# Use style instead of d-flex class to avoid !important override of v-show
240+
# Add background color to match VToolbar appearance
241+
style["style"] = (
242+
"display: flex; align-items: center; background: rgb(var(--v-theme-surface));"
243+
)
240244
super().__init__(**style)
241245

242246
with self:
243-
v3.VIcon("mdi-tune-variant", classes="ml-3 opacity-50")
244-
245-
with v3.VRow(classes="ma-0 pr-2 flex-wrap", dense=True):
247+
v3.VIcon("mdi-tune-variant", classes="ml-3 mr-2 opacity-50")
248+
249+
with v3.VRow(classes="ma-0 pr-2 flex-wrap flex-grow-1", dense=True):
246250
# Debug: Show animation_tracks array
247251
# html.Div("Animation Tracks: {{ JSON.stringify(animation_tracks) }}", classes="col-12")
248252
# Each track gets a column (3 per row)
249253
with v3.VCol(
250254
cols=4,
251255
v_for="(track, idx) in animation_tracks",
252256
key="idx",
253-
classes="pa-2"
257+
classes="pa-2",
254258
):
255259
with client.Getter(name=("track.value",), value_name="t_values"):
256-
with client.Getter(name=("track.value + '_idx'",), value_name="t_idx"):
260+
with client.Getter(
261+
name=("track.value + '_idx'",), value_name="t_idx"
262+
):
257263
with v3.VRow(classes="ma-0 align-center", dense=True):
258264
v3.VLabel(
259265
"{{track.title}}",
@@ -266,9 +272,12 @@ def __init__(self):
266272
)
267273
v3.VSlider(
268274
model_value=("t_idx",),
269-
update_modelValue=(self.on_update_slider, "[track.value, $event]"),
275+
update_modelValue=(
276+
self.on_update_slider,
277+
"[track.value, $event]",
278+
),
270279
min=0,
271-
#max=100,#("get(track.value).length - 1",),
280+
# max=100,#("get(track.value).length - 1",),
272281
max=("t_values.length - 1",),
273282
step=1,
274283
density="compact",

src/e3sm_quickview/pipeline.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import fnmatch
22
import json
3-
import numpy as np
43
import os
54

65

@@ -12,12 +11,11 @@
1211
LegacyVTKReader,
1312
)
1413

15-
from paraview import servermanager as sm
16-
from paraview.vtk.numpy_interface import dataset_adapter as dsa
1714
from vtkmodules.vtkCommonCore import vtkLogger
1815

1916
from collections import defaultdict
2017

18+
2119
# Define a VTK error observer
2220
class ErrorObserver:
2321
def __init__(self):
@@ -151,7 +149,6 @@ def UpdateSlicing(self, dimension, slice):
151149
x = json.dumps(self.slicing)
152150
self.data.Slicing = x
153151

154-
155152
def Update(self, data_file, conn_file, force_reload=False):
156153
# Check if we need to reload
157154
if (
@@ -165,7 +162,7 @@ def Update(self, data_file, conn_file, force_reload=False):
165162
self.conn_file = conn_file
166163

167164
if self.data is None:
168-
data = EAMSliceDataReader(
165+
data = EAMSliceDataReader( # noqa: F821
169166
registrationName="AtmosReader",
170167
ConnectivityFile=conn_file,
171168
DataFile=data_file,
@@ -180,7 +177,6 @@ def Update(self, data_file, conn_file, force_reload=False):
180177
for dim in self.dimmeta.keys():
181178
self.slicing[dim] = 0
182179

183-
print(self.slicing)
184180
self.observer.clear()
185181
else:
186182
self.data.DataFile = data_file
@@ -196,7 +192,7 @@ def Update(self, data_file, conn_file, force_reload=False):
196192
"Please check if the data and connectivity files exist "
197193
"and are compatible"
198194
)
199-
195+
200196
# Ensure TimestepValues is always a list
201197
timestep_values = self.data.TimestepValues
202198
if isinstance(timestep_values, (list, tuple)):
@@ -213,7 +209,7 @@ def Update(self, data_file, conn_file, force_reload=False):
213209
)
214210

215211
# Step 1: Extract and transform atmospheric data
216-
atmos_extract = EAMTransformAndExtract(
212+
atmos_extract = EAMTransformAndExtract( # noqa: F821
217213
registrationName="AtmosExtract", Input=self.data
218214
)
219215
atmos_extract.LongitudeRange = [-180.0, 180.0]
@@ -222,7 +218,7 @@ def Update(self, data_file, conn_file, force_reload=False):
222218
self.extents = atmos_extract.GetDataInformation().GetBounds()
223219

224220
# Step 2: Apply map projection to atmospheric data
225-
atmos_proj = EAMProject(
221+
atmos_proj = EAMProject( # noqa: F821
226222
registrationName="AtmosProj", Input=OutputPort(atmos_extract, 0)
227223
)
228224
atmos_proj.Projection = self.projection
@@ -247,26 +243,26 @@ def Update(self, data_file, conn_file, force_reload=False):
247243
self.globe = cont_contour
248244

249245
# Step 4: Extract and transform continent data
250-
cont_extract = EAMTransformAndExtract(
246+
cont_extract = EAMTransformAndExtract( # noqa: F821
251247
registrationName="ContExtract", Input=self.globe
252248
)
253249
cont_extract.LongitudeRange = [-180.0, 180.0]
254250
cont_extract.LatitudeRange = [-90.0, 90.0]
255251

256252
# Step 5: Apply map projection to continents
257-
cont_proj = EAMProject(
253+
cont_proj = EAMProject( # noqa: F821
258254
registrationName="ContProj", Input=OutputPort(cont_extract, 0)
259255
)
260256
cont_proj.Projection = self.projection
261257
cont_proj.Translate = 0
262258
cont_proj.UpdatePipeline()
263259

264260
# Step 6: Generate lat/lon grid lines
265-
grid_gen = EAMGridLines(registrationName="GridGen")
261+
grid_gen = EAMGridLines(registrationName="GridGen") # noqa: F821
266262
grid_gen.UpdatePipeline()
267263

268264
# Step 7: Apply map projection to grid lines
269-
grid_proj = EAMProject(
265+
grid_proj = EAMProject( # noqa: F821
270266
registrationName="GridProj", Input=OutputPort(grid_gen, 0)
271267
)
272268
grid_proj.Projection = self.projection
@@ -289,10 +285,10 @@ def Update(self, data_file, conn_file, force_reload=False):
289285
return self.valid
290286

291287
def LoadVariables(self, vars):
292-
print(f"Gonna Load {vars}")
293288
if not self.valid:
294289
return
295290
self.data.Variables = vars
296291

292+
297293
if __name__ == "__main__":
298294
e = EAMVisSource()

0 commit comments

Comments
 (0)