From 2bcb7df22097c971279395aef756c9d6fc60c112 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Wed, 1 Oct 2025 10:40:23 -0600 Subject: [PATCH 01/14] feat(vue3): update ui --- quickview/app2.py | 123 ++++++++++++++++++++++++++++++++ quickview/assets/__init__.py | 4 ++ quickview/assets/small-icon.png | Bin 0 -> 51134 bytes 3 files changed, 127 insertions(+) create mode 100644 quickview/app2.py create mode 100644 quickview/assets/__init__.py create mode 100644 quickview/assets/small-icon.png diff --git a/quickview/app2.py b/quickview/app2.py new file mode 100644 index 0000000..c95fffc --- /dev/null +++ b/quickview/app2.py @@ -0,0 +1,123 @@ +import json + +from pathlib import Path + +from trame.app import TrameApp +from trame.ui.vuetify3 import VAppLayout +from trame.widgets import vuetify3 as v3, paraview as pvw, client + +from quickview.pipeline import EAMVisSource +from quickview.assets import ASSETS + + +class EAMApp(TrameApp): + def __init__(self, server=None): + super().__init__(server) + + # CLI + cli = self.server.cli + cli.add_argument( + "-cf", + "--conn", + nargs="?", + help="the nc file with connnectivity information", + ) + cli.add_argument( + "-df", + "--data", + help="the nc file with data/variables", + ) + cli.add_argument( + "-sf", + "--state", + nargs="?", + help="state file to be loaded", + ) + cli.add_argument( + "-wd", + "--workdir", + default=str(Path.cwd().resolve()), + help="working directory (to store session data)", + ) + args, _ = cli.parse_known_args() + + # Data input + self.source = EAMVisSource() + self.app_state = {} + if args.state is not None: + self.app_state = json.loads(Path(args.state).read_text()) + self.source.Update(**{k: state[k] for k in ("data_file", "conn_file")}) + + # GUI + self._build_ui() + + def _build_ui(self, **_): + with VAppLayout(self.server, fill_height=True) as self.ui: + with v3.VLayout(): + with v3.VNavigationDrawer(permanent=True, rail=True): + with v3.VListItem(loading=True): + v3.VAvatar(image=ASSETS.icon) + v3.VProgressCircular( + color="primary", + indeterminate=True, + v_show="trame__busy", + style="position: absolute !important;left: 50%;top: 50%;transform: translate(-50%, -50%);", + ) + with v3.VList(density="compact", nav=True, v_model=("active_drawer", "load-data")): + v3.VListItem( + prepend_icon="mdi-file-document-outline", + value="load-data", + ) + v3.VListItem( + prepend_icon="mdi-database-check-outline", + value="select-fields", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-collage", + value="adjust-layout", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-compass-rose", + value="reset-camera", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-compass-rose", + value="reset-camera", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-cog", + value="settings", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-earth", + value="projection-sphere", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-earth-box", + value="projection-box", + disabled=True, + ) + v3.VListItem( + prepend_icon="mdi-folder-arrow-left-right-outline", + value="import-export", + disabled=True, + ) + + with v3.VMain(classes="bg-red"): + v3.VLabel("Hello") + + + +def main(): + app = EAMApp() + app.server.start() + + +if __name__ == "__main__": + main() diff --git a/quickview/assets/__init__.py b/quickview/assets/__init__.py new file mode 100644 index 0000000..b336786 --- /dev/null +++ b/quickview/assets/__init__.py @@ -0,0 +1,4 @@ +from trame.assets.local import LocalFileManager + +ASSETS = LocalFileManager(__file__) +ASSETS.url("icon", "small-icon.png") diff --git a/quickview/assets/small-icon.png b/quickview/assets/small-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0220cdf851469eb0ea6bba6e42ae963b1bb4f9 GIT binary patch literal 51134 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 literal 0 HcmV?d00001 From dcf2725b5226a5ea05cd2715023f8670dd9bb622 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Wed, 1 Oct 2025 17:51:08 -0600 Subject: [PATCH 02/14] feat(file): add file handling in webui --- quickview/app2.py | 278 +++++++++++++++--- quickview/components/__init__.py | 0 quickview/components/file_browser.py | 403 +++++++++++++++++++++++++++ quickview/components/variables.py | 0 4 files changed, 647 insertions(+), 34 deletions(-) create mode 100644 quickview/components/__init__.py create mode 100644 quickview/components/file_browser.py create mode 100644 quickview/components/variables.py diff --git a/quickview/app2.py b/quickview/app2.py index c95fffc..22b5fdd 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -1,13 +1,28 @@ +import asyncio import json +import time from pathlib import Path from trame.app import TrameApp from trame.ui.vuetify3 import VAppLayout -from trame.widgets import vuetify3 as v3, paraview as pvw, client +from trame.widgets import vuetify3 as v3, paraview as pvw, client, html +from trame.decorators import controller from quickview.pipeline import EAMVisSource from quickview.assets import ASSETS +from quickview.components.file_browser import ParaViewFileBrowser + +from paraview import simple + +# ----------------------------------------------------------------------------- +# Externalize +# ----------------------------------------------------------------------------- +VAR_HEADERS = [ + {"title": "Name", "align": "start", "key": "name", "sortable": True}, + {"title": "Type", "align": "start", "key": "type", "sortable": True}, +] +# ----------------------------------------------------------------------------- class EAMApp(TrameApp): @@ -41,12 +56,31 @@ def __init__(self, server=None): ) args, _ = cli.parse_known_args() + # Development setup + if self.server.hot_reload: + self.ctrl.on_server_reload.add(self._build_ui) + + # Helpers + self.file_browser = ParaViewFileBrowser( + self.server, + prefix="pv_files", + home=args.workdir, # can use current= + group="", + ) + # Data input + self.state.variables_listing = [] self.source = EAMVisSource() self.app_state = {} if args.state is not None: self.app_state = json.loads(Path(args.state).read_text()) - self.source.Update(**{k: state[k] for k in ("data_file", "conn_file")}) + self.source.Update( + **{k: self.app_state[k] for k in ("data_file", "conn_file")} + ) + elif args.data and args.conn: + self.file_browser.set_data_simulation(args.data) + self.file_browser.set_data_connectivity(args.conn) + self.ctrl.on_server_ready.add(self.file_browser.load_data_files) # GUI self._build_ui() @@ -54,64 +88,240 @@ def __init__(self, server=None): def _build_ui(self, **_): with VAppLayout(self.server, fill_height=True) as self.ui: with v3.VLayout(): - with v3.VNavigationDrawer(permanent=True, rail=True): - with v3.VListItem(loading=True): - v3.VAvatar(image=ASSETS.icon) - v3.VProgressCircular( - color="primary", - indeterminate=True, - v_show="trame__busy", - style="position: absolute !important;left: 50%;top: 50%;transform: translate(-50%, -50%);", - ) - with v3.VList(density="compact", nav=True, v_model=("active_drawer", "load-data")): + with v3.VNavigationDrawer( + permanent=True, rail=("compact_drawer", True), width=220 + ): + with v3.VList( + density="compact", + nav=True, + select_strategy="independent", + v_model_selected=("active_tools", ["load-data"]), + ): + with v3.VListItem( + title=("compact_drawer ? null : 'QuickView'",), + classes="text-h6", + ): + with v3.Template(raw_attrs=["#prepend"]): + v3.VAvatar(image=ASSETS.icon, size=24, classes="me-4") + v3.VProgressCircular( + color="primary", + indeterminate=True, + v_show="trame__busy", + v_if="compact_drawer", + style="position: absolute !important;left: 50%;top: 50%; transform: translate(-50%, -50%);", + ) + v3.VProgressLinear( + v_else=True, + color="primary", + indeterminate=True, + v_show="trame__busy", + absolute=True, + style="top:90%;width:100%;", + ) v3.VListItem( prepend_icon="mdi-file-document-outline", value="load-data", + title=("compact_drawer ? null : 'File loading'",), ) v3.VListItem( - prepend_icon="mdi-database-check-outline", + prepend_icon="mdi-list-status", value="select-fields", - disabled=True, + disabled=("variables_listing.length === 0",), + title=("compact_drawer ? null : 'Fields selection'",), ) v3.VListItem( prepend_icon="mdi-collage", value="adjust-layout", - disabled=True, + title=("compact_drawer ? null : 'Layout management'",), ) v3.VListItem( - prepend_icon="mdi-compass-rose", - value="reset-camera", - disabled=True, - ) - v3.VListItem( - prepend_icon="mdi-compass-rose", - value="reset-camera", - disabled=True, - ) - v3.VListItem( - prepend_icon="mdi-cog", - value="settings", - disabled=True, + prepend_icon="mdi-crop", + value="adjust-databounds", + title=("compact_drawer ? null : 'Lat/Long cropping'",), ) v3.VListItem( prepend_icon="mdi-earth", value="projection-sphere", - disabled=True, + title=("compact_drawer ? null : 'Map Projection'",), ) v3.VListItem( - prepend_icon="mdi-earth-box", - value="projection-box", - disabled=True, + prepend_icon="mdi-movie-open-cog-outline", + value="animation-controls", + title=("compact_drawer ? null : 'Animation controls'",), ) + v3.VListItem( prepend_icon="mdi-folder-arrow-left-right-outline", value="import-export", - disabled=True, + title=("compact_drawer ? null : 'State Import/Export'",), ) + # v3.VListItem( + # prepend_icon="mdi-compass-rose", + # value="reset-camera", + # disabled=True, + # ) + # v3.VListItem( + # prepend_icon="mdi-cog", + # value="settings", + # disabled=True, + # ) + + # v3.VListItem( + # prepend_icon="mdi-earth-box", + # value="projection-box", + # disabled=True, + # ) + + with v3.Template(raw_attrs=["#append"]): + with v3.VList(density="compact", nav=True): + v3.VListItem( + prepend_icon="mdi-lifebuoy", + click="compact_drawer = !compact_drawer", + title=("compact_drawer ? null : 'Toggle Help'",), + ) + if self.server.hot_reload: + v3.VListItem( + prepend_icon="mdi-timer-sand-complete", + click=self.fake_busy, + title=("compact_drawer ? null : 'Trigger busy'",), + ) + v3.VListItem( + prepend_icon="mdi-database-refresh-outline", + click=self.ctrl.on_server_reload, + title=("compact_drawer ? null : 'Refresh UI'",), + ) + with v3.VMain(classes="bg-red"): - v3.VLabel("Hello") + # Field selection container + with v3.VNavigationDrawer( + model_value=("active_tools.includes('select-fields')",), + width=500, + ): + v3.VTextField( + v_model=("variables_filter", ""), + hide_details=True, + color="primary", + placeholder="Filter", + density="compact", + variant="outlined", + classes="mx-2 mt-2", + prepend_inner_icon="mdi-magnify", + clearable=True, + ) + v3.VDataTable( + v_model=("variables_selected", []), + show_select=True, + item_value="id", + density="compact", + fixed_header=True, + headers=("variables_headers", VAR_HEADERS), + items=("variables_listing", []), + height="calc(100vh - 6.5rem)", + style="user-select: none; cursor: pointer;", + hover=True, + search=("variables_filter", ""), + items_per_page=-1, + hide_default_footer=True, + ) + + with v3.VCardActions(key="variables_selected.length"): + v3.VChip( + "{{ variables_selected.filter((v) => v.at(-1) === 's').length }} Surfaces", + color="success", + v_show="variables_selected.filter((v) => v.at(-1) === 's').length", + size="small", + closable=True, + click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 's')", + ) + v3.VChip( + "{{ variables_selected.filter((v) => v.at(-1) === 'i').length }} Interfaces", + color="info", + v_show="variables_selected.filter((v) => v.at(-1) === 'i').length", + size="small", + closable=True, + click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 'i')", + ) + v3.VChip( + "{{ variables_selected.filter((v) => v.at(-1) === 'm').length }} Midpoints", + color="warning", + v_show="variables_selected.filter((v) => v.at(-1) === 'm').length", + size="small", + closable=True, + click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 'm')", + ) + v3.VSpacer() + v3.VBtn( + classes="text-none", + color="primary", + prepend_icon="mdi-database", + text="Load variables", + variant="flat", + disabled=("variables_selected.length === 0",), + ) + + with v3.VContainer(classes="h-100", fluid=True): + # load-data + with v3.VDialog( + model_value=("active_tools.includes('load-data')",), + contained=True, + max_width="80vw", + persistent=True, + ): + self.file_browser.ui() + + # layout content + with html.Div(classes="bg-green h-100"): + v3.VLabel("Hello {{ active_tools }}") + + def fake_busy(self): + time.sleep(3) + + @controller.add_task("file_selection_load") + async def data_loading_open(self, simulation, connectivity): + await asyncio.sleep(0.1) + self.source.Update( + data_file=simulation, + conn_file=connectivity, + ) + + self.file_browser.loading_completed(self.source.valid) + + if self.source.valid: + with self.state as s: + s.active_tools = list( + set( + ( + "select-fields", + *(tool for tool in s.active_tools if tool != "load-data"), + ) + ) + ) + + self.state.variables_filter = "" + self.state.variables_listing = [ + *( + {"name": name, "type": "surface", "id": f"{name}s"} + for name in self.source.surface_vars + ), + *( + {"name": name, "type": "interface", "id": f"{name}i"} + for name in self.source.interface_vars + ), + *( + {"name": name, "type": "midpoint", "id": f"{name}m"} + for name in self.source.midpoint_vars + ), + ] + + # for name in ["timestamps", "midpoints", "interfaces", "surface_vars", "interface_vars", "midpoint_vars", ]: + # print(name, getattr(self.source, name)) + @controller.set("file_selection_cancel") + def data_loading_hide(self): + self.state.active_tools = [ + tool for tool in self.state.active_tools if tool != "load-data" + ] def main(): diff --git a/quickview/components/__init__.py b/quickview/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/quickview/components/file_browser.py b/quickview/components/file_browser.py new file mode 100644 index 0000000..71eeb54 --- /dev/null +++ b/quickview/components/file_browser.py @@ -0,0 +1,403 @@ +import re +from pathlib import Path +from paraview import simple +from trame.widgets import vuetify3 as v3, html +from trame.app import TrameComponent + +DIRECTORY = dict(icon="mdi-folder", type="directory") +GROUP = dict(icon="mdi-file-document-multiple-outline", type="group") +FILE = dict(icon="mdi-file-document-outline", type="file") + +HEADERS = [ + {"title": "Name", "align": "start", "key": "name", "sortable": False}, + {"title": "Size", "align": "end", "key": "size", "sortable": False}, + {"title": "Date", "align": "end", "key": "modified", "sortable": False}, +] + + +def sort_by_name(e): + return e.get("name") + + +def to_type(e): + return e.get("type", "") + + +def to_suffix(e): + return Path(e.get("name", "")).suffix + + +class ParaViewFileBrowser(TrameComponent): + def __init__( + self, + server, + prefix="pv_files", + home=None, + current=None, + exclude=r"^\.|~$|^\$", + group=r"[0-9]+\.", + ): + super().__init__(server) + self._prefix = prefix + + self._enable_groups = True + self._home_path = Path(home).resolve() if home else Path.home() + self._current_path = Path(current).resolve() if current else self._home_path + self.pattern_exclude = re.compile(exclude) + self.pattern_group = re.compile(group) + + self._pxm = simple.servermanager.ProxyManager() + self._proxy_listing = self._pxm.NewProxy("misc", "ListDirectory") + self._proxy_directories = simple.servermanager.VectorProperty( + self._proxy_listing, self._proxy_listing.GetProperty("DirectoryList") + ) + self._proxy_files = simple.servermanager.VectorProperty( + self._proxy_listing, self._proxy_listing.GetProperty("FileList") + ) + + # Initialize trame state + self.update_listing() + + def name(self, name): + return f"{self._prefix}_{name}" + + def set(self, name, value): + self.state[self.name(name)] = value + + def get(self, name): + return self.state[self.name(name)] + + def update_listing(self, selection=None): + with self.state: + self.set("active", -1) + self.set("listing", self.listing) + self.set("selected", selection) + + @property + def enable_groups(self): + return self._enable_groups + + @enable_groups.setter + def enable_groups(self, v): + self._enable_groups = v + + @property + def listing(self): + directories = [] + files = [] + groups = [] + g_map = {} + + self._proxy_listing.List(str(self._current_path.resolve())) + self._proxy_listing.UpdatePropertyInformation() + + # Files + Groups + file_listing = [] + if len(self._proxy_files) > 1: + file_listing = self._proxy_files.GetData() + if len(self._proxy_files) == 1: + file_listing.append(self._proxy_files.GetData()) + file_listing = [ + file_name + for file_name in file_listing + if not re.search(self.pattern_exclude, file_name) + ] + for file_name in file_listing: + f = self._current_path / file_name + stats = f.stat() + + # Group or file? + file_split = re.split(self.pattern_group, file_name) + if self.enable_groups and len(file_split) == 2: + # Group + g_name = "*.".join(file_split) + if g_name not in g_map: + g_entry = dict( + name=g_name, + modified=stats.st_mtime, + size=0, + files=[], + **GROUP, + ) + g_map[g_name] = g_entry + groups.append(g_entry) + + g_map[g_name]["size"] += stats.st_size + g_map[g_name]["files"].append(file_name) + # Many need to sort files??? + else: + # File + files.append( + dict( + name=f.name, + modified=stats.st_mtime, + size=stats.st_size, + **FILE, + ) + ) + + # Directories + dir_listing = [] + if len(self._proxy_directories) > 1: + dir_listing = self._proxy_directories.GetData() + if len(self._proxy_directories) == 1: + dir_listing.append(self._proxy_directories.GetData()) + dir_listing = [ + dir_name + for dir_name in dir_listing + if not re.search(self.pattern_exclude, dir_name) + ] + for dir_name in dir_listing: + f = self._current_path / dir_name + directories.append( + dict(name=f.name, modified=f.stat().st_mtime, **DIRECTORY) + ) + + # Sort content + directories.sort(key=sort_by_name) + groups.sort(key=sort_by_name) + files.sort(key=sort_by_name) + + return [ + {**e, "index": i} for i, e in enumerate([*directories, *groups, *files]) + ] + + def open_entry(self, entry): + entry_type = entry.get("type") + if entry_type == "directory": + self._current_path = self._current_path / entry.get("name") + self.update_listing() + return entry_type, str(self._current_path) + if entry_type == "group": + files = entry.get("files", []) + self.update_listing() + return entry, [str(self._current_path / f) for f in files] + if entry_type == "file": + file = self._current_path / entry.get("name") + file_name = file.name.lower() + full_path = str(file) + var_name = ( + "data_connectivity" + if "connectivity_" in file_name + else "data_simulation" + ) + self.set(var_name, full_path) + self.update_listing(full_path) + return entry_type, full_path + + return None + + @property + def active_path(self): + entry = self.get("listing")[self.get("active")] + return str(self._current_path / entry.get("name")) + + def set_data_connectivity(self, value=None): + self.set("data_connectivity", value or self.active_path) + + def set_data_simulation(self, value=None): + self.set("data_simulation", value or self.active_path) + + def goto_home(self): + self._current_path = self._home_path + self.update_listing() + + def goto_parent(self): + self._current_path = self._current_path.parent + self.update_listing() + + def open_dataset(self, entry): + event = {} + if to_type(entry) == "group": + files = [str(self._current_path / f) for f in entry.get("files")] + source = simple.OpenDataFile(files) + representation = simple.Show(source) + view = simple.Render() + event = dict( + source=source, representation=representation, view=view, type="group" + ) + else: + source = simple.OpenDataFile(str(self._current_path / entry.get("name"))) + representation = simple.Show(source) + view = simple.Render() + event = dict( + source=source, representation=representation, view=view, type="dataset" + ) + + return event + + def select_entry(self, entry): + with self.state as state: + state[f"{self._prefix}_active"] = entry.get("index", 0) if entry else -1 + + def load_data_files(self, **_): + self.set("loading", True) + print("Load files:") + print(" - simulation:", self.get("data_simulation")) + print(" - connectivity:", self.get("data_connectivity")) + self.ctrl.file_selection_load( + self.get("data_simulation"), self.get("data_connectivity") + ) + + def cancel(self): + self.ctrl.file_selection_cancel() + + def loading_completed(self, valid): + with self.state: + self.set("loading", False) + self.set("error", not valid) + + def ui(self): + with v3.VCard(rounded="lg"): + with v3.VCardTitle("File loading", classes="d-flex align-center px-3"): + v3.VSpacer() + v3.VBtn( + icon="mdi-home", + variant="flat", + size="small", + click=self.goto_home, + ) + v3.VBtn( + icon="mdi-folder-upload-outline", + variant="flat", + size="small", + click=self.goto_parent, + ) + v3.VTextField( + v_model=self.name("filter"), + hide_details=True, + color="primary", + placeholder="filter", + density="compact", + variant="outlined", + classes="ml-2", + prepend_inner_icon="mdi-magnify", + clearable=True, + ) + + with v3.VCardText( + classes="rounded-lg border border-opacity-25 pa-0 mx-3 my-0 overflow-hidden" + ): + style_align_center = "d-flex align-center " + with v3.VDataTable( + density="compact", + fixed_header=True, + headers=(self.name("headers"), HEADERS), + items=(self.name("listing"), []), + height="calc(80vh - 20rem)", + style="user-select: none; cursor: pointer;", + hover=True, + search=(self.name("filter"), ""), + items_per_page=-1, + ): + v3.Template(raw_attrs=["v-slot:bottom"]) + with v3.Template(raw_attrs=['v-slot:item="{ index, item }"']): + with v3.VDataTableRow( + index=("index",), + item=("item",), + click=(self.select_entry, "[item]"), + dblclick=(self.open_entry, "[item]"), + classes=( + f"{{ 'bg-grey': item.index === {self.name('active')}, 'cursor-pointer': 1 }}", + ), + ): + with v3.Template(raw_attrs=["v-slot:item.name"]): + with html.Div(classes=style_align_center): + v3.VIcon( + "{{ item.icon }}", + size="small", + classes="mr-2", + ) + html.Div("{{ item.name }}") + + with v3.Template(raw_attrs=["v-slot:item.size"]): + with html.Div( + classes=style_align_center + " justify-end", + ): + html.Div( + "{{ utils.fmt.bytes(item.size, 0) }}", + v_if="item.size", + ) + html.Div(" - ", v_else=True) + + with v3.Template(raw_attrs=["v-slot:item.modified"]): + with html.Div( + classes=style_align_center + " justify-end", + ): + html.Div( + "{{ new Date(item.modified * 1000).toDateString() }}" + ) + + with v3.VCol(): + html.Label( + "Simulation File", + classes="text-subtitle-1 font-weight-medium d-block", + ) + v3.VTextField( + v_model=(self.name("data_simulation"), ""), + density="compact", + variant="outlined", + disabled=True, + messages="EAM's history output on the physics grids (pg2 grids) written by EAMv2, v3, and an intermediate version towards v4 (EAMxx).", + ) + html.Label( + "Connectivity File", + classes="text-subtitle-1 font-weight-medium d-block", + ) + v3.VTextField( + v_model=(self.name("data_connectivity"), ""), + density="compact", + variant="outlined", + disabled=True, + messages="The horizontal grids used by EAM are cubed spheres. Since these are unstructed grids, QuickView needs to know how to map data to the globe. Therefore, for each simulation data file, a 'connectivity file' needs to be provided.", + ) + + v3.VDivider() + with v3.VCardActions(classes="pa-3"): + v3.VBtn( + classes="text-none", + variant="tonal", + text="Simulation", + prepend_icon="mdi-database-plus", + disabled=( + f"{self.name('listing')}[{self.name('active')}]?.type !== 'file'", + ), + click=self.set_data_simulation, + ) + v3.VBtn( + classes="text-none", + text="Connectivity", + variant="tonal", + prepend_icon="mdi-vector-polyline-plus", + disabled=( + f"{self.name('listing')}[{self.name('active')}]?.type !== 'file'", + ), + click=self.set_data_connectivity, + ) + v3.VBtn( + classes="text-none", + text="Reset", + variant="tonal", + prepend_icon="mdi-close-octagon-outline", + click=f"{self.name('data_connectivity')}='';{self.name('data_simulation')}='';{self.name('error')}=false", + ) + v3.VSpacer() + v3.VBtn( + border=True, + classes="text-none", + color="surface", + text="Cancel", + variant="flat", + click=self.cancel, + ) + v3.VBtn( + classes="text-none", + color=(f"{self.name('error')} ? 'error' : 'primary'",), + text="Load files", + variant="flat", + disabled=( + f"!{self.name('data_simulation')} || !{self.name('data_connectivity')} || {self.name('error')}", + ), + loading=(self.name("loading"), False), + click=self.load_data_files, + ) diff --git a/quickview/components/variables.py b/quickview/components/variables.py new file mode 100644 index 0000000..e69de29 From 4de576d75688a9d6a7d7ae7fda57bd8976fa766d Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Thu, 2 Oct 2025 18:39:49 -0600 Subject: [PATCH 03/14] feat(rendering): add initial layout handler --- quickview/app2.py | 475 ++++++++++++++++++++++++++++++++----- quickview/interface.py | 12 +- quickview/view_manager2.py | 181 ++++++++++++++ 3 files changed, 595 insertions(+), 73 deletions(-) create mode 100644 quickview/view_manager2.py diff --git a/quickview/app2.py b/quickview/app2.py index 22b5fdd..31265d5 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -6,14 +6,15 @@ from trame.app import TrameApp from trame.ui.vuetify3 import VAppLayout -from trame.widgets import vuetify3 as v3, paraview as pvw, client, html -from trame.decorators import controller +from trame.widgets import vuetify3 as v3, client, html +from trame.decorators import controller, change from quickview.pipeline import EAMVisSource from quickview.assets import ASSETS +from quickview.view_manager2 import ViewManager from quickview.components.file_browser import ParaViewFileBrowser -from paraview import simple +v3.enable_lab() # ----------------------------------------------------------------------------- # Externalize @@ -22,6 +23,22 @@ {"title": "Name", "align": "start", "key": "name", "sortable": True}, {"title": "Type", "align": "start", "key": "type", "sortable": True}, ] + + +def js_var_count(name): + return f"variables_selected.filter((v) => v[0] === '{name[0]}').length" + + +def js_var_remove(name): + return ( + f"variables_selected = variables_selected.filter((v) => v[0] !== '{name[0]}')" + ) + + +def js_var_title(name): + return " ".join(["{{", js_var_count(name), "}}", name.capitalize()]) + + # ----------------------------------------------------------------------------- @@ -60,7 +77,15 @@ def __init__(self, server=None): if self.server.hot_reload: self.ctrl.on_server_reload.add(self._build_ui) + # Data input + self.selected_variables = None + self.state.variables_listing = [] + self.state.toolbar_slider_visibility = [] + self.source = EAMVisSource() + self.app_state = {} + # Helpers + self.view_manager = ViewManager(self.server, self.source) self.file_browser = ParaViewFileBrowser( self.server, prefix="pv_files", @@ -68,10 +93,7 @@ def __init__(self, server=None): group="", ) - # Data input - self.state.variables_listing = [] - self.source = EAMVisSource() - self.app_state = {} + # Process CLI to pre-load data if args.state is not None: self.app_state = json.loads(Path(args.state).read_text()) self.source.Update( @@ -85,6 +107,10 @@ def __init__(self, server=None): # GUI self._build_ui() + # ------------------------------------------------------------------------- + # UI definition + # ------------------------------------------------------------------------- + def _build_ui(self, **_): with VAppLayout(self.server, fill_height=True) as self.ui: with v3.VLayout(): @@ -100,6 +126,7 @@ def _build_ui(self, **_): with v3.VListItem( title=("compact_drawer ? null : 'QuickView'",), classes="text-h6", + click=self.view_manager.reset_camera, ): with v3.Template(raw_attrs=["#prepend"]): v3.VAvatar(image=ASSETS.icon, size=24, classes="me-4") @@ -129,6 +156,35 @@ def _build_ui(self, **_): disabled=("variables_listing.length === 0",), title=("compact_drawer ? null : 'Fields selection'",), ) + with v3.VListItem( + prepend_icon="mdi-earth", + title=("compact_drawer ? null : 'Map Projection'",), + ): + with v3.VMenu( + activator="parent", location="end", offset=10 + ): + v3.VList( + mandatory=True, + v_model_selected=( + "projection", + ["Cyl. Equidistant"], + ), + density="compact", + items=( + "projections", + [ + { + "title": "Cylindrical Equidistant", + "value": "Cyl. Equidistant", + }, + {"title": "Robinson", "value": "Robinson"}, + { + "title": "Mollweide", + "value": "Mollweide", + }, + ], + ), + ) v3.VListItem( prepend_icon="mdi-collage", value="adjust-layout", @@ -140,16 +196,15 @@ def _build_ui(self, **_): title=("compact_drawer ? null : 'Lat/Long cropping'",), ) v3.VListItem( - prepend_icon="mdi-earth", - value="projection-sphere", - title=("compact_drawer ? null : 'Map Projection'",), + prepend_icon="mdi-tune-variant", + value="select-slice-time", + title=("compact_drawer ? null : 'Slice selection'",), ) v3.VListItem( prepend_icon="mdi-movie-open-cog-outline", value="animation-controls", title=("compact_drawer ? null : 'Animation controls'",), ) - v3.VListItem( prepend_icon="mdi-folder-arrow-left-right-outline", value="import-export", @@ -192,12 +247,55 @@ def _build_ui(self, **_): title=("compact_drawer ? null : 'Refresh UI'",), ) - with v3.VMain(classes="bg-red"): + with v3.VMain(): + # load-data + with html.Div( + style="position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:1000;" + ): + with v3.VDialog( + model_value=("active_tools.includes('load-data')",), + contained=True, + max_width="80vw", + persistent=True, + ): + self.file_browser.ui() + # Field selection container with v3.VNavigationDrawer( model_value=("active_tools.includes('select-fields')",), width=500, + permanent=True, ): + with v3.VCardActions(key="variables_selected.length"): + for name, color in [ + ("surfaces", "success"), + ("interfaces", "info"), + ("midpoints", "warning"), + ]: + v3.VChip( + js_var_title(name), + color=color, + v_show=js_var_count(name), + size="small", + closable=True, + click_close=js_var_remove(name), + ) + + v3.VSpacer() + v3.VBtn( + classes="text-none", + color="primary", + prepend_icon="mdi-database", + text=( + "`Load ${variables_selected.length} variable${variables_selected.length > 1 ? 's' :''}`", + ), + variant="flat", + disabled=( + "variables_selected.length === 0 || variables_loaded", + ), + click=self.data_load_variables, + ) + v3.VTextField( v_model=("variables_filter", ""), hide_details=True, @@ -205,7 +303,7 @@ def _build_ui(self, **_): placeholder="Filter", density="compact", variant="outlined", - classes="mx-2 mt-2", + classes="mx-2", prepend_inner_icon="mdi-magnify", clearable=True, ) @@ -217,7 +315,9 @@ def _build_ui(self, **_): fixed_header=True, headers=("variables_headers", VAR_HEADERS), items=("variables_listing", []), - height="calc(100vh - 6.5rem)", + height=( + "`calc(max(100vh, ${Math.floor(main_size?.size?.height || 0)}px) - 6rem)`", + ), style="user-select: none; cursor: pointer;", hover=True, search=("variables_filter", ""), @@ -225,60 +325,248 @@ def _build_ui(self, **_): hide_default_footer=True, ) - with v3.VCardActions(key="variables_selected.length"): - v3.VChip( - "{{ variables_selected.filter((v) => v.at(-1) === 's').length }} Surfaces", - color="success", - v_show="variables_selected.filter((v) => v.at(-1) === 's').length", - size="small", - closable=True, - click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 's')", - ) - v3.VChip( - "{{ variables_selected.filter((v) => v.at(-1) === 'i').length }} Interfaces", - color="info", - v_show="variables_selected.filter((v) => v.at(-1) === 'i').length", - size="small", - closable=True, - click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 'i')", - ) - v3.VChip( - "{{ variables_selected.filter((v) => v.at(-1) === 'm').length }} Midpoints", - color="warning", - v_show="variables_selected.filter((v) => v.at(-1) === 'm').length", - size="small", - closable=True, - click_close="variables_selected = variables_selected.filter((v) => v.at(-1) !== 'm')", - ) - v3.VSpacer() - v3.VBtn( - classes="text-none", - color="primary", - prepend_icon="mdi-database", - text="Load variables", - variant="flat", - disabled=("variables_selected.length === 0",), - ) - - with v3.VContainer(classes="h-100", fluid=True): - # load-data - with v3.VDialog( - model_value=("active_tools.includes('load-data')",), - contained=True, - max_width="80vw", - persistent=True, - ): - self.file_browser.ui() + with v3.VContainer(classes="h-100 pa-0", fluid=True): + with client.SizeObserver("main_size"): + # Layout control toolbar + with v3.VToolbar( + v_show="active_tools.includes('adjust-layout')", + color="white", + classes="border-b-thin", + density="compact", + ): + v3.VIcon("mdi-collage", classes="px-6 opacity-50") + v3.VLabel("Layout Controls", classes="text-subtitle-2") + v3.VSpacer() + + with v3.VRadioGroup( + classes="d-inline-block", + hide_details=True, + inline=True, + v_model=("col_mode", "auto"), + ): + v3.VRadio(label="Auto", value="auto") + v3.VRadio(label="Full width", value="1") + v3.VRadio(label="2 cols", value="2") + v3.VRadio(label="3 cols", value="3") + v3.VRadio(label="4 cols", value="4") + v3.VRadio(label="6 cols", value="6") + v3.VRadio(label="12 cols", value="12") + + v3.VSpacer() + v3.VSlider( + v_model=("aspect_ratio", 2), + prepend_icon="mdi-aspect-ratio", + min=1, + max=2, + step=0.1, + density="compact", + hide_details=True, + style="max-width: 400px;", + classes="mx-4", + ) - # layout content - with html.Div(classes="bg-green h-100"): - v3.VLabel("Hello {{ active_tools }}") + # Crop selection + with v3.VToolbar( + v_show="active_tools.includes('adjust-databounds')", + color="white", + classes="border-b-thin", + ): + v3.VIcon("mdi-crop", classes="pl-6 opacity-50") + with v3.VRow(classes="ma-0 px-2 align-center"): + with v3.VCol(cols=6): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Longitude", classes="text-subtitle-2" + ) + v3.VSpacer() + v3.VLabel( + "{{ crop_longitude }}", + classes="text-body-2", + ) + v3.VRangeSlider( + v_model=("crop_longitude", [-180, 180]), + min=-180, + max=180, + step=1, + density="compact", + hide_details=True, + ) + with v3.VCol(cols=6): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Latitude", classes="text-subtitle-2" + ) + v3.VSpacer() + v3.VLabel( + "{{ crop_latitude }}", + classes="text-body-2", + ) + v3.VRangeSlider( + v_model=("crop_latitude", [-90, 90]), + min=-90, + max=90, + step=1, + density="compact", + hide_details=True, + ) + + # Layer/Time selection + with v3.VToolbar( + v_show="active_tools.includes('select-slice-time')", + color="white", + classes="border-b-thin", + ): + v3.VIcon("mdi-tune-variant", classes="ml-3 opacity-50") + with v3.VRow( + classes="ma-0 pr-2 align-center", dense=True + ): + # midpoint layer + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="toolbar_slider_visibility.includes('m')", + ): + self.state.setdefault( + "layer_midpoints_value", 80.50 + ) + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Layer Midpoints", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ layer_midpoints_value }} hPa (k={{layer_midpoints}})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("layer_midpoints", 0), + min=0, + max=("layer_midpoints_max", 10), + step=1, + density="compact", + hide_details=True, + ) + + # interface layer + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="toolbar_slider_visibility.includes('i')", + ): + self.state.setdefault( + "layer_interfaces_value", 80.50 + ) + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Layer Interfaces", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ layer_interfaces_value }} hPa (k={{layer_interfaces}})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("layer_interfaces", 0), + min=0, + max=("layer_interfaces_max", 10), + step=1, + density="compact", + hide_details=True, + ) + + # time + with v3.VCol(cols=("toolbar_slider_cols", 4)): + self.state.setdefault("time_value", 80.50) + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel("Time", classes="text-subtitle-2") + v3.VSpacer() + v3.VLabel( + "{{ time_value }} hPa (t={{time}})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("time", 0), + min=0, + max=("time_max", 10), + step=1, + density="compact", + hide_details=True, + ) + + # Animation + with v3.VToolbar( + v_show="active_tools.includes('animation-controls')", + color="white", + classes="border-b-thin", + density="compact", + ): + v3.VIcon( + "mdi-movie-open-cog-outline", + classes="px-6 opacity-50", + ) + with v3.VRow(classes="ma-0 px-2 align-center"): + v3.VSelect( + v_model=("animation_track", "Time"), + items=( + "animation_tracks", + [ + "Time", + "Layer Midpoints", + "Layer Interfaces", + ], + ), + flat=True, + variant="plain", + hide_details=True, + density="compact", + style="max-width: 200px;", + ) + v3.VSlider( + v_model=("animation_step", 1), + min=0, + max=("amimation_step_max", 100), + step=1, + hide_details=True, + density="compact", + ) + v3.VIconBtn( + icon="mdi-page-first", + flat=True, + ) + v3.VIconBtn( + icon="mdi-chevron-left", + flat=True, + ) + v3.VIconBtn( + icon="mdi-chevron-right", + flat=True, + ) + v3.VIconBtn( + icon="mdi-page-last", + flat=True, + ) + v3.VIconBtn( + icon="mdi-play", + flat=True, + ) + v3.VIconBtn( + icon="mdi-stop", + flat=True, + ) + + client.ServerTemplate(name=("active_layout", "auto_layout")) + + # ------------------------------------------------------------------------- + # Methods connected to UI + # ------------------------------------------------------------------------- def fake_busy(self): time.sleep(3) @controller.add_task("file_selection_load") async def data_loading_open(self, simulation, connectivity): + self.selected_variables = None + self.state.variables_loaded = False await asyncio.sleep(0.1) self.source.Update( data_file=simulation, @@ -301,15 +589,15 @@ async def data_loading_open(self, simulation, connectivity): self.state.variables_filter = "" self.state.variables_listing = [ *( - {"name": name, "type": "surface", "id": f"{name}s"} + {"name": name, "type": "surface", "id": f"s{name}"} for name in self.source.surface_vars ), *( - {"name": name, "type": "interface", "id": f"{name}i"} + {"name": name, "type": "interface", "id": f"i{name}"} for name in self.source.interface_vars ), *( - {"name": name, "type": "midpoint", "id": f"{name}m"} + {"name": name, "type": "midpoint", "id": f"m{name}"} for name in self.source.midpoint_vars ), ] @@ -323,7 +611,64 @@ def data_loading_hide(self): tool for tool in self.state.active_tools if tool != "load-data" ] - + def data_load_variables(self): + vars_per_type = {n: [] for n in "smi"} + for var in self.state.variables_selected: + type = var[0] + name = var[1:] + vars_per_type[type].append(name) + + self.source.LoadVariables( + vars_per_type["s"], # surfaces + vars_per_type["m"], # midpoints + vars_per_type["i"], # interfaces + ) + self.selected_variables = vars_per_type + self.view_manager.build_auto_layout(vars_per_type) + + # Compute Layer/Time column spread + n_cols = 1 # time + toolbar_slider_visibility = [] + for var_type in "mi": + if vars_per_type[var_type]: + toolbar_slider_visibility.append(var_type) + n_cols += 1 + + with self.state: + self.state.variables_loaded = True + self.state.toolbar_slider_cols = 12 / n_cols if n_cols else 12 + self.state.toolbar_slider_visibility = toolbar_slider_visibility + self.state.dirty("toolbar_slider_visibility") + + @change("variables_selected") + def _on_dirty_variable_selection(self, **_): + self.state.variables_loaded = False + + @change("col_mode") + def _on_layout_refresh(self, **_): + if self.selected_variables is None: + return + + self.view_manager.build_auto_layout(self.selected_variables) + + @change("projection") + async def _on_projection(self, projection, **_): + proj_str = projection[0] + self.source.UpdateProjection(proj_str) + self.source.UpdatePipeline() + self.view_manager.reset_camera() + + # Hack to force reset_camera for "cyl mode" + # => may not be needed if we switch to rca + if " " in proj_str: + for _ in range(2): + await asyncio.sleep(0.1) + self.view_manager.reset_camera() + + +# ------------------------------------------------------------------------- +# Standalone execution +# ------------------------------------------------------------------------- def main(): app = EAMApp() app.server.start() diff --git a/quickview/interface.py b/quickview/interface.py index 76005c0..a22f362 100644 --- a/quickview/interface.py +++ b/quickview/interface.py @@ -247,14 +247,6 @@ def __init__( else: self.update_state_from_config(initstate) - @property - def state(self): - return self.server.state - - @property - def ctrl(self): - return self.server.controller - @life_cycle.server_ready def _tauri_ready(self, **_): os.write(1, f"tauri-server-port={self.server.port}\n".encode()) @@ -476,6 +468,10 @@ def load_variables(self, use_cached_layout=False): f_intf = self.interface_vars_state # Use the full state array if len(v_intf) == len(f_intf): # Ensure arrays are same length intf = v_intf[f_intf].tolist() + + print("Load surf", surf) + print("Load mid", mid) + print("Load intf", intf) self.source.LoadVariables(surf, mid, intf) vars = surf + mid + intf diff --git a/quickview/view_manager2.py b/quickview/view_manager2.py new file mode 100644 index 0000000..062b7fa --- /dev/null +++ b/quickview/view_manager2.py @@ -0,0 +1,181 @@ +from trame.app import TrameComponent +from trame.ui.html import DivLayout +from trame.widgets import paraview as pvw, vuetify3 as v3, client, html +from trame.decorators import hot_reload + +from paraview import simple + + +def auto_size_to_col(size): + if size == 1: + return 12 + + if size >= 8 and size % 2 == 0: + return 3 + + if size % 3 == 0: + return 4 + + if size % 2 == 0: + return 6 + + return auto_size_to_col(size + 1) + + +COL_SIZE_LOOKUP = { + "auto": auto_size_to_col, + "1": 12, + "2": 6, + "3": 4, + "4": 3, + "6": 2, + "12": 1, +} + +TYPE_COLOR = { + "s": "success", + "i": "info", + "m": "warning", +} + + +class VariableView(TrameComponent): + def __init__(self, server, source, variable_name): + super().__init__(server) + self.source = source + self.variable_name = variable_name + self.name = f"view_{self.variable_name}" + self.view = simple.CreateRenderView() + self.view.GetRenderWindow().SetOffScreenRendering(True) + self.view.InteractionMode = "2D" + self.view.OrientationAxesVisibility = 0 + self.view.UseColorPaletteForBackground = 0 + self.view.BackgroundColorMode = "Gradient" + self.view.CameraParallelProjection = 1 + self.representation = simple.Show( + proxy=source.views["atmosphere_data"], + view=self.view, + ) + simple.ColorBy(self.representation, ("CELLS", variable_name)) + self.lut = simple.GetColorTransferFunction(variable_name) + self.lut.NanOpacity = 0.0 + + self.view.ResetActiveCameraToNegativeZ() + self.view.ResetCamera(True, 0.9) + self.disable_render = False + # FIXME use preset/logscale/invert/range + + self._build_ui() + + def render(self): + if self.disable_render: + return + self.ctx[self.name].update() + + def set_camera_modified(self, fn): + self._observer = self.camera.AddObserver("ModifiedEvent", fn) + + @property + def camera(self): + return self.view.GetActiveCamera() + + def reset_camera(self): + self.view.InteractionMode = "2D" + self.view.ResetActiveCameraToNegativeZ() + self.view.ResetCamera(True, 0.9) + self.ctx[self.name].update() + + def _build_ui(self): + with DivLayout( + self.server, template_name=self.name, connect_parent=False + ) as self.ui: + with v3.VCard(variant="tonal"): + v3.VCardSubtitle( + self.variable_name, + classes="pt-1 pb-0 px-2 bg-black opacity-90 text-subtitle-2", + ) + with html.Div(style=("`aspect-ratio: ${aspect_ratio};`",)): + pvw.VtkRemoteView( + self.view, interactive_ratio=1, ctx_name=self.name + ) + + +class ViewManager(TrameComponent): + def __init__(self, server, source): + super().__init__(server) + self.source = source + self._var2view = {} + self._camera_sync_in_progress = False + + pvw.initialize(self.server) + + def reset_camera(self): + views = list(self._var2view.values()) + for view in views: + view.disable_render = True + + for view in views: + view.reset_camera() + + for view in views: + view.disable_render = False + + def get_view(self, variable_name): + view = self._var2view.get(variable_name) + if view is None: + view = self._var2view.setdefault( + variable_name, + VariableView(self.server, self.source, variable_name), + ) + view.set_camera_modified(self.sync_camera) + + return view + + def sync_camera(self, camera, *_): + if self._camera_sync_in_progress: + return + self._camera_sync_in_progress = True + + for var_view in self._var2view.values(): + cam = var_view.camera + if cam is camera: + continue + cam.DeepCopy(camera) + var_view.render() + + self._camera_sync_in_progress = False + + @hot_reload + def build_auto_layout(self, variables): + with DivLayout(self.server, template_name="auto_layout") as self.ui: + size_to_col = COL_SIZE_LOOKUP[self.state.col_mode] + with v3.VCol(classes="pa-1"): + if callable(size_to_col): + for var_type in "smi": + var_names = variables[var_type] + total_size = len(var_names) + + if total_size == 0: + continue + + n_cols = size_to_col(total_size) + with v3.VAlert( + border="start", + classes="pr-1 py-1 pl-3 mb-1", + variant="flat", + border_color=TYPE_COLOR[var_type], + ): + with v3.VRow(dense=True): + for name in var_names: + view = self.get_view(name) + with v3.VCol(cols=n_cols): + client.ServerTemplate(name=view.name) + else: + n_cols = size_to_col + with v3.VRow(dense=True): + for var_type in "smi": + var_names = variables[var_type] + for name in var_names: + view = self.get_view(name) + with v3.VCol(cols=n_cols): + client.ServerTemplate(name=view.name) From f671910a040c692377382c05221891bd290cef06 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Fri, 3 Oct 2025 14:35:41 -0600 Subject: [PATCH 04/14] fix(steps): reorder steps and add tooltip --- quickview/app2.py | 329 ++++++++++++++++++++++++++++------------------ 1 file changed, 203 insertions(+), 126 deletions(-) diff --git a/quickview/app2.py b/quickview/app2.py index 31265d5..556353b 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -78,7 +78,6 @@ def __init__(self, server=None): self.ctrl.on_server_reload.add(self._build_ui) # Data input - self.selected_variables = None self.state.variables_listing = [] self.state.toolbar_slider_visibility = [] self.source = EAMVisSource() @@ -123,130 +122,198 @@ def _build_ui(self, **_): select_strategy="independent", v_model_selected=("active_tools", ["load-data"]), ): - with v3.VListItem( - title=("compact_drawer ? null : 'QuickView'",), - classes="text-h6", - click=self.view_manager.reset_camera, + with v3.VTooltip( + text="Reset camera", disabled=("!compact_drawer",) ): - with v3.Template(raw_attrs=["#prepend"]): - v3.VAvatar(image=ASSETS.icon, size=24, classes="me-4") - v3.VProgressCircular( - color="primary", - indeterminate=True, - v_show="trame__busy", - v_if="compact_drawer", - style="position: absolute !important;left: 50%;top: 50%; transform: translate(-50%, -50%);", - ) - v3.VProgressLinear( - v_else=True, - color="primary", - indeterminate=True, - v_show="trame__busy", - absolute=True, - style="top:90%;width:100%;", - ) - v3.VListItem( - prepend_icon="mdi-file-document-outline", - value="load-data", - title=("compact_drawer ? null : 'File loading'",), - ) - v3.VListItem( - prepend_icon="mdi-list-status", - value="select-fields", - disabled=("variables_listing.length === 0",), - title=("compact_drawer ? null : 'Fields selection'",), - ) - with v3.VListItem( - prepend_icon="mdi-earth", - title=("compact_drawer ? null : 'Map Projection'",), + with v3.Template(v_slot_activator="{ props }"): + with v3.VListItem( + v_bind="props", + title=("compact_drawer ? null : 'QuickView'",), + classes="text-h6", + click=self.view_manager.reset_camera, + ): + with v3.Template(raw_attrs=["#prepend"]): + v3.VAvatar( + image=ASSETS.icon, size=24, classes="me-4" + ) + v3.VProgressCircular( + color="primary", + indeterminate=True, + v_show="trame__busy", + v_if="compact_drawer", + style="position: absolute !important;left: 50%;top: 50%; transform: translate(-50%, -50%);", + ) + v3.VProgressLinear( + v_else=True, + color="primary", + indeterminate=True, + v_show="trame__busy", + absolute=True, + style="top:90%;width:100%;", + ) + with v3.VTooltip( + text="File loading", disabled=("!compact_drawer",) ): - with v3.VMenu( - activator="parent", location="end", offset=10 - ): - v3.VList( - mandatory=True, - v_model_selected=( - "projection", - ["Cyl. Equidistant"], + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-file-document-outline", + value="load-data", + title=("compact_drawer ? null : 'File loading'",), + ) + with v3.VTooltip( + text="Fields selection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-list-status", + value="select-fields", + disabled=("variables_listing.length === 0",), + title=( + "compact_drawer ? null : 'Fields selection'", ), - density="compact", - items=( - "projections", - [ - { - "title": "Cylindrical Equidistant", - "value": "Cyl. Equidistant", - }, - {"title": "Robinson", "value": "Robinson"}, - { - "title": "Mollweide", - "value": "Mollweide", - }, - ], + ) + + with v3.VTooltip( + text="State Import/Export", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-folder-arrow-left-right-outline", + value="import-export", + title=( + "compact_drawer ? null : 'State Import/Export'", ), ) - v3.VListItem( - prepend_icon="mdi-collage", - value="adjust-layout", - title=("compact_drawer ? null : 'Layout management'",), - ) - v3.VListItem( - prepend_icon="mdi-crop", - value="adjust-databounds", - title=("compact_drawer ? null : 'Lat/Long cropping'",), - ) - v3.VListItem( - prepend_icon="mdi-tune-variant", - value="select-slice-time", - title=("compact_drawer ? null : 'Slice selection'",), - ) - v3.VListItem( - prepend_icon="mdi-movie-open-cog-outline", - value="animation-controls", - title=("compact_drawer ? null : 'Animation controls'",), - ) - v3.VListItem( - prepend_icon="mdi-folder-arrow-left-right-outline", - value="import-export", - title=("compact_drawer ? null : 'State Import/Export'",), - ) - # v3.VListItem( - # prepend_icon="mdi-compass-rose", - # value="reset-camera", - # disabled=True, - # ) - # v3.VListItem( - # prepend_icon="mdi-cog", - # value="settings", - # disabled=True, - # ) - - # v3.VListItem( - # prepend_icon="mdi-earth-box", - # value="projection-box", - # disabled=True, - # ) - - with v3.Template(raw_attrs=["#append"]): - with v3.VList(density="compact", nav=True): - v3.VListItem( - prepend_icon="mdi-lifebuoy", - click="compact_drawer = !compact_drawer", - title=("compact_drawer ? null : 'Toggle Help'",), - ) - if self.server.hot_reload: + with v3.VTooltip( + text="Toggle Help", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): v3.VListItem( - prepend_icon="mdi-timer-sand-complete", - click=self.fake_busy, - title=("compact_drawer ? null : 'Trigger busy'",), + v_bind="props", + prepend_icon="mdi-lifebuoy", + click="compact_drawer = !compact_drawer", + title=("compact_drawer ? null : 'Toggle Help'",), ) + + v3.VDivider(classes="my-1") + + with v3.VTooltip( + text="Map Projection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + with v3.VListItem( + v_bind="props", + prepend_icon="mdi-earth", + title=("compact_drawer ? null : 'Map Projection'",), + ): + with v3.VMenu( + activator="parent", location="end", offset=10 + ): + v3.VList( + mandatory=True, + v_model_selected=( + "projection", + ["Cyl. Equidistant"], + ), + density="compact", + items=( + "projections", + [ + { + "title": "Cylindrical Equidistant", + "value": "Cyl. Equidistant", + }, + { + "title": "Robinson", + "value": "Robinson", + }, + { + "title": "Mollweide", + "value": "Mollweide", + }, + ], + ), + ) + + with v3.VTooltip( + text="Layout management", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): v3.VListItem( - prepend_icon="mdi-database-refresh-outline", - click=self.ctrl.on_server_reload, - title=("compact_drawer ? null : 'Refresh UI'",), + v_bind="props", + prepend_icon="mdi-collage", + value="adjust-layout", + title=( + "compact_drawer ? null : 'Layout management'", + ), ) + v3.VDivider(classes="my-1") + + with v3.VTooltip( + text="Lat/Long cropping", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-crop", + value="adjust-databounds", + title=( + "compact_drawer ? null : 'Lat/Long cropping'", + ), + ) + + with v3.VTooltip( + text="Slice selection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-tune-variant", + value="select-slice-time", + title=( + "compact_drawer ? null : 'Slice selection'", + ), + ) + + with v3.VTooltip( + text="Animation controls", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-movie-open-cog-outline", + value="animation-controls", + title=( + "compact_drawer ? null : 'Animation controls'", + ), + ) + + if self.server.hot_reload: + v3.VDivider(classes="mt-8 mb-1", color="red") + v3.VListItem( + prepend_icon="mdi-timer-sand-complete", + click=self.fake_busy, + title=("compact_drawer ? null : 'Trigger busy'",), + ) + v3.VListItem( + prepend_icon="mdi-database-refresh-outline", + click=self.ctrl.on_server_reload, + title=("compact_drawer ? null : 'Refresh UI'",), + ) + + # with v3.Template(raw_attrs=["#append"]): + # with v3.VList(density="compact", nav=True): + # v3.VListItem( + # prepend_icon="mdi-lifebuoy", + # click="compact_drawer = !compact_drawer", + # title=("compact_drawer ? null : 'Toggle Help'",), + # ) + with v3.VMain(): # load-data with html.Div( @@ -565,8 +632,10 @@ def fake_busy(self): @controller.add_task("file_selection_load") async def data_loading_open(self, simulation, connectivity): - self.selected_variables = None + # Reset state + self.state.variables_selected = [] self.state.variables_loaded = False + await asyncio.sleep(0.1) self.source.Update( data_file=simulation, @@ -611,26 +680,33 @@ def data_loading_hide(self): tool for tool in self.state.active_tools if tool != "load-data" ] - def data_load_variables(self): + @property + def selected_variables(self): vars_per_type = {n: [] for n in "smi"} for var in self.state.variables_selected: type = var[0] name = var[1:] vars_per_type[type].append(name) + print("=> selected_variables", vars_per_type) + + return vars_per_type + + def data_load_variables(self): + vars_to_show = self.selected_variables + self.source.LoadVariables( - vars_per_type["s"], # surfaces - vars_per_type["m"], # midpoints - vars_per_type["i"], # interfaces + vars_to_show["s"], # surfaces + vars_to_show["m"], # midpoints + vars_to_show["i"], # interfaces ) - self.selected_variables = vars_per_type - self.view_manager.build_auto_layout(vars_per_type) + self.view_manager.build_auto_layout(vars_to_show) # Compute Layer/Time column spread n_cols = 1 # time toolbar_slider_visibility = [] for var_type in "mi": - if vars_per_type[var_type]: + if vars_to_show[var_type]: toolbar_slider_visibility.append(var_type) n_cols += 1 @@ -646,10 +722,11 @@ def _on_dirty_variable_selection(self, **_): @change("col_mode") def _on_layout_refresh(self, **_): - if self.selected_variables is None: - return - - self.view_manager.build_auto_layout(self.selected_variables) + vars_to_show = self.selected_variables + print("col_mode", vars_to_show) + if any(vars_to_show.values()): + print("build layout") + self.view_manager.build_auto_layout(vars_to_show) @change("projection") async def _on_projection(self, projection, **_): From c72b3685d7f51d55c60fb5b0dc936fd05f8b2271 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Fri, 3 Oct 2025 18:04:46 -0600 Subject: [PATCH 05/14] feat(animation): enable animation --- pyproject.toml | 1 + quickview/app2.py | 275 +++++++++++++++++++++++++--------- quickview/presets/__init__.py | 19 +++ quickview/utils/compute.py | 45 ++++++ quickview/view_manager2.py | 64 ++++++-- 5 files changed, 321 insertions(+), 83 deletions(-) create mode 100644 quickview/presets/__init__.py create mode 100644 quickview/utils/compute.py diff --git a/pyproject.toml b/pyproject.toml index 49286db..df86adf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ dependencies = [ "pyproj>=3.6.1", "netCDF4>=1.6.5", "pyinstaller", + "trame-dataclass", ] requires-python = ">=3.13" readme = "README.md" diff --git a/quickview/app2.py b/quickview/app2.py index 556353b..6c6ca78 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -4,15 +4,17 @@ from pathlib import Path -from trame.app import TrameApp +from trame.app import TrameApp, asynchronous from trame.ui.vuetify3 import VAppLayout from trame.widgets import vuetify3 as v3, client, html from trame.decorators import controller, change +from quickview import __version__ as quickview_version from quickview.pipeline import EAMVisSource from quickview.assets import ASSETS from quickview.view_manager2 import ViewManager from quickview.components.file_browser import ParaViewFileBrowser +from quickview.utils import compute v3.enable_lab() @@ -24,6 +26,18 @@ {"title": "Type", "align": "start", "key": "type", "sortable": True}, ] +TRACK_STEPS = { + "timestamps": "time_idx", + "interfaces": "interface_idx", + "midpoints": "midpoint_idx", +} + +TRACK_ENTRIES = { + "timestamps": {"title": "Time", "value": "timestamps"}, + "midpoints": {"title": "Layer Midpoints", "value": "midpoints"}, + "interfaces": {"title": "Layer Interfaces", "value": "interfaces"}, +} + def js_var_count(name): return f"variables_selected.filter((v) => v[0] === '{name[0]}').length" @@ -77,9 +91,32 @@ def __init__(self, server=None): if self.server.hot_reload: self.ctrl.on_server_reload.add(self._build_ui) + # Initial UI state + self.state.update( + { + "trame__title": "QuickView", + "trame__favicon": ASSETS.icon, + "animation_play": False, + # All available variables + "variables_listing": [], + # Selected variables to load + "variables_selected": [], + # Control 'Load Variables' button availability + "variables_loaded": False, + # Level controls + "midpoint_idx": 0, + "midpoints": [], + "interface_idx": 0, + "interfaces": [], + # Time controls + "time_idx": 0, + "timestamps": [], + # Fields summaries + "fields_avgs": {}, + } + ) + # Data input - self.state.variables_listing = [] - self.state.toolbar_slider_visibility = [] self.source = EAMVisSource() self.app_state = {} @@ -306,13 +343,13 @@ def _build_ui(self, **_): title=("compact_drawer ? null : 'Refresh UI'",), ) - # with v3.Template(raw_attrs=["#append"]): - # with v3.VList(density="compact", nav=True): - # v3.VListItem( - # prepend_icon="mdi-lifebuoy", - # click="compact_drawer = !compact_drawer", - # title=("compact_drawer ? null : 'Toggle Help'",), - # ) + # Show version at the bottom + with v3.Template(raw_attrs=["#append"]): + v3.VDivider() + v3.VLabel( + f"{quickview_version}", + classes="text-center text-caption d-block text-wrap", + ) with v3.VMain(): # load-data @@ -490,11 +527,8 @@ def _build_ui(self, **_): # midpoint layer with v3.VCol( cols=("toolbar_slider_cols", 4), - v_show="toolbar_slider_visibility.includes('m')", + v_show="midpoints.length > 1", ): - self.state.setdefault( - "layer_midpoints_value", 80.50 - ) with v3.VRow(classes="mx-2 my-0"): v3.VLabel( "Layer Midpoints", @@ -502,13 +536,13 @@ def _build_ui(self, **_): ) v3.VSpacer() v3.VLabel( - "{{ layer_midpoints_value }} hPa (k={{layer_midpoints}})", + "{{ parseFloat(midpoints[midpoint_idx] || 0).toFixed(2) }} hPa (k={{ midpoint_idx }})", classes="text-body-2", ) v3.VSlider( - v_model=("layer_midpoints", 0), + v_model=("midpoint_idx", 0), min=0, - max=("layer_midpoints_max", 10), + max=("Math.max(0, midpoints.length - 1)",), step=1, density="compact", hide_details=True, @@ -517,11 +551,8 @@ def _build_ui(self, **_): # interface layer with v3.VCol( cols=("toolbar_slider_cols", 4), - v_show="toolbar_slider_visibility.includes('i')", + v_show="interfaces.length > 1", ): - self.state.setdefault( - "layer_interfaces_value", 80.50 - ) with v3.VRow(classes="mx-2 my-0"): v3.VLabel( "Layer Interfaces", @@ -529,32 +560,35 @@ def _build_ui(self, **_): ) v3.VSpacer() v3.VLabel( - "{{ layer_interfaces_value }} hPa (k={{layer_interfaces}})", + "{{ parseFloat(interfaces[interface_idx] || 0).toFixed(2) }} hPa (k={{interface_idx}})", classes="text-body-2", ) v3.VSlider( - v_model=("layer_interfaces", 0), + v_model=("interface_idx", 0), min=0, - max=("layer_interfaces_max", 10), + max=("Math.max(0, interfaces.length - 1)",), step=1, density="compact", hide_details=True, ) # time - with v3.VCol(cols=("toolbar_slider_cols", 4)): + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="timestamps.length > 1", + ): self.state.setdefault("time_value", 80.50) with v3.VRow(classes="mx-2 my-0"): v3.VLabel("Time", classes="text-subtitle-2") v3.VSpacer() v3.VLabel( - "{{ time_value }} hPa (t={{time}})", + "{{ parseFloat(timestamps[time_idx]).toFixed(2) }} (t={{time_idx}})", classes="text-body-2", ) v3.VSlider( - v_model=("time", 0), + v_model=("time_idx", 0), min=0, - max=("time_max", 10), + max=("Math.max(0, timestamps.length - 1)",), step=1, density="compact", hide_details=True, @@ -573,56 +607,83 @@ def _build_ui(self, **_): ) with v3.VRow(classes="ma-0 px-2 align-center"): v3.VSelect( - v_model=("animation_track", "Time"), - items=( - "animation_tracks", - [ - "Time", - "Layer Midpoints", - "Layer Interfaces", - ], - ), + v_model=("animation_track", "timestamps"), + items=("animation_tracks", []), flat=True, variant="plain", hide_details=True, density="compact", - style="max-width: 200px;", + style="max-width: 10rem;", ) + v3.VDivider(vertical=True, classes="mx-2") v3.VSlider( v_model=("animation_step", 1), min=0, - max=("amimation_step_max", 100), + max=("amimation_step_max", 0), step=1, hide_details=True, density="compact", + classes="mx-4", ) + v3.VDivider(vertical=True, classes="mx-2") v3.VIconBtn( icon="mdi-page-first", flat=True, + disabled=("animation_step === 0",), + click="animation_step = 0", ) v3.VIconBtn( icon="mdi-chevron-left", flat=True, + disabled=("animation_step === 0",), + click="animation_step = Math.max(0, animation_step - 1)", ) v3.VIconBtn( icon="mdi-chevron-right", flat=True, + disabled=( + "animation_step === amimation_step_max", + ), + click="animation_step = Math.min(amimation_step_max, animation_step + 1)", ) v3.VIconBtn( icon="mdi-page-last", + disabled=( + "animation_step === amimation_step_max", + ), flat=True, + click="animation_step = amimation_step_max", ) + v3.VDivider(vertical=True, classes="mx-2") v3.VIconBtn( - icon="mdi-play", - flat=True, - ) - v3.VIconBtn( - icon="mdi-stop", + icon=( + "animation_play ? 'mdi-stop' : 'mdi-play'", + ), flat=True, + click="animation_play = !animation_play", ) client.ServerTemplate(name=("active_layout", "auto_layout")) + # ------------------------------------------------------------------------- + # Derived properties + # ------------------------------------------------------------------------- + + @property + def selected_variables(self): + vars_per_type = {n: [] for n in "smi"} + for var in self.state.variables_selected: + type = var[0] + name = var[1:] + vars_per_type[type].append(name) + + return vars_per_type + + @property + def selected_variable_names(self): + # Remove var type (first char) + return [var[1:] for var in self.state.variables_selected] + # ------------------------------------------------------------------------- # Methods connected to UI # ------------------------------------------------------------------------- @@ -635,6 +696,12 @@ async def data_loading_open(self, simulation, connectivity): # Reset state self.state.variables_selected = [] self.state.variables_loaded = False + self.state.midpoint_idx = 0 + self.state.midpoints = [] + self.state.interface_idx = 0 + self.state.interfaces = [] + self.state.time_idx = 0 + self.state.timestamps = [] await asyncio.sleep(0.1) self.source.Update( @@ -671,8 +738,24 @@ async def data_loading_open(self, simulation, connectivity): ), ] - # for name in ["timestamps", "midpoints", "interfaces", "surface_vars", "interface_vars", "midpoint_vars", ]: - # print(name, getattr(self.source, name)) + # Update Layer/Time values and ui layout + n_cols = 0 + available_tracks = [] + for name in ["midpoints", "interfaces", "timestamps"]: + values = getattr(self.source, name) + self.state[name] = values + + if len(values) > 1: + n_cols += 1 + available_tracks.append(TRACK_ENTRIES[name]) + + self.state.toolbar_slider_cols = 12 / n_cols if n_cols else 12 + self.state.animation_tracks = available_tracks + self.state.animation_track = ( + self.state.animation_tracks[0]["value"] + if available_tracks + else None + ) @controller.set("file_selection_cancel") def data_loading_hide(self): @@ -680,19 +763,8 @@ def data_loading_hide(self): tool for tool in self.state.active_tools if tool != "load-data" ] - @property - def selected_variables(self): - vars_per_type = {n: [] for n in "smi"} - for var in self.state.variables_selected: - type = var[0] - name = var[1:] - vars_per_type[type].append(name) - - print("=> selected_variables", vars_per_type) - - return vars_per_type - def data_load_variables(self): + """Called at 'Load Variables' button click""" vars_to_show = self.selected_variables self.source.LoadVariables( @@ -700,21 +772,14 @@ def data_load_variables(self): vars_to_show["m"], # midpoints vars_to_show["i"], # interfaces ) - self.view_manager.build_auto_layout(vars_to_show) - - # Compute Layer/Time column spread - n_cols = 1 # time - toolbar_slider_visibility = [] - for var_type in "mi": - if vars_to_show[var_type]: - toolbar_slider_visibility.append(var_type) - n_cols += 1 + # Trigger source update + compute avg with self.state: self.state.variables_loaded = True - self.state.toolbar_slider_cols = 12 / n_cols if n_cols else 12 - self.state.toolbar_slider_visibility = toolbar_slider_visibility - self.state.dirty("toolbar_slider_visibility") + + # Update views in layout + with self.state: + self.view_manager.build_auto_layout(vars_to_show) @change("variables_selected") def _on_dirty_variable_selection(self, **_): @@ -723,9 +788,7 @@ def _on_dirty_variable_selection(self, **_): @change("col_mode") def _on_layout_refresh(self, **_): vars_to_show = self.selected_variables - print("col_mode", vars_to_show) if any(vars_to_show.values()): - print("build layout") self.view_manager.build_auto_layout(vars_to_show) @change("projection") @@ -742,6 +805,74 @@ async def _on_projection(self, projection, **_): await asyncio.sleep(0.1) self.view_manager.reset_camera() + @change( + "variables_loaded", + "time_idx", + "midpoint_idx", + "interface_idx", + "crop_longitude", + "crop_latitude", + "projection", + ) + def _on_time_change( + self, + variables_loaded, + time_idx, + timestamps, + midpoint_idx, + interface_idx, + crop_longitude, + crop_latitude, + projection, + **_, + ): + if not variables_loaded: + return + + time_value = timestamps[time_idx] if len(timestamps) else 0.0 + self.source.UpdateLev(midpoint_idx, interface_idx) + self.source.ApplyClipping(crop_longitude, crop_latitude) + self.source.UpdateProjection(projection[0]) + self.source.UpdateTimeStep(time_idx) + self.source.UpdatePipeline(time_value) + self.view_manager.render() + + # Update avg computation + # Get area variable to calculate weighted average + data = self.source.views["atmosphere_data"] + self.state.fields_avgs = compute.extract_avgs( + data, self.selected_variable_names + ) + + @change("animation_track") + def _on_animation_track_change(self, animation_track, **_): + self.state.animation_step = 0 + self.state.amimation_step_max = 0 + + if animation_track: + self.state.amimation_step_max = len(self.state[animation_track]) - 1 + + @change("animation_step") + def _on_animation_step(self, animation_track, animation_step, **_): + if animation_track: + self.state[TRACK_STEPS[animation_track]] = animation_step + + @change("animation_play") + def _on_animation_play(self, animation_play, **_): + if animation_play: + asynchronous.create_task(self._run_animation()) + + async def _run_animation(self): + with self.state as s: + while s.animation_play: + await asyncio.sleep(0.1) + if s.animation_step < s.amimation_step_max: + with s: + s.animation_step += 1 + await self.server.network_completion + else: + s.animation_play = False + # ------------------------------------------------------------------------- # Standalone execution diff --git a/quickview/presets/__init__.py b/quickview/presets/__init__.py new file mode 100644 index 0000000..26b7667 --- /dev/null +++ b/quickview/presets/__init__.py @@ -0,0 +1,19 @@ +from pathlib import Path + +from paraview import simple + +ALL_PRESETS = set(simple.GetLookupTableNames()) +CUSTOM_PRESETS = set() + +# Import any missing preset +for preset_file in Path(__file__).parent.glob("*_PARAVIEW.xml"): + preset_name = preset_file.name[:-13] # remove _PARAVIEW.xml + if preset_name not in ALL_PRESETS: + try: + simple.ImportPresets(str(preset_file.resolve())) + ALL_PRESETS.add(preset_name) + CUSTOM_PRESETS.add(preset_name) + except Exception as e: + print("Error importing color preset to ParaView", e) + +PARAVIEW_PRESETS = ALL_PRESETS - CUSTOM_PRESETS diff --git a/quickview/utils/compute.py b/quickview/utils/compute.py new file mode 100644 index 0000000..ca2beeb --- /dev/null +++ b/quickview/utils/compute.py @@ -0,0 +1,45 @@ +from paraview import servermanager +import numpy as np +from typing import Optional + + +def calculate_weighted_average( + data_array: np.ndarray, weights: Optional[np.ndarray] = None +) -> float: + """ + Calculate average of data, optionally weighted. + + Args: + data_array: The data to average + weights: Optional weights for weighted averaging (e.g., area weights) + + Returns: + The (weighted) average, handling NaN values + """ + data = np.array(data_array) + weights = np.array(weights) + # Handle NaN values + if np.isnan(data).any(): + mask = ~np.isnan(data) + if not np.any(mask): + return np.nan # all values are NaN + data = data[mask] + if weights is not None: + weights = weights[mask] + + if weights is not None: + return float(np.average(data, weights=weights)) + else: + return float(np.mean(data)) + + +def extract_avgs(pv_data, array_names): + results = {} + vtk_data = servermanager.Fetch(pv_data) + area_array = vtk_data.GetCellData().GetArray("area") + for name in array_names: + vtk_array = vtk_data.GetCellData().GetArray(name) + avg_value = calculate_weighted_average(vtk_array, area_array) + results[name] = avg_value + + return results diff --git a/quickview/view_manager2.py b/quickview/view_manager2.py index 062b7fa..570d77b 100644 --- a/quickview/view_manager2.py +++ b/quickview/view_manager2.py @@ -3,8 +3,12 @@ from trame.widgets import paraview as pvw, vuetify3 as v3, client, html from trame.decorators import hot_reload +from trame_dataclass.core import StateDataModel + from paraview import simple +from quickview.presets import CUSTOM_PRESETS, PARAVIEW_PRESETS, ALL_PRESETS + def auto_size_to_col(size): if size == 1: @@ -39,8 +43,15 @@ def auto_size_to_col(size): } +class ViewState(StateDataModel): + preset: str = "Fast" + invert: bool = False + color_range: list[float] + data_range: list[float] + + class VariableView(TrameComponent): - def __init__(self, server, source, variable_name): + def __init__(self, server, source, variable_name, variable_type): super().__init__(server) self.source = source self.variable_name = variable_name @@ -65,7 +76,7 @@ def __init__(self, server, source, variable_name): self.disable_render = False # FIXME use preset/logscale/invert/range - self._build_ui() + self._build_ui(variable_type) def render(self): if self.disable_render: @@ -85,15 +96,42 @@ def reset_camera(self): self.view.ResetCamera(True, 0.9) self.ctx[self.name].update() - def _build_ui(self): + def _build_ui(self, variable_type): with DivLayout( self.server, template_name=self.name, connect_parent=False ) as self.ui: with v3.VCard(variant="tonal"): - v3.VCardSubtitle( - self.variable_name, - classes="pt-1 pb-0 px-2 bg-black opacity-90 text-subtitle-2", - ) + with v3.VRow( + dense=True, + classes="ma-0 pa-0 bg-black opacity-90 d-flex align-center", + ): + html.Div(self.variable_name, classes="text-subtitle-2 px-2") + v3.VSpacer() + html.Div( + "t = {{ time_idx }}", + classes="text-caption px-1", + v_if="timestamps.length > 1", + ) + if variable_type == "m": + html.Div( + "[k = {{ midpoint_idx }}]", + classes="text-caption px-1", + v_if="midpoints.length > 1", + ) + if variable_type == "i": + html.Div( + "[k = {{ interface_idx }}]", + classes="text-caption px-1", + v_if="interfaces.length > 1", + ) + v3.VSpacer() + html.Div( + "avg = {{" + f"fields_avgs['{self.variable_name}']?.toExponential(2) || 'N/A'" + "}}", + classes="text-caption px-1", + ) + with html.Div(style=("`aspect-ratio: ${aspect_ratio};`",)): pvw.VtkRemoteView( self.view, interactive_ratio=1, ctx_name=self.name @@ -120,12 +158,16 @@ def reset_camera(self): for view in views: view.disable_render = False - def get_view(self, variable_name): + def render(self): + for view in list(self._var2view.values()): + view.render() + + def get_view(self, variable_name, variable_type): view = self._var2view.get(variable_name) if view is None: view = self._var2view.setdefault( variable_name, - VariableView(self.server, self.source, variable_name), + VariableView(self.server, self.source, variable_name, variable_type), ) view.set_camera_modified(self.sync_camera) @@ -167,7 +209,7 @@ def build_auto_layout(self, variables): ): with v3.VRow(dense=True): for name in var_names: - view = self.get_view(name) + view = self.get_view(name, var_type) with v3.VCol(cols=n_cols): client.ServerTemplate(name=view.name) else: @@ -176,6 +218,6 @@ def build_auto_layout(self, variables): for var_type in "smi": var_names = variables[var_type] for name in var_names: - view = self.get_view(name) + view = self.get_view(name, var_type) with v3.VCol(cols=n_cols): client.ServerTemplate(name=view.name) From 00ce9d141fd7b34c56fb16218a22902fb05c8c94 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Tue, 14 Oct 2025 19:00:45 -0600 Subject: [PATCH 06/14] feat: lut/size/order/import/export --- docs/setup/for_app_developers.md | 2 +- quickview/app2.py | 262 +++++++++++++-- quickview/components/file_browser.py | 50 ++- quickview/components/variables.py | 0 quickview/module/__init__.py | 6 + quickview/module/serve/utils.js | 11 + quickview/view_manager2.py | 481 ++++++++++++++++++++++++--- 7 files changed, 740 insertions(+), 72 deletions(-) delete mode 100644 quickview/components/variables.py create mode 100644 quickview/module/__init__.py create mode 100644 quickview/module/serve/utils.js diff --git a/docs/setup/for_app_developers.md b/docs/setup/for_app_developers.md index 5433f53..99b909f 100644 --- a/docs/setup/for_app_developers.md +++ b/docs/setup/for_app_developers.md @@ -38,7 +38,7 @@ python -m quickview.app --data /path/to/your/data.nc --conn /path/to/connectivit To launch server only (no browser popup), use ``` -python --server -m quickview.app --data /path/to/your/data.nc --conn /path/to/connectivity.nc +python -m quickview.app --data /path/to/your/data.nc --conn /path/to/connectivity.nc --server ``` ---- diff --git a/quickview/app2.py b/quickview/app2.py index 6c6ca78..a1c3c26 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -4,10 +4,10 @@ from pathlib import Path -from trame.app import TrameApp, asynchronous +from trame.app import TrameApp, asynchronous, file_upload from trame.ui.vuetify3 import VAppLayout -from trame.widgets import vuetify3 as v3, client, html -from trame.decorators import controller, change +from trame.widgets import vuetify3 as v3, client, html, dataclass +from trame.decorators import controller, change, trigger from quickview import __version__ as quickview_version from quickview.pipeline import EAMVisSource @@ -15,6 +15,7 @@ from quickview.view_manager2 import ViewManager from quickview.components.file_browser import ParaViewFileBrowser from quickview.utils import compute +from quickview import module as qv_module v3.enable_lab() @@ -60,6 +61,10 @@ class EAMApp(TrameApp): def __init__(self, server=None): super().__init__(server) + # Pre-load deferred widgets + dataclass.initialize(self.server) + self.server.enable_module(qv_module) + # CLI cli = self.server.cli cli.add_argument( @@ -87,10 +92,6 @@ def __init__(self, server=None): ) args, _ = cli.parse_known_args() - # Development setup - if self.server.hot_reload: - self.ctrl.on_server_reload.add(self._build_ui) - # Initial UI state self.state.update( { @@ -118,7 +119,6 @@ def __init__(self, server=None): # Data input self.source = EAMVisSource() - self.app_state = {} # Helpers self.view_manager = ViewManager(self.server, self.source) @@ -131,15 +131,22 @@ def __init__(self, server=None): # Process CLI to pre-load data if args.state is not None: - self.app_state = json.loads(Path(args.state).read_text()) - self.source.Update( - **{k: self.app_state[k] for k in ("data_file", "conn_file")} - ) + state_content = json.loads(Path(args.state).read_text()) + + async def wait_for_import(**_): + await self.import_state(state_content) + + self.ctrl.on_server_ready.add_task(wait_for_import) elif args.data and args.conn: self.file_browser.set_data_simulation(args.data) self.file_browser.set_data_connectivity(args.conn) self.ctrl.on_server_ready.add(self.file_browser.load_data_files) + # Development setup + if self.server.hot_reload: + self.ctrl.on_server_reload.add(self._build_ui) + self.ctrl.on_server_reload.add(self.view_manager.refresh_ui) + # GUI self._build_ui() @@ -160,14 +167,16 @@ def _build_ui(self, **_): v_model_selected=("active_tools", ["load-data"]), ): with v3.VTooltip( - text="Reset camera", disabled=("!compact_drawer",) + text=f"QuickView {quickview_version}", + disabled=("!compact_drawer",), ): with v3.Template(v_slot_activator="{ props }"): with v3.VListItem( v_bind="props", - title=("compact_drawer ? null : 'QuickView'",), + title=( + f"compact_drawer ? null : 'QuickView {quickview_version}'", + ), classes="text-h6", - click=self.view_manager.reset_camera, ): with v3.Template(raw_attrs=["#prepend"]): v3.VAvatar( @@ -212,6 +221,17 @@ def _build_ui(self, **_): ), ) + with v3.VTooltip( + text="Reset camera", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-crop-free", + title=("compact_drawer ? null : 'Reset camera'",), + click=self.view_manager.reset_camera, + ) + with v3.VTooltip( text="State Import/Export", disabled=("!compact_drawer",) ): @@ -431,6 +451,47 @@ def _build_ui(self, **_): with v3.VContainer(classes="h-100 pa-0", fluid=True): with client.SizeObserver("main_size"): + # Import/Export toolbar + with v3.VToolbar( + v_show="active_tools.includes('import-export')", + color="white", + classes="border-b-thin", + ): + v3.VIcon( + "mdi-folder-arrow-left-right-outline", + classes="px-6 opacity-50", + ) + v3.VLabel( + "Import/Export Controls", classes="text-subtitle-2" + ) + v3.VSpacer() + + v3.VTextField( + v_model=("download_name", "quickview-state.json"), + hide_details=True, + density="compact", + label="Download state file", + prepend_inner_icon="mdi-file-download-outline", + variant="outlined", + flat=True, + style="max-width: 250px", + classes="mx-2", + click_prependInner="utils.download(download_name, trigger('download_state'), 'application/json')", + ) + + v3.VFileInput( + v_model=("upload_state_file", None), + hide_details=True, + chips=True, + density="compact", + label="Import state file", + prepend_icon=False, + prepend_inner_icon="mdi-file-upload-outline", + variant="outlined", + style="max-width: 250px", + classes="mx-2", + ) + # Layout control toolbar with v3.VToolbar( v_show="active_tools.includes('adjust-layout')", @@ -442,21 +503,6 @@ def _build_ui(self, **_): v3.VLabel("Layout Controls", classes="text-subtitle-2") v3.VSpacer() - with v3.VRadioGroup( - classes="d-inline-block", - hide_details=True, - inline=True, - v_model=("col_mode", "auto"), - ): - v3.VRadio(label="Auto", value="auto") - v3.VRadio(label="Full width", value="1") - v3.VRadio(label="2 cols", value="2") - v3.VRadio(label="3 cols", value="3") - v3.VRadio(label="4 cols", value="4") - v3.VRadio(label="6 cols", value="6") - v3.VRadio(label="12 cols", value="12") - - v3.VSpacer() v3.VSlider( v_model=("aspect_ratio", 2), prepend_icon="mdi-aspect-ratio", @@ -466,8 +512,68 @@ def _build_ui(self, **_): density="compact", hide_details=True, style="max-width: 400px;", - classes="mx-4", ) + v3.VSpacer() + v3.VCheckbox( + v_model=("layout_grouped", True), + label=("layout_grouped ? 'Grouped' : 'Uniform'",), + hide_details=True, + inset=True, + false_icon="mdi-apps", + true_icon="mdi-focus-field", + density="compact", + ) + + with v3.VBtn( + "Size", + classes="text-none mx-4", + prepend_icon="mdi-view-module", + append_icon="mdi-menu-down", + ): + with v3.VMenu(activator="parent"): + with v3.VList(density="compact"): + v3.VListItem( + title="Auto", + click=( + self.view_manager.apply_size, + "[0]", + ), + ) + v3.VListItem( + title="Full Width", + click=( + self.view_manager.apply_size, + "[1]", + ), + ) + v3.VListItem( + title="2 Columns", + click=( + self.view_manager.apply_size, + "[2]", + ), + ) + v3.VListItem( + title="3 Columns", + click=( + self.view_manager.apply_size, + "[3]", + ), + ) + v3.VListItem( + title="4 Columns", + click=( + self.view_manager.apply_size, + "[4]", + ), + ) + v3.VListItem( + title="6 Columns", + click=( + self.view_manager.apply_size, + "[6]", + ), + ) # Crop selection with v3.VToolbar( @@ -688,6 +794,93 @@ def selected_variable_names(self): # Methods connected to UI # ------------------------------------------------------------------------- + @trigger("download_state") + def download_state(self): + active_variables = self.selected_variables + state_content = {} + state_content["files"] = { + "simulation": self.file_browser.get("data_simulation"), + "connectivity": self.file_browser.get("data_connectivity"), + } + state_content["variables-selection"] = self.state.variables_selected + state_content["layout"] = { + "aspect-ratio": self.state.aspect_ratio, + "grouped": self.state.layout_grouped, + "active": self.state.active_layout, + "tools": self.state.active_tools, + "help": not self.state.compact_drawer, + } + state_content["data-selection"] = { + k: self.state[k] + for k in [ + "time_idx", + "midpoint_idx", + "interface_idx", + "crop_longitude", + "crop_latitude", + "projection", + ] + } + views_to_export = state_content["views"] = [] + for view_type, var_names in active_variables.items(): + for var_name in var_names: + config = self.view_manager.get_view(var_name, view_type).config + views_to_export.append( + { + "type": view_type, + "name": var_name, + "config": { + "preset": config.preset, + "invert": config.invert, + "use_log_scale": config.use_log_scale, + "color_range": config.color_range, + "override_range": config.override_range, + "order": config.order, + "size": config.size, + }, + } + ) + + return json.dumps(state_content, indent=2) + + @change("upload_state_file") + def _on_import_state(self, upload_state_file, **_): + if upload_state_file is None: + return + + file_proxy = file_upload.ClientFile(upload_state_file) + state_content = json.loads(file_proxy.content) + asynchronous.create_task(self.import_state(state_content)) + + @controller.set("import_state") + async def import_state(self, state_content): + # Files + self.file_browser.set_data_simulation(state_content["files"]["simulation"]) + self.file_browser.set_data_connectivity(state_content["files"]["connectivity"]) + await self.data_loading_open( + self.file_browser.get("data_simulation"), + self.file_browser.get("data_connectivity"), + ) + + # Load variables + self.state.variables_selected = state_content["variables-selection"] + self.state.update(state_content["data-selection"]) + self.data_load_variables() + + # Update view states + for view_state in state_content["views"]: + view_type = view_state["type"] + var_name = view_state["name"] + config = self.view_manager.get_view(var_name, view_type).config + config.update(**view_state["config"]) + + # Update layout + self.state.aspect_ratio = state_content["layout"]["aspect-ratio"] + self.state.layout_grouped = state_content["layout"]["grouped"] + self.state.active_layout = state_content["layout"]["active"] + self.state.active_tools = state_content["layout"]["tools"] + self.state.compact_drawer = not state_content["layout"]["help"] + def fake_busy(self): time.sleep(3) @@ -785,9 +978,10 @@ def data_load_variables(self): def _on_dirty_variable_selection(self, **_): self.state.variables_loaded = False - @change("col_mode") - def _on_layout_refresh(self, **_): + @change("layout_grouped") + def _on_layout_change(self, **_): vars_to_show = self.selected_variables + if any(vars_to_show.values()): self.view_manager.build_auto_layout(vars_to_show) @@ -835,6 +1029,8 @@ def _on_time_change( self.source.UpdateProjection(projection[0]) self.source.UpdateTimeStep(time_idx) self.source.UpdatePipeline(time_value) + + self.view_manager.update_color_range() self.view_manager.render() # Update avg computation diff --git a/quickview/components/file_browser.py b/quickview/components/file_browser.py index 71eeb54..5fdacd4 100644 --- a/quickview/components/file_browser.py +++ b/quickview/components/file_browser.py @@ -1,8 +1,9 @@ +import json import re from pathlib import Path from paraview import simple from trame.widgets import vuetify3 as v3, html -from trame.app import TrameComponent +from trame.app import TrameComponent, asynchronous DIRECTORY = dict(icon="mdi-folder", type="directory") GROUP = dict(icon="mdi-file-document-multiple-outline", type="group") @@ -46,6 +47,9 @@ def __init__( self.pattern_exclude = re.compile(exclude) self.pattern_group = re.compile(group) + # Disable state import by default + self.set("is_state_file", False) + self._pxm = simple.servermanager.ProxyManager() self._proxy_listing = self._pxm.NewProxy("misc", "ListDirectory") self._proxy_directories = simple.servermanager.VectorProperty( @@ -229,6 +233,28 @@ def open_dataset(self, entry): def select_entry(self, entry): with self.state as state: state[f"{self._prefix}_active"] = entry.get("index", 0) if entry else -1 + file_path = Path(self.active_path) + + # Check if it is a state file + if file_path.suffix == ".json" and file_path.exists(): + state_content = json.loads(file_path.read_text()) + self.set( + "is_state_file", + all( + ( + k in state_content + for k in [ + "files", + "variables-selection", + "layout", + "data-selection", + "views", + ] + ) + ), + ) + else: + self.set("is_state_file", False) def load_data_files(self, **_): self.set("loading", True) @@ -239,6 +265,19 @@ def load_data_files(self, **_): self.get("data_simulation"), self.get("data_connectivity") ) + def import_state_file(self): + self.set("state_loading", True) + + state_content = json.loads(Path(self.active_path).read_text()) + coroutine = self.ctrl.import_state(state_content) + task = asynchronous.create_task(coroutine) + + def done_loading(): + with self.state: + self.set("state_loading", False) + + task.add_done_callback(done_loading) + def cancel(self): self.ctrl.file_selection_cancel() @@ -390,6 +429,15 @@ def ui(self): variant="flat", click=self.cancel, ) + v3.VBtn( + disabled=(f"!{self.name('is_state_file')}",), + loading=(self.name("state_loading"), False), + classes="text-none", + color="primary", + text="Import state file", + variant="flat", + click=self.import_state_file, + ) v3.VBtn( classes="text-none", color=(f"{self.name('error')} ? 'error' : 'primary'",), diff --git a/quickview/components/variables.py b/quickview/components/variables.py deleted file mode 100644 index e69de29..0000000 diff --git a/quickview/module/__init__.py b/quickview/module/__init__.py new file mode 100644 index 0000000..84b3d26 --- /dev/null +++ b/quickview/module/__init__.py @@ -0,0 +1,6 @@ +from pathlib import Path + +__all__ = ["serve", "scripts"] + +serve = {"quick_view": str(Path(__file__).with_name("serve").resolve())} +scripts = ["quick_view/utils.js"] diff --git a/quickview/module/serve/utils.js b/quickview/module/serve/utils.js new file mode 100644 index 0000000..0371e77 --- /dev/null +++ b/quickview/module/serve/utils.js @@ -0,0 +1,11 @@ +window.trame.utils.quickview = { + formatRange(value, useLog) { + if (value === null || value === undefined || isNaN(value)) { + return 'Auto'; + } + if (useLog && value > 0) { + return `10^(${Math.log10(value).toFixed(1)})`; + } + return value.toExponential(1); + } +} diff --git a/quickview/view_manager2.py b/quickview/view_manager2.py index 570d77b..3116289 100644 --- a/quickview/view_manager2.py +++ b/quickview/view_manager2.py @@ -1,13 +1,17 @@ +import math + from trame.app import TrameComponent from trame.ui.html import DivLayout from trame.widgets import paraview as pvw, vuetify3 as v3, client, html -from trame.decorators import hot_reload +from trame.decorators import hot_reload, controller from trame_dataclass.core import StateDataModel from paraview import simple +from quickview.utils.color import get_cached_colorbar_image from quickview.presets import CUSTOM_PRESETS, PARAVIEW_PRESETS, ALL_PRESETS +from quickview.utils.color import COLORBAR_CACHE def auto_size_to_col(size): @@ -27,13 +31,13 @@ def auto_size_to_col(size): COL_SIZE_LOOKUP = { - "auto": auto_size_to_col, - "1": 12, - "2": 6, - "3": 4, - "4": 3, - "6": 2, - "12": 1, + 0: auto_size_to_col, + 1: 12, + 2: 6, + 3: 4, + 4: 3, + 6: 2, + 12: 1, } TYPE_COLOR = { @@ -43,18 +47,27 @@ def auto_size_to_col(size): } -class ViewState(StateDataModel): - preset: str = "Fast" +class ViewConfiguration(StateDataModel): + variable: str + preset: str = "Inferno (matplotlib)" + preset_img: str invert: bool = False - color_range: list[float] - data_range: list[float] + use_log_scale: bool = False + color_range: list[float] = (0, 1) + override_range: bool = False + order: int = 0 + size: int = 4 + menu: bool = False + swap_group: list[str] class VariableView(TrameComponent): def __init__(self, server, source, variable_name, variable_type): super().__init__(server) + self.config = ViewConfiguration(server, variable=variable_name) self.source = source self.variable_name = variable_name + self.variable_type = variable_type self.name = f"view_{self.variable_name}" self.view = simple.CreateRenderView() self.view.GetRenderWindow().SetOffScreenRendering(True) @@ -67,6 +80,8 @@ def __init__(self, server, source, variable_name, variable_type): proxy=source.views["atmosphere_data"], view=self.view, ) + + # Lookup table color management simple.ColorBy(self.representation, ("CELLS", variable_name)) self.lut = simple.GetColorTransferFunction(variable_name) self.lut.NanOpacity = 0.0 @@ -74,12 +89,48 @@ def __init__(self, server, source, variable_name, variable_type): self.view.ResetActiveCameraToNegativeZ() self.view.ResetCamera(True, 0.9) self.disable_render = False - # FIXME use preset/logscale/invert/range - self._build_ui(variable_type) + # Add annotation to the view + # - continents + globe = source.views["continents"] + repG = simple.Show(globe, self.view) + simple.ColorBy(repG, None) + repG.SetRepresentationType("Wireframe") + repG.RenderLinesAsTubes = 1 + repG.LineWidth = 1.0 + repG.AmbientColor = [0.67, 0.67, 0.67] + repG.DiffuseColor = [0.67, 0.67, 0.67] + self.rep_globe = repG + # - gridlines + annot = source.views["grid_lines"] + repAn = simple.Show(annot, self.view) + repAn.SetRepresentationType("Wireframe") + repAn.AmbientColor = [0.67, 0.67, 0.67] + repAn.DiffuseColor = [0.67, 0.67, 0.67] + repAn.Opacity = 0.4 + self.rep_grid = repAn + + # Reactive behavior + self.config.watch( + ["override_range", "color_range"], self.update_color_range, eager=True + ) + self.config.watch( + ["preset", "invert", "use_log_scale"], self.update_color_preset, eager=True + ) + + # GUI + self._build_ui() + + # def update_order(self, order): + # with self.state: + # self.ctrl.apply_layout() + + # def update_size(self, size): + # with self.state: + # self.ctrl.apply_layout() def render(self): - if self.disable_render: + if self.disable_render or not self.ctx.has(self.name): return self.ctx[self.name].update() @@ -96,29 +147,170 @@ def reset_camera(self): self.view.ResetCamera(True, 0.9) self.ctx[self.name].update() - def _build_ui(self, variable_type): + def update_color_preset(self, name, invert, log_scale): + self.config.preset = name + self.config.preset_img = get_cached_colorbar_image( + self.config.preset, + self.config.invert, + ) + self.lut.ApplyPreset(self.config.preset, True) + if invert: + self.lut.InvertTransferFunction() + if log_scale: + self.lut.MapControlPointsToLogSpace() + self.lut.UseLogScale = 1 + self.render() + + def update_color_range(self, *_): + if self.config.override_range: + if math.isnan(self.config.color_range[0]) or math.isnan( + self.config.color_range[1] + ): + return + self.lut.RescaleTransferFunction(*self.config.color_range) + else: + self.representation.RescaleTransferFunctionToDataRange(False, True) + data_array = ( + self.source.views["atmosphere_data"] + .GetCellDataInformation() + .GetArray(self.variable_name) + ) + if data_array: + data_range = data_array.GetRange() + self.config.color_range = data_range + self.lut.RescaleTransferFunction(*data_range) + self.render() + + @hot_reload + def _build_ui(self): with DivLayout( - self.server, template_name=self.name, connect_parent=False + self.server, template_name=self.name, connect_parent=False, classes="h-100" ) as self.ui: - with v3.VCard(variant="tonal"): + self.ui.root.classes = "h-100" + with v3.VCard( + variant="tonal", + classes=( + "active_layout !== 'auto_layout' ? 'h-100' : 'overflow-hidden'", + ), + tile=("active_layout !== 'auto_layout'",), + ): with v3.VRow( dense=True, classes="ma-0 pa-0 bg-black opacity-90 d-flex align-center", ): - html.Div(self.variable_name, classes="text-subtitle-2 px-2") + with v3.VBtn( + icon=True, + density="compact", + variant="plain", + classes="mx-1", + size="small", + ): + v3.VIcon( + "mdi-arrow-expand", + size="x-small", + style="transform: scale(-1, 1);", + ) + with v3.VMenu(activator="parent"): + with self.config.provide_as("config"): + with v3.VList(density="compact"): + v3.VListItem( + subtitle="Full Screen", + click=f"active_layout = '{self.name}'", + ) + v3.VDivider() + + v3.VListItem( + subtitle="Full width", + click="active_layout = 'auto_layout';config.size = 12", + ) + v3.VListItem( + subtitle="1/2 width", + click="active_layout = 'auto_layout';config.size = 6", + ) + v3.VListItem( + subtitle="1/3 width", + click="active_layout = 'auto_layout';config.size = 4", + ) + v3.VListItem( + subtitle="1/4 width", + click="active_layout = 'auto_layout';config.size = 3", + ) + v3.VListItem( + subtitle="1/6 width", + click="active_layout = 'auto_layout';config.size = 2", + ) + with html.Div( + classes="text-subtitle-2 pr-2", style="user-select: none;" + ) as el: + # v3.VIcon("mdi-menu-down", size="x-small") + el.add_child(self.variable_name) + with v3.VMenu(activator="parent"): + with v3.VList(density="compact", style="max-height: 40vh;"): + with self.config.provide_as("config"): + v3.VListItem( + subtitle=("name",), + v_for="name, idx in config.swap_group", + key="name", + click=( + self.ctrl.swap_order, + "[config.variable, name]", + ), + ) + + # with v3.VListGroup(value="size"): + # with v3.Template(v_slot_activator="{ props }"): + # v3.VListItem( + # title="Size controls", v_bind="props" + # ) + + # v3.VListItem( + # "Auto size", click="config.size = 0" + # ) + # v3.VListItem( + # "Full width", click="config.size = 12" + # ) + # v3.VListItem( + # "Half width", click="config.size = 6" + # ) + # v3.VListItem( + # "1/3 width", click="config.size = 4" + # ) + # v3.VListItem( + # "1/4 width", click="config.size = 3" + # ) + # v3.VListItem( + # "1/6 width", click="config.size = 2" + # ) + # v3.VDivider() + + # v3.VDivider() + + # with v3.VListItem("Order {{ config.order }}"): + # v3.VSpacer() + # v3.VIconBtn( + # icon="mdi-plus", + # size="small", + # click="config.order++", + # ) + # v3.VIconBtn( + # icon="mdi-minus", + # size="small", + # click="config.order--", + # ) + v3.VSpacer() html.Div( "t = {{ time_idx }}", classes="text-caption px-1", v_if="timestamps.length > 1", ) - if variable_type == "m": + if self.variable_type == "m": html.Div( "[k = {{ midpoint_idx }}]", classes="text-caption px-1", v_if="midpoints.length > 1", ) - if variable_type == "i": + if self.variable_type == "i": html.Div( "[k = {{ interface_idx }}]", classes="text-caption px-1", @@ -132,11 +324,139 @@ def _build_ui(self, variable_type): classes="text-caption px-1", ) - with html.Div(style=("`aspect-ratio: ${aspect_ratio};`",)): + with html.Div( + style=( + """{ + aspectRatio: active_layout === 'auto_layout' ? aspect_ratio : null, + height: active_layout !== 'auto_layout' ? 'calc(100% - 2.4rem)' : null, + }""", + ), + ): pvw.VtkRemoteView( self.view, interactive_ratio=1, ctx_name=self.name ) + with self.config.provide_as("config"): + with html.Div( + classes="bg-blue-grey-darken-2 d-flex align-center", + style="height:1rem;position:relative;top:0;user-select:none;cursor:context-menu;", + ): + with v3.VMenu( + v_model="config.menu", + activator="parent", + location="end", + close_on_content_click=False, + ): + with v3.VCard(): + with v3.VCardItem(classes="pb-0"): + v3.VIconBtn( + icon=( + "config.invert ? 'mdi-invert-colors' : 'mdi-invert-colors-off'", + ), + click="config.invert = !config.invert", + size="small", + text="Invert", + variant="text", + ) + v3.VIconBtn( + icon=( + "config.use_log_scale ? 'mdi-math-log' : 'mdi-stairs'", + ), + click="config.use_log_scale = !config.use_log_scale", + size="small", + text=( + "config.use_log_scale ? 'Log scale' : 'Linear scale'", + ), + variant="text", + ) + v3.VIconBtn( + icon=( + "config.override_range ? 'mdi-arrow-expand-horizontal' : 'mdi-pencil'", + ), + click="config.override_range = !config.override_range", + size="small", + text="Use data range", + variant="text", + ) + + with v3.Template(v_slot_append=True): + v3.VLabel( + "{{ config.preset }}", + classes="mr-2 text-caption", + ) + v3.VIconBtn( + icon="mdi-close", + size="small", + text="Close", + click="config.menu=false", + ) + with v3.VCardItem( + v_show="config.override_range", classes="py-0" + ): + v3.VNumberInput( + model_value=("config.color_range[0]",), + update_modelValue="config.color_range = [Number($event), config.color_range[1]]", + hide_details=True, + density="compact", + variant="outlined", + flat=True, + label="Min", + classes="mt-2", + control_variant="hidden", + precision=("15",), + step=( + "Math.max(0.0001, (config.color_range[1] - config.color_range[0]) / 255)", + ), + ) + v3.VNumberInput( + model_value=("config.color_range[1]",), + update_modelValue="config.color_range = [config.color_range[0], Number($event)]", + hide_details=True, + density="compact", + variant="outlined", + flat=True, + label="Max", + classes="mt-2", + control_variant="hidden", + precision=("15",), + step=( + "Math.max(0.0001, (config.color_range[1] - config.color_range[0]) / 255)", + ), + ) + v3.VDivider(classes="mt-2") + with v3.VList(density="compact", max_height="40vh"): + with v3.VListItem( + v_for="url, name in (config.invert ? luts_inverted : luts_normal)", + key="name", + subtitle=("name",), + click=( + self.update_color_preset, + "[name, config.invert, config.use_log_scale]", + ), + active=("config.preset === name",), + ): + html.Img( + src=("url",), + style="width:20rem;height:1rem;", + classes="rounded", + ) + html.Div( + "{{ utils.quickview.formatRange(config.color_range?.[0], config.use_log_scale) }}", + classes="text-caption px-2 text-no-wrap", + ) + with html.Div( + classes="overflow-hidden rounded", style="height:70%;" + ): + html.Img( + src=("config.preset_img",), + style="width:100%;height:2rem;", + draggable=False, + ) + html.Div( + "{{ utils.quickview.formatRange(config.color_range?.[1], config.use_log_scale) }}", + classes="text-caption px-2 text-no-wrap", + ) + class ViewManager(TrameComponent): def __init__(self, server, source): @@ -144,9 +464,18 @@ def __init__(self, server, source): self.source = source self._var2view = {} self._camera_sync_in_progress = False + self._last_vars = {} + self._active_configs = {} pvw.initialize(self.server) + self.state.luts_normal = {k: v["normal"] for k, v in COLORBAR_CACHE.items()} + self.state.luts_inverted = {k: v["inverted"] for k, v in COLORBAR_CACHE.items()} + + def refresh_ui(self, **_): + for view in self._var2view.values(): + view._build_ui() + def reset_camera(self): views = list(self._var2view.values()) for view in views: @@ -162,6 +491,10 @@ def render(self): for view in list(self._var2view.values()): view.render() + def update_color_range(self): + for view in list(self._var2view.values()): + view.update_color_range() + def get_view(self, variable_name, variable_type): view = self._var2view.get(variable_name) if view is None: @@ -187,12 +520,53 @@ def sync_camera(self, camera, *_): self._camera_sync_in_progress = False + @controller.set("swap_order") + def swap_order(self, variable_a, variable_b): + print("swap_order", variable_a, variable_b) + config_a = self._active_configs[variable_a] + config_b = self._active_configs[variable_b] + config_a.order, config_b.order = config_b.order, config_a.order + + def apply_size(self, n_cols): + if not self._last_vars: + return + + if n_cols == 0: + # Auto based on group size + if self.state.layout_grouped: + for var_type in "smi": + var_names = self._last_vars[var_type] + total_size = len(var_names) + + if total_size == 0: + continue + + size = auto_size_to_col(total_size) + for name in var_names: + config = self.get_view(name, var_type).config + config.size = size + + else: + size = auto_size_to_col(len(self._active_configs)) + for config in self._active_configs.values(): + config.size = size + else: + # uniform size + for config in self._active_configs.values(): + config.size = COL_SIZE_LOOKUP[n_cols] + @hot_reload - def build_auto_layout(self, variables): + def build_auto_layout(self, variables=None): + if variables is None: + variables = self._last_vars + + self._last_vars = variables + + # Create UI based on variables + self.state.swap_groups = {} with DivLayout(self.server, template_name="auto_layout") as self.ui: - size_to_col = COL_SIZE_LOOKUP[self.state.col_mode] - with v3.VCol(classes="pa-1"): - if callable(size_to_col): + if self.state.layout_grouped: + with v3.VCol(classes="pa-1"): for var_type in "smi": var_names = variables[var_type] total_size = len(var_names) @@ -200,7 +574,6 @@ def build_auto_layout(self, variables): if total_size == 0: continue - n_cols = size_to_col(total_size) with v3.VAlert( border="start", classes="pr-1 py-1 pl-3 mb-1", @@ -210,14 +583,48 @@ def build_auto_layout(self, variables): with v3.VRow(dense=True): for name in var_names: view = self.get_view(name, var_type) - with v3.VCol(cols=n_cols): - client.ServerTemplate(name=view.name) - else: - n_cols = size_to_col - with v3.VRow(dense=True): - for var_type in "smi": - var_names = variables[var_type] - for name in var_names: - view = self.get_view(name, var_type) - with v3.VCol(cols=n_cols): + view.config.swap_group = [ + n for n in var_names if n != name + ] + with view.config.provide_as("config"): + with v3.VCol( + cols=("config.size",), + style=("`order: ${config.order};`",), + ): + client.ServerTemplate(name=view.name) + else: + all_names = [name for names in variables.values() for name in names] + with v3.VRow(dense=True, classes="pa-2"): + for var_type in "smi": + var_names = variables[var_type] + for name in var_names: + view = self.get_view(name, var_type) + view.config.swap_group = [n for n in all_names if n != name] + with view.config.provide_as("config"): + with v3.VCol( + cols=("config.size",), + style=("`order: ${config.order};`",), + ): client.ServerTemplate(name=view.name) + + # Assign any missing order + self._active_configs = {} + existed_order = set() + order_max = 0 + orders_to_update = [] + for var_type in "smi": + var_names = variables[var_type] + for name in var_names: + config = self.get_view(name, var_type).config + self._active_configs[name] = config + if config.order: + order_max = max(order_max, config.order) + assert config.order not in existed_order, "Order already assigned" + existed_order.add(config.order) + else: + orders_to_update.append(config) + + next_order = order_max + 1 + for config in orders_to_update: + config.order = next_order + next_order += 1 From 81292afb7b16288ba281a9243468cfcee0d56c2d Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Wed, 15 Oct 2025 08:58:25 -0600 Subject: [PATCH 07/14] fix(camera): reset camera after variable loading --- quickview/app2.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/quickview/app2.py b/quickview/app2.py index a1c3c26..a3d74f6 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -351,12 +351,6 @@ def _build_ui(self, **_): ) if self.server.hot_reload: - v3.VDivider(classes="mt-8 mb-1", color="red") - v3.VListItem( - prepend_icon="mdi-timer-sand-complete", - click=self.fake_busy, - title=("compact_drawer ? null : 'Trigger busy'",), - ) v3.VListItem( prepend_icon="mdi-database-refresh-outline", click=self.ctrl.on_server_reload, @@ -865,7 +859,7 @@ async def import_state(self, state_content): # Load variables self.state.variables_selected = state_content["variables-selection"] self.state.update(state_content["data-selection"]) - self.data_load_variables() + await self._data_load_variables() # Update view states for view_state in state_content["views"]: @@ -881,9 +875,6 @@ async def import_state(self, state_content): self.state.active_tools = state_content["layout"]["tools"] self.state.compact_drawer = not state_content["layout"]["help"] - def fake_busy(self): - time.sleep(3) - @controller.add_task("file_selection_load") async def data_loading_open(self, simulation, connectivity): # Reset state @@ -957,6 +948,9 @@ def data_loading_hide(self): ] def data_load_variables(self): + asynchronous.create_task(self._data_load_variables()) + + async def _data_load_variables(self): """Called at 'Load Variables' button click""" vars_to_show = self.selected_variables @@ -969,10 +963,16 @@ def data_load_variables(self): # Trigger source update + compute avg with self.state: self.state.variables_loaded = True + await self.server.network_completion # Update views in layout with self.state: self.view_manager.build_auto_layout(vars_to_show) + await self.server.network_completion + + # Reset camera after yield + await asyncio.sleep(0.1) + self.view_manager.reset_camera() @change("variables_selected") def _on_dirty_variable_selection(self, **_): From 442fc2f4b762507ecac3205885a1f0ab4e2dbaa9 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Wed, 15 Oct 2025 11:28:02 -0600 Subject: [PATCH 08/14] fix(ui): better scrolling handling --- quickview/app2.py | 1195 ++++++++++++++------------ quickview/components/file_browser.py | 9 +- quickview/view_manager2.py | 67 +- 3 files changed, 675 insertions(+), 596 deletions(-) diff --git a/quickview/app2.py b/quickview/app2.py index a3d74f6..a273e05 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -1,6 +1,7 @@ import asyncio import json -import time +import datetime +import os from pathlib import Path @@ -158,212 +159,260 @@ def _build_ui(self, **_): with VAppLayout(self.server, fill_height=True) as self.ui: with v3.VLayout(): with v3.VNavigationDrawer( - permanent=True, rail=("compact_drawer", True), width=220 + permanent=True, + rail=("compact_drawer", True), + width=220, + style="transform: none;", ): - with v3.VList( - density="compact", - nav=True, - select_strategy="independent", - v_model_selected=("active_tools", ["load-data"]), + with html.Div( + style=( + "`position:fixed;top:0;width:${compact_drawer ? '55' : '219'}px;`", + ) ): - with v3.VTooltip( - text=f"QuickView {quickview_version}", - disabled=("!compact_drawer",), + with v3.VList( + density="compact", + nav=True, + select_strategy="independent", + v_model_selected=("active_tools", ["load-data"]), ): - with v3.Template(v_slot_activator="{ props }"): - with v3.VListItem( - v_bind="props", - title=( - f"compact_drawer ? null : 'QuickView {quickview_version}'", - ), - classes="text-h6", - ): - with v3.Template(raw_attrs=["#prepend"]): - v3.VAvatar( - image=ASSETS.icon, size=24, classes="me-4" + with v3.VTooltip( + text=f"QuickView {quickview_version}", + disabled=("!compact_drawer",), + ): + with v3.Template(v_slot_activator="{ props }"): + with v3.VListItem( + v_bind="props", + title=( + f"compact_drawer ? null : 'QuickView {quickview_version}'", + ), + classes="text-h6", + ): + with v3.Template(raw_attrs=["#prepend"]): + v3.VAvatar( + image=ASSETS.icon, + size=24, + classes="me-4", + ) + v3.VProgressCircular( + color="primary", + indeterminate=True, + v_show="trame__busy", + v_if="compact_drawer", + style="position: absolute !important;left: 50%;top: 50%; transform: translate(-50%, -50%);", ) - v3.VProgressCircular( - color="primary", - indeterminate=True, - v_show="trame__busy", - v_if="compact_drawer", - style="position: absolute !important;left: 50%;top: 50%; transform: translate(-50%, -50%);", + v3.VProgressLinear( + v_else=True, + color="primary", + indeterminate=True, + v_show="trame__busy", + absolute=True, + style="top:90%;width:100%;", + ) + with v3.VTooltip( + text="File loading", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-file-document-outline", + value="load-data", + title=( + "compact_drawer ? null : 'File loading'", + ), ) - v3.VProgressLinear( - v_else=True, - color="primary", - indeterminate=True, - v_show="trame__busy", - absolute=True, - style="top:90%;width:100%;", + with v3.VTooltip( + text="Fields selection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-list-status", + value="select-fields", + disabled=("variables_listing.length === 0",), + title=( + "compact_drawer ? null : 'Fields selection'", + ), ) - with v3.VTooltip( - text="File loading", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-file-document-outline", - value="load-data", - title=("compact_drawer ? null : 'File loading'",), - ) - with v3.VTooltip( - text="Fields selection", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-list-status", - value="select-fields", - disabled=("variables_listing.length === 0",), - title=( - "compact_drawer ? null : 'Fields selection'", - ), - ) - with v3.VTooltip( - text="Reset camera", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-crop-free", - title=("compact_drawer ? null : 'Reset camera'",), - click=self.view_manager.reset_camera, - ) + with v3.VTooltip( + text="Reset camera", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-crop-free", + title=( + "compact_drawer ? null : 'Reset camera'", + ), + click=self.view_manager.reset_camera, + ) - with v3.VTooltip( - text="State Import/Export", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-folder-arrow-left-right-outline", - value="import-export", - title=( - "compact_drawer ? null : 'State Import/Export'", - ), - ) + with v3.VTooltip( + text="State Import/Export", + disabled=("!compact_drawer",), + ): + with v3.Template(v_slot_activator="{ props }"): + with v3.VListItem( + v_bind="props", + prepend_icon="mdi-folder-arrow-left-right-outline", + title=( + "compact_drawer ? null : 'State Import/Export'", + ), + ): + with v3.VMenu( + activator="parent", + location="end", + offset=10, + ): + with v3.VList(density="compact"): + v3.VListItem( + title="Download state file", + prepend_icon="mdi-file-download-outline", + click="show_export_dialog=true", + ) + v3.VListItem( + title="Upload state file", + prepend_icon="mdi-file-upload-outline", + click="utils.get('document').querySelector('#fileUpload').click()", + ) + + v3.VFileInput( + id="fileUpload", + v_show=False, + v_model=("upload_state_file", None), + density="compact", + prepend_icon=False, + style="position: absolute;left:-1000px;width:1px;", + ) - with v3.VTooltip( - text="Toggle Help", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-lifebuoy", - click="compact_drawer = !compact_drawer", - title=("compact_drawer ? null : 'Toggle Help'",), - ) + with v3.VTooltip( + text="Toggle Help", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-lifebuoy", + click="compact_drawer = !compact_drawer", + title=( + "compact_drawer ? null : 'Toggle Help'", + ), + ) - v3.VDivider(classes="my-1") + v3.VDivider(classes="my-1") - with v3.VTooltip( - text="Map Projection", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - with v3.VListItem( - v_bind="props", - prepend_icon="mdi-earth", - title=("compact_drawer ? null : 'Map Projection'",), - ): - with v3.VMenu( - activator="parent", location="end", offset=10 + with v3.VTooltip( + text="Map Projection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + with v3.VListItem( + v_bind="props", + prepend_icon="mdi-earth", + title=( + "compact_drawer ? null : 'Map Projection'", + ), ): - v3.VList( - mandatory=True, - v_model_selected=( - "projection", - ["Cyl. Equidistant"], - ), - density="compact", - items=( - "projections", - [ - { - "title": "Cylindrical Equidistant", - "value": "Cyl. Equidistant", - }, - { - "title": "Robinson", - "value": "Robinson", - }, - { - "title": "Mollweide", - "value": "Mollweide", - }, - ], - ), - ) + with v3.VMenu( + activator="parent", + location="end", + offset=10, + ): + v3.VList( + mandatory=True, + v_model_selected=( + "projection", + ["Cyl. Equidistant"], + ), + density="compact", + items=( + "projections", + [ + { + "title": "Cylindrical Equidistant", + "value": "Cyl. Equidistant", + }, + { + "title": "Robinson", + "value": "Robinson", + }, + { + "title": "Mollweide", + "value": "Mollweide", + }, + ], + ), + ) - with v3.VTooltip( - text="Layout management", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-collage", - value="adjust-layout", - title=( - "compact_drawer ? null : 'Layout management'", - ), - ) + with v3.VTooltip( + text="Layout management", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-collage", + value="adjust-layout", + title=( + "compact_drawer ? null : 'Layout management'", + ), + ) - v3.VDivider(classes="my-1") + v3.VDivider(classes="my-1") - with v3.VTooltip( - text="Lat/Long cropping", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-crop", - value="adjust-databounds", - title=( - "compact_drawer ? null : 'Lat/Long cropping'", - ), - ) + with v3.VTooltip( + text="Lat/Long cropping", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-crop", + value="adjust-databounds", + title=( + "compact_drawer ? null : 'Lat/Long cropping'", + ), + ) - with v3.VTooltip( - text="Slice selection", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): - v3.VListItem( - v_bind="props", - prepend_icon="mdi-tune-variant", - value="select-slice-time", - title=( - "compact_drawer ? null : 'Slice selection'", - ), - ) + with v3.VTooltip( + text="Slice selection", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-tune-variant", + value="select-slice-time", + title=( + "compact_drawer ? null : 'Slice selection'", + ), + ) - with v3.VTooltip( - text="Animation controls", disabled=("!compact_drawer",) - ): - with v3.Template(v_slot_activator="{ props }"): + with v3.VTooltip( + text="Animation controls", disabled=("!compact_drawer",) + ): + with v3.Template(v_slot_activator="{ props }"): + v3.VListItem( + v_bind="props", + prepend_icon="mdi-movie-open-cog-outline", + value="animation-controls", + title=( + "compact_drawer ? null : 'Animation controls'", + ), + ) + + if self.server.hot_reload: v3.VListItem( - v_bind="props", - prepend_icon="mdi-movie-open-cog-outline", - value="animation-controls", - title=( - "compact_drawer ? null : 'Animation controls'", - ), + prepend_icon="mdi-database-refresh-outline", + click=self.ctrl.on_server_reload, + title=("compact_drawer ? null : 'Refresh UI'",), ) - if self.server.hot_reload: - v3.VListItem( - prepend_icon="mdi-database-refresh-outline", - click=self.ctrl.on_server_reload, - title=("compact_drawer ? null : 'Refresh UI'",), + with html.Div( + style=( + "`position:fixed;bottom:0;width:${compact_drawer ? '55' : '219'}px;`", + ) + ): + v3.VDivider() + v3.VLabel( + f"{quickview_version}", + classes="text-center text-caption d-block text-wrap", ) - - # Show version at the bottom - with v3.Template(raw_attrs=["#append"]): - v3.VDivider() - v3.VLabel( - f"{quickview_version}", - classes="text-center text-caption d-block text-wrap", - ) with v3.VMain(): # load-data @@ -378,390 +427,450 @@ def _build_ui(self, **_): ): self.file_browser.ui() + # download state + with html.Div( + style="position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:1000;" + ): + with v3.VDialog( + model_value=("show_export_dialog", False), + contained=True, + max_width="80vw", + persistent=True, + ): + with v3.VCard( + title="Download QuickView State file", rounded="lg" + ): + v3.VDivider() + with v3.VCardText(): + with v3.VRow(dense=True): + with v3.VCol(cols=12): + html.Label( + "Filename", + classes="text-subtitle-1 font-weight-medium mb-2 d-block", + ) + v3.VTextField( + v_model=( + "download_name", + "quickview-state.json", + ), + density="comfortable", + placeholder="Enter the filename to download", + variant="outlined", + ) + with v3.VRow(dense=True): + with v3.VCol(cols=12): + html.Label( + "Comments", + classes="text-subtitle-1 font-weight-medium mb-2 d-block", + ) + v3.VTextarea( + v_model=("export_comment", ""), + density="comfortable", + placeholder="Remind yourself what that state captures", + rows="4", + variant="outlined", + ) + with v3.VCardActions(): + v3.VSpacer() + v3.VBtn( + text="Cancel", + click="show_export_dialog=false", + classes="text-none", + variant="flat", + color="surface", + ) + v3.VBtn( + text="Download", + classes="text-none", + variant="flat", + color="primary", + click="show_export_dialog=false;utils.download(download_name, trigger('download_state'), 'application/json')", + ) + # Field selection container with v3.VNavigationDrawer( model_value=("active_tools.includes('select-fields')",), width=500, permanent=True, + style=( + "active_tools.includes('select-fields') ? 'transform: none;' : ''", + ), ): - with v3.VCardActions(key="variables_selected.length"): - for name, color in [ - ("surfaces", "success"), - ("interfaces", "info"), - ("midpoints", "warning"), - ]: - v3.VChip( - js_var_title(name), - color=color, - v_show=js_var_count(name), - size="small", - closable=True, - click_close=js_var_remove(name), - ) - - v3.VSpacer() - v3.VBtn( - classes="text-none", - color="primary", - prepend_icon="mdi-database", - text=( - "`Load ${variables_selected.length} variable${variables_selected.length > 1 ? 's' :''}`", - ), - variant="flat", - disabled=( - "variables_selected.length === 0 || variables_loaded", - ), - click=self.data_load_variables, - ) - - v3.VTextField( - v_model=("variables_filter", ""), - hide_details=True, - color="primary", - placeholder="Filter", - density="compact", - variant="outlined", - classes="mx-2", - prepend_inner_icon="mdi-magnify", - clearable=True, - ) - v3.VDataTable( - v_model=("variables_selected", []), - show_select=True, - item_value="id", - density="compact", - fixed_header=True, - headers=("variables_headers", VAR_HEADERS), - items=("variables_listing", []), - height=( - "`calc(max(100vh, ${Math.floor(main_size?.size?.height || 0)}px) - 6rem)`", - ), - style="user-select: none; cursor: pointer;", - hover=True, - search=("variables_filter", ""), - items_per_page=-1, - hide_default_footer=True, - ) + with html.Div(style="position:fixed;top:0;width: 500px;"): + with v3.VCardActions(key="variables_selected.length"): + for name, color in [ + ("surfaces", "success"), + ("interfaces", "info"), + ("midpoints", "warning"), + ]: + v3.VChip( + js_var_title(name), + color=color, + v_show=js_var_count(name), + size="small", + closable=True, + click_close=js_var_remove(name), + ) - with v3.VContainer(classes="h-100 pa-0", fluid=True): - with client.SizeObserver("main_size"): - # Import/Export toolbar - with v3.VToolbar( - v_show="active_tools.includes('import-export')", - color="white", - classes="border-b-thin", - ): - v3.VIcon( - "mdi-folder-arrow-left-right-outline", - classes="px-6 opacity-50", - ) - v3.VLabel( - "Import/Export Controls", classes="text-subtitle-2" - ) v3.VSpacer() - - v3.VTextField( - v_model=("download_name", "quickview-state.json"), - hide_details=True, - density="compact", - label="Download state file", - prepend_inner_icon="mdi-file-download-outline", - variant="outlined", - flat=True, - style="max-width: 250px", - classes="mx-2", - click_prependInner="utils.download(download_name, trigger('download_state'), 'application/json')", + v3.VBtn( + classes="text-none", + color="primary", + prepend_icon="mdi-database", + text=( + "`Load ${variables_selected.length} variable${variables_selected.length > 1 ? 's' :''}`", + ), + variant="flat", + disabled=( + "variables_selected.length === 0 || variables_loaded", + ), + click=self.data_load_variables, ) - v3.VFileInput( - v_model=("upload_state_file", None), - hide_details=True, - chips=True, + v3.VTextField( + v_model=("variables_filter", ""), + hide_details=True, + color="primary", + placeholder="Filter", + density="compact", + variant="outlined", + classes="mx-2", + prepend_inner_icon="mdi-magnify", + clearable=True, + ) + with html.Div(style="margin:1px;"): + v3.VDataTable( + v_model=("variables_selected", []), + show_select=True, + item_value="id", density="compact", - label="Import state file", - prepend_icon=False, - prepend_inner_icon="mdi-file-upload-outline", - variant="outlined", - style="max-width: 250px", - classes="mx-2", + fixed_header=True, + headers=("variables_headers", VAR_HEADERS), + items=("variables_listing", []), + height="calc(100vh - 6rem)", + style="user-select: none; cursor: pointer;", + hover=True, + search=("variables_filter", ""), + items_per_page=-1, + hide_default_footer=True, ) - # Layout control toolbar - with v3.VToolbar( + with v3.VContainer(classes="h-100 pa-0", fluid=True): + with client.SizeObserver("main_size"): + # Take space to push content below the fixed overlay + v3.VToolbar( v_show="active_tools.includes('adjust-layout')", - color="white", - classes="border-b-thin", density="compact", - ): - v3.VIcon("mdi-collage", classes="px-6 opacity-50") - v3.VLabel("Layout Controls", classes="text-subtitle-2") - v3.VSpacer() + ) + v3.VToolbar( + v_show="active_tools.includes('adjust-databounds')" + ) + v3.VToolbar( + v_show="active_tools.includes('select-slice-time')" + ) + v3.VToolbar( + v_show="active_tools.includes('animation-controls')", + density="compact", + ) - v3.VSlider( - v_model=("aspect_ratio", 2), - prepend_icon="mdi-aspect-ratio", - min=1, - max=2, - step=0.1, - density="compact", - hide_details=True, - style="max-width: 400px;", - ) - v3.VSpacer() - v3.VCheckbox( - v_model=("layout_grouped", True), - label=("layout_grouped ? 'Grouped' : 'Uniform'",), - hide_details=True, - inset=True, - false_icon="mdi-apps", - true_icon="mdi-focus-field", + # Fixed overlay for toolbars + with html.Div( + style=( + "`position:fixed;top:0;width:calc(100vw - ${compact_drawer ? '55' : '219'}px);z-index:1;`", + ), + ): + # Layout control toolbar + with v3.VToolbar( + v_show="active_tools.includes('adjust-layout')", + color="white", + classes="border-b-thin", density="compact", - ) + ): + v3.VIcon("mdi-collage", classes="px-6 opacity-50") + v3.VLabel( + "Layout Controls", classes="text-subtitle-2" + ) + v3.VSpacer() - with v3.VBtn( - "Size", - classes="text-none mx-4", - prepend_icon="mdi-view-module", - append_icon="mdi-menu-down", + v3.VSlider( + v_model=("aspect_ratio", 2), + prepend_icon="mdi-aspect-ratio", + min=1, + max=2, + step=0.1, + density="compact", + hide_details=True, + style="max-width: 400px;", + ) + v3.VSpacer() + v3.VCheckbox( + v_model=("layout_grouped", True), + label=( + "layout_grouped ? 'Grouped' : 'Uniform'", + ), + hide_details=True, + inset=True, + false_icon="mdi-apps", + true_icon="mdi-focus-field", + density="compact", + ) + + with v3.VBtn( + "Size", + classes="text-none mx-4", + prepend_icon="mdi-view-module", + append_icon="mdi-menu-down", + ): + with v3.VMenu(activator="parent"): + with v3.VList(density="compact"): + v3.VListItem( + title="Auto", + click=( + self.view_manager.apply_size, + "[0]", + ), + ) + v3.VListItem( + title="Full Width", + click=( + self.view_manager.apply_size, + "[1]", + ), + ) + v3.VListItem( + title="2 Columns", + click=( + self.view_manager.apply_size, + "[2]", + ), + ) + v3.VListItem( + title="3 Columns", + click=( + self.view_manager.apply_size, + "[3]", + ), + ) + v3.VListItem( + title="4 Columns", + click=( + self.view_manager.apply_size, + "[4]", + ), + ) + v3.VListItem( + title="6 Columns", + click=( + self.view_manager.apply_size, + "[6]", + ), + ) + + # Crop selection + with v3.VToolbar( + v_show="active_tools.includes('adjust-databounds')", + color="white", + classes="border-b-thin", ): - with v3.VMenu(activator="parent"): - with v3.VList(density="compact"): - v3.VListItem( - title="Auto", - click=( - self.view_manager.apply_size, - "[0]", - ), + v3.VIcon("mdi-crop", classes="pl-6 opacity-50") + with v3.VRow(classes="ma-0 px-2 align-center"): + with v3.VCol(cols=6): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Longitude", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ crop_longitude }}", + classes="text-body-2", + ) + v3.VRangeSlider( + v_model=("crop_longitude", [-180, 180]), + min=-180, + max=180, + step=1, + density="compact", + hide_details=True, ) - v3.VListItem( - title="Full Width", - click=( - self.view_manager.apply_size, - "[1]", - ), + with v3.VCol(cols=6): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Latitude", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ crop_latitude }}", + classes="text-body-2", + ) + v3.VRangeSlider( + v_model=("crop_latitude", [-90, 90]), + min=-90, + max=90, + step=1, + density="compact", + hide_details=True, ) - v3.VListItem( - title="2 Columns", - click=( - self.view_manager.apply_size, - "[2]", - ), - ) - v3.VListItem( - title="3 Columns", - click=( - self.view_manager.apply_size, - "[3]", + + # Layer/Time selection + with v3.VToolbar( + v_show="active_tools.includes('select-slice-time')", + color="white", + classes="border-b-thin", + ): + v3.VIcon( + "mdi-tune-variant", classes="ml-3 opacity-50" + ) + with v3.VRow( + classes="ma-0 pr-2 align-center", dense=True + ): + # midpoint layer + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="midpoints.length > 1", + ): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Layer Midpoints", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ parseFloat(midpoints[midpoint_idx] || 0).toFixed(2) }} hPa (k={{ midpoint_idx }})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("midpoint_idx", 0), + min=0, + max=( + "Math.max(0, midpoints.length - 1)", ), + step=1, + density="compact", + hide_details=True, ) - v3.VListItem( - title="4 Columns", - click=( - self.view_manager.apply_size, - "[4]", + + # interface layer + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="interfaces.length > 1", + ): + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Layer Interfaces", + classes="text-subtitle-2", + ) + v3.VSpacer() + v3.VLabel( + "{{ parseFloat(interfaces[interface_idx] || 0).toFixed(2) }} hPa (k={{interface_idx}})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("interface_idx", 0), + min=0, + max=( + "Math.max(0, interfaces.length - 1)", ), + step=1, + density="compact", + hide_details=True, ) - v3.VListItem( - title="6 Columns", - click=( - self.view_manager.apply_size, - "[6]", + + # time + with v3.VCol( + cols=("toolbar_slider_cols", 4), + v_show="timestamps.length > 1", + ): + self.state.setdefault("time_value", 80.50) + with v3.VRow(classes="mx-2 my-0"): + v3.VLabel( + "Time", classes="text-subtitle-2" + ) + v3.VSpacer() + v3.VLabel( + "{{ parseFloat(timestamps[time_idx]).toFixed(2) }} (t={{time_idx}})", + classes="text-body-2", + ) + v3.VSlider( + v_model=("time_idx", 0), + min=0, + max=( + "Math.max(0, timestamps.length - 1)", ), + step=1, + density="compact", + hide_details=True, ) - # Crop selection - with v3.VToolbar( - v_show="active_tools.includes('adjust-databounds')", - color="white", - classes="border-b-thin", - ): - v3.VIcon("mdi-crop", classes="pl-6 opacity-50") - with v3.VRow(classes="ma-0 px-2 align-center"): - with v3.VCol(cols=6): - with v3.VRow(classes="mx-2 my-0"): - v3.VLabel( - "Longitude", classes="text-subtitle-2" - ) - v3.VSpacer() - v3.VLabel( - "{{ crop_longitude }}", - classes="text-body-2", - ) - v3.VRangeSlider( - v_model=("crop_longitude", [-180, 180]), - min=-180, - max=180, - step=1, - density="compact", + # Animation + with v3.VToolbar( + v_show="active_tools.includes('animation-controls')", + color="white", + classes="border-b-thin", + density="compact", + ): + v3.VIcon( + "mdi-movie-open-cog-outline", + classes="px-6 opacity-50", + ) + with v3.VRow(classes="ma-0 px-2 align-center"): + v3.VSelect( + v_model=("animation_track", "timestamps"), + items=("animation_tracks", []), + flat=True, + variant="plain", hide_details=True, - ) - with v3.VCol(cols=6): - with v3.VRow(classes="mx-2 my-0"): - v3.VLabel( - "Latitude", classes="text-subtitle-2" - ) - v3.VSpacer() - v3.VLabel( - "{{ crop_latitude }}", - classes="text-body-2", - ) - v3.VRangeSlider( - v_model=("crop_latitude", [-90, 90]), - min=-90, - max=90, - step=1, density="compact", - hide_details=True, + style="max-width: 10rem;", ) - - # Layer/Time selection - with v3.VToolbar( - v_show="active_tools.includes('select-slice-time')", - color="white", - classes="border-b-thin", - ): - v3.VIcon("mdi-tune-variant", classes="ml-3 opacity-50") - with v3.VRow( - classes="ma-0 pr-2 align-center", dense=True - ): - # midpoint layer - with v3.VCol( - cols=("toolbar_slider_cols", 4), - v_show="midpoints.length > 1", - ): - with v3.VRow(classes="mx-2 my-0"): - v3.VLabel( - "Layer Midpoints", - classes="text-subtitle-2", - ) - v3.VSpacer() - v3.VLabel( - "{{ parseFloat(midpoints[midpoint_idx] || 0).toFixed(2) }} hPa (k={{ midpoint_idx }})", - classes="text-body-2", - ) + v3.VDivider(vertical=True, classes="mx-2") v3.VSlider( - v_model=("midpoint_idx", 0), + v_model=("animation_step", 1), min=0, - max=("Math.max(0, midpoints.length - 1)",), + max=("amimation_step_max", 0), step=1, - density="compact", hide_details=True, - ) - - # interface layer - with v3.VCol( - cols=("toolbar_slider_cols", 4), - v_show="interfaces.length > 1", - ): - with v3.VRow(classes="mx-2 my-0"): - v3.VLabel( - "Layer Interfaces", - classes="text-subtitle-2", - ) - v3.VSpacer() - v3.VLabel( - "{{ parseFloat(interfaces[interface_idx] || 0).toFixed(2) }} hPa (k={{interface_idx}})", - classes="text-body-2", - ) - v3.VSlider( - v_model=("interface_idx", 0), - min=0, - max=("Math.max(0, interfaces.length - 1)",), - step=1, density="compact", - hide_details=True, + classes="mx-4", ) - - # time - with v3.VCol( - cols=("toolbar_slider_cols", 4), - v_show="timestamps.length > 1", - ): - self.state.setdefault("time_value", 80.50) - with v3.VRow(classes="mx-2 my-0"): - v3.VLabel("Time", classes="text-subtitle-2") - v3.VSpacer() - v3.VLabel( - "{{ parseFloat(timestamps[time_idx]).toFixed(2) }} (t={{time_idx}})", - classes="text-body-2", - ) - v3.VSlider( - v_model=("time_idx", 0), - min=0, - max=("Math.max(0, timestamps.length - 1)",), - step=1, - density="compact", - hide_details=True, + v3.VDivider(vertical=True, classes="mx-2") + v3.VIconBtn( + icon="mdi-page-first", + flat=True, + disabled=("animation_step === 0",), + click="animation_step = 0", + ) + v3.VIconBtn( + icon="mdi-chevron-left", + flat=True, + disabled=("animation_step === 0",), + click="animation_step = Math.max(0, animation_step - 1)", + ) + v3.VIconBtn( + icon="mdi-chevron-right", + flat=True, + disabled=( + "animation_step === amimation_step_max", + ), + click="animation_step = Math.min(amimation_step_max, animation_step + 1)", + ) + v3.VIconBtn( + icon="mdi-page-last", + disabled=( + "animation_step === amimation_step_max", + ), + flat=True, + click="animation_step = amimation_step_max", + ) + v3.VDivider(vertical=True, classes="mx-2") + v3.VIconBtn( + icon=( + "animation_play ? 'mdi-stop' : 'mdi-play'", + ), + flat=True, + click="animation_play = !animation_play", ) - - # Animation - with v3.VToolbar( - v_show="active_tools.includes('animation-controls')", - color="white", - classes="border-b-thin", - density="compact", - ): - v3.VIcon( - "mdi-movie-open-cog-outline", - classes="px-6 opacity-50", - ) - with v3.VRow(classes="ma-0 px-2 align-center"): - v3.VSelect( - v_model=("animation_track", "timestamps"), - items=("animation_tracks", []), - flat=True, - variant="plain", - hide_details=True, - density="compact", - style="max-width: 10rem;", - ) - v3.VDivider(vertical=True, classes="mx-2") - v3.VSlider( - v_model=("animation_step", 1), - min=0, - max=("amimation_step_max", 0), - step=1, - hide_details=True, - density="compact", - classes="mx-4", - ) - v3.VDivider(vertical=True, classes="mx-2") - v3.VIconBtn( - icon="mdi-page-first", - flat=True, - disabled=("animation_step === 0",), - click="animation_step = 0", - ) - v3.VIconBtn( - icon="mdi-chevron-left", - flat=True, - disabled=("animation_step === 0",), - click="animation_step = Math.max(0, animation_step - 1)", - ) - v3.VIconBtn( - icon="mdi-chevron-right", - flat=True, - disabled=( - "animation_step === amimation_step_max", - ), - click="animation_step = Math.min(amimation_step_max, animation_step + 1)", - ) - v3.VIconBtn( - icon="mdi-page-last", - disabled=( - "animation_step === amimation_step_max", - ), - flat=True, - click="animation_step = amimation_step_max", - ) - v3.VDivider(vertical=True, classes="mx-2") - v3.VIconBtn( - icon=( - "animation_play ? 'mdi-stop' : 'mdi-play'", - ), - flat=True, - click="animation_play = !animation_play", - ) client.ServerTemplate(name=("active_layout", "auto_layout")) @@ -792,9 +901,16 @@ def selected_variable_names(self): def download_state(self): active_variables = self.selected_variables state_content = {} + state_content["origin"] = { + "user": os.environ.get("USER", os.environ.get("USERNAME")), + "created": f"{datetime.datetime.now()}", + "comment": self.state.export_comment, + } state_content["files"] = { - "simulation": self.file_browser.get("data_simulation"), - "connectivity": self.file_browser.get("data_connectivity"), + "simulation": str(Path(self.file_browser.get("data_simulation")).resolve()), + "connectivity": str( + Path(self.file_browser.get("data_connectivity")).resolve() + ), } state_content["variables-selection"] = self.state.variables_selected state_content["layout"] = { @@ -844,10 +960,13 @@ def _on_import_state(self, upload_state_file, **_): file_proxy = file_upload.ClientFile(upload_state_file) state_content = json.loads(file_proxy.content) - asynchronous.create_task(self.import_state(state_content)) + self.import_state(state_content) @controller.set("import_state") - async def import_state(self, state_content): + def import_state(self, state_content): + asynchronous.create_task(self._import_state(state_content)) + + async def _import_state(self, state_content): # Files self.file_browser.set_data_simulation(state_content["files"]["simulation"]) self.file_browser.set_data_connectivity(state_content["files"]["connectivity"]) @@ -875,6 +994,10 @@ async def import_state(self, state_content): self.state.active_tools = state_content["layout"]["tools"] self.state.compact_drawer = not state_content["layout"]["help"] + # Update filebrowser state + with self.state: + self.file_browser.set("state_loading", False) + @controller.add_task("file_selection_load") async def data_loading_open(self, simulation, connectivity): # Reset state diff --git a/quickview/components/file_browser.py b/quickview/components/file_browser.py index 5fdacd4..11a885f 100644 --- a/quickview/components/file_browser.py +++ b/quickview/components/file_browser.py @@ -269,14 +269,7 @@ def import_state_file(self): self.set("state_loading", True) state_content = json.loads(Path(self.active_path).read_text()) - coroutine = self.ctrl.import_state(state_content) - task = asynchronous.create_task(coroutine) - - def done_loading(): - with self.state: - self.set("state_loading", False) - - task.add_done_callback(done_loading) + self.ctrl.import_state(state_content) def cancel(self): self.ctrl.file_selection_cancel() diff --git a/quickview/view_manager2.py b/quickview/view_manager2.py index 3116289..c75a14b 100644 --- a/quickview/view_manager2.py +++ b/quickview/view_manager2.py @@ -240,10 +240,10 @@ def _build_ui(self): click="active_layout = 'auto_layout';config.size = 2", ) with html.Div( - classes="text-subtitle-2 pr-2", style="user-select: none;" - ) as el: - # v3.VIcon("mdi-menu-down", size="x-small") - el.add_child(self.variable_name) + self.variable_name, + classes="text-subtitle-2 pr-2", + style="user-select: none;", + ): with v3.VMenu(activator="parent"): with v3.VList(density="compact", style="max-height: 40vh;"): with self.config.provide_as("config"): @@ -257,47 +257,6 @@ def _build_ui(self): ), ) - # with v3.VListGroup(value="size"): - # with v3.Template(v_slot_activator="{ props }"): - # v3.VListItem( - # title="Size controls", v_bind="props" - # ) - - # v3.VListItem( - # "Auto size", click="config.size = 0" - # ) - # v3.VListItem( - # "Full width", click="config.size = 12" - # ) - # v3.VListItem( - # "Half width", click="config.size = 6" - # ) - # v3.VListItem( - # "1/3 width", click="config.size = 4" - # ) - # v3.VListItem( - # "1/4 width", click="config.size = 3" - # ) - # v3.VListItem( - # "1/6 width", click="config.size = 2" - # ) - # v3.VDivider() - - # v3.VDivider() - - # with v3.VListItem("Order {{ config.order }}"): - # v3.VSpacer() - # v3.VIconBtn( - # icon="mdi-plus", - # size="small", - # click="config.order++", - # ) - # v3.VIconBtn( - # icon="mdi-minus", - # size="small", - # click="config.order--", - # ) - v3.VSpacer() html.Div( "t = {{ time_idx }}", @@ -326,10 +285,12 @@ def _build_ui(self): with html.Div( style=( - """{ - aspectRatio: active_layout === 'auto_layout' ? aspect_ratio : null, - height: active_layout !== 'auto_layout' ? 'calc(100% - 2.4rem)' : null, - }""", + """ + { + aspectRatio: active_layout === 'auto_layout' ? aspect_ratio : null, + height: active_layout !== 'auto_layout' ? 'calc(100% - 2.4rem)' : null, + } + """, ), ): pvw.VtkRemoteView( @@ -344,10 +305,12 @@ def _build_ui(self): with v3.VMenu( v_model="config.menu", activator="parent", - location="end", + location=( + "active_layout !== 'auto_layout' || config.size == 12 ? 'top' : 'end'", + ), close_on_content_click=False, ): - with v3.VCard(): + with v3.VCard(style="max-width: 360px;"): with v3.VCardItem(classes="pb-0"): v3.VIconBtn( icon=( @@ -437,7 +400,7 @@ def _build_ui(self): ): html.Img( src=("url",), - style="width:20rem;height:1rem;", + style="width:100%;min-width:20rem;height:1rem;", classes="rounded", ) html.Div( From c8b99649e7d479bebbdc7b57b2a8a155c121ac20 Mon Sep 17 00:00:00 2001 From: Sebastien Jourdain Date: Wed, 15 Oct 2025 12:41:31 -0600 Subject: [PATCH 09/14] docs(landing): add landing page --- quickview/app2.py | 7 +- quickview/assets/__init__.py | 1 + quickview/assets/banner.jpg | Bin 0 -> 660952 bytes quickview/components/doc.py | 299 +++++++++++++++++++++++++++++++++++ 4 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 quickview/assets/banner.jpg create mode 100644 quickview/components/doc.py diff --git a/quickview/app2.py b/quickview/app2.py index a273e05..a477475 100644 --- a/quickview/app2.py +++ b/quickview/app2.py @@ -15,6 +15,7 @@ from quickview.assets import ASSETS from quickview.view_manager2 import ViewManager from quickview.components.file_browser import ParaViewFileBrowser +from quickview.components.doc import LandingPage from quickview.utils import compute from quickview import module as qv_module @@ -576,7 +577,7 @@ def _build_ui(self, **_): # Fixed overlay for toolbars with html.Div( style=( - "`position:fixed;top:0;width:calc(100vw - ${compact_drawer ? '55' : '219'}px);z-index:1;`", + "`position:fixed;top:0;width:${Math.floor(main_size?.size?.width || 0)}px;z-index:1;`", ), ): # Layout control toolbar @@ -872,8 +873,12 @@ def _build_ui(self, **_): click="animation_play = !animation_play", ) + # View of all the variables client.ServerTemplate(name=("active_layout", "auto_layout")) + with html.Div(v_if="!variables_selected.length"): + LandingPage() + # ------------------------------------------------------------------------- # Derived properties # ------------------------------------------------------------------------- diff --git a/quickview/assets/__init__.py b/quickview/assets/__init__.py index b336786..6a48d5b 100644 --- a/quickview/assets/__init__.py +++ b/quickview/assets/__init__.py @@ -2,3 +2,4 @@ ASSETS = LocalFileManager(__file__) ASSETS.url("icon", "small-icon.png") +ASSETS.url("banner", "banner.jpg") diff --git a/quickview/assets/banner.jpg b/quickview/assets/banner.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7ca3a16d082d1a716ea6be82294c7f853c8e31fc GIT binary patch literal 660952 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

h<=c4?NY)C=f2re~91`p$pI zcKcp0f#>Z^dltT(JGK{9EK8uLDiMxYu5ndUM! zP3xI%ue63vBEUO2;(v&5meVQL6vc2gDRAS@YAgs3nvf?EQBE2Nu#$b>2{rSR;(j6u zlBn3S7B&@a%uz<*^KhPI5djRJw(x;Q& z3ig&N%E4hYMn@Jzt5!W9uFj36iGU04oK}|p(L?^CW-wA`HA4f zxx$k;B=McW@$E`xz<8aT=C01ZIyDrodslwE@td2au-L!gRKF%yUyU05U7f|+OA1tA z{F6)Edzxa0yVNcHxy+vPZ@fwi!;x#4d`aVmXB!0uqWah(6RuL!^AP}G*wwjX3okRg zzIU?`@452|)+ z*s%v`_H4y@wRyH6caHvN_IHcuGfo+bRit26*ua&mwaq3L)v4I@yRmvxe!r;pD~evT^!-)Gs&z7* zw(6a$)@+*Xr4?<|MxHNLWhtuGi+HVF>^oFS4(j^Hr9C#?=?DCErHcWhqN}>#yW_J| zElV|339SJ@Y?k|CfARH)TEFO@Qqz5a-g;rptzFfLP(xtkVn!nuT#c0VRFuWM0+z(P z70Bzgck;WS7@d(2xoskKJH$*&mw?FZqvWi7S4zZ{nwdYcEb)uL*@oyunZGW5$0OM7#TLZdSXEibC0oP=wgE*!7=kR25+{t3RPM zykg!_`p3q0p3@_Y{tlyBOy~>R)cR(rb9YUmc-qrYwJZMsr>L#_EiC1n80fctBx*EN z>(}qhC(9DK?6Yy{s^7FsGy%650TX2UkePAk%K^an{EX?)fA#?<0DlBF;A&ZpCKqHX zR@cxqOed_g2n$SL$m8UCjts^S^F0R!h#|fyS++Zz&uo>1xDS99ft8XFh3s*bN?bSi66Wl;oY>xMKXbUS@sB*reR6C7!!EIo zve@HZxfSbuB}3Fy+2}1Y34V|Cs}XzB-ke>JBkLBibT(@BK8o2XC04oZc1Wbj+I!Y| zXVT2vXY5{;qRXD#a?hUCk4Y=FrFGRN-`6^)skd~W z>WRGjw4LJ_S$^X&&6WMIq9Q1e+GTJssc^G%@Iz_}y}2S9TUb<8-mY+(rwi)?fygS? zb$^!4qvjD^vo>{ua0)GJ$u>TgOo~GoF_q8?1(@?>ezAxAIpx~C9szL#9$BoR2(#{C z!?^Ja_Wtbu0CD!=+RccoFY_C{x@y`NMg2#L{1Utd*bL%3cpzV{5fQn36vS;;%FRyA zjTnq`dm)gx3Zij@-?9}YH!aIqQGM64sP#XoG#Sdw<@)(W-$h-*(~*gFP-0@eT1y4tjJZF{_lb({45F z{XJKOP+!KO{%W76{DW(yS;qeWb$RkxzFg*wkGG*j5W1r4we;Io!@Xa!2HP%dyXvLb zd}RJc4{=>!haKYiU2m<5qsLKBE{(mDZ#KTEwk{o()lq`z9bhmoAjI(mzj%txuSl!3 zd~9H@A>k0m^_9LR4d61CcM+e0&*vnH2}}nL%d9F$LMGWdx0ueve;W@eAuSg+lQ`nwX!|&gitIBzsys}uST>q(D^-1nO6mS$TKeVNGvxHmS$*pV z;~TBwFLL}k?5|RU7z(S@bls~Jb60D=bHwkH#A#!J_hL>-!~$%pa>l(jm1?O|HkJ(I znbhuD>6Fe(8hnrY=eB!MoFTW$Qv4C)Eo?sVV$EY+x))&mJKitD2HjB+MF$OsUtemP zwohH0nI=}z%N}*PjNy*|04A}Jc=AV_MybVi+OFD`0>a;0+gpJ#b(?|#*vme_J-Xz+zJB0(*6(*aI<++`^uMZf8~XI>-}KhH^}F7_y=QCb@u^t# z)H|Sji}w%?hm$)*{Nvl<2DMU~Ha)p6e-xL)CyZ~%A6~BVD#q+AvC@3qg|<1!vZk3i$tyN{<;$k$I?C#tg zD_LE)CA!+YTh{enw$Fu|Dss!TXr`r8*w%JcKbw=?_ir(-U0cyBU*5i>Yjt1v#^RCq z0?Nl-?Mq^h+yOn~3Ba25o6*($UTWt0)h;lYt@`{Z^(7xoYP~v>5doOaa8H=QJT`MD zE#-fZSOUCVuRS=fOv`q>Be14-RKB>IcWDY*VqTN4;i>8xbVA;~3`LR>2K0A{{aU$b z-l}JkenpEp1~4NT`I6I-f}+!Y(4wpSKH|B-1|+@yw^(v7h9qB+n@c|PXEDxLj=8S- zqoUnrHQKdn7aeAgb9brl%j{VEg%RUV#}##+`GZ*q3xV*m=`_BH^8QxG!s~enoJLy@ zB9xE4RY3&$Yzs+8U>B8g9y)0G8RM`rT9D{*zfHoZMu>su>v4uW3k zLEe2pt!pjqO}7C7SltcS<-KRPUaqaS1$w+~HV`YDuK3urfs2B%T97V`WJ+vDz!GiW%e? zoQoqEw~XMooKkts%>2@hqgK$ac9LkfBsO&^dq*olwEa>aGj)oXmSv@kn*N+j!403jQ$B|4{eZHOaQy{ilky+2Zkf!J5#P~l<<-{A`Z z3?MSaIsqP}cQ%!Ny%cSFSr~W-Yg!dM1)=XHB zn+9IjUu>kws_T}%AVymw162#Ll8e?+r6tRyUZM8h$r>=gBxxV68ZBAqKkau=7n|pj~!R+){-(N9$G)gQO9oz!YSva zy)}1eX^mA9i#oRD&rRv}E8co(luy{3EGPv+Ve=*R=jnVq;;YzsEefisEP{xWZ+wof zT4(wn8=hlG(kAwUIiF!HE-rk9VUmv+_K)&{p-`ZcHqSW)o_Wi2_{L|w0pVs{nKyND z=^K8J^xb0D2d4csS$mC3cQ-b>Aa6~#sxH2_r2Ra-!wzRu$0bR#Ej#xgO}f|1V`LP56{=$+VM5hf+DG}5 zU?Qt(JNkRqo~sgabyj>~moa+xYX@81s=b>O*q7G0v#;#s7gKd3uZptD?YBRJR-KmB z&t{!uIbW~0KkbvmKdxJ6bUD8-{FW>iT%)PEvpwy5o}b)$XVetw2cR|+Z*S#N!gc5? zT5gr@`r}%SKJWR$jEVg`z9^|+-IHVNRx-z!va5;d4PYDHtLJ0T6&EY}glN^_t;%bs zVPP)HvLaS5Gs?L9f)J?vVO_>zCLX3G&~gXZx%XfgQ$E`41%|&{%Rgo(tJB*rWo_yU zBk7pA0k7@tum`hjj{?d1>tmVF)GZQ$Y^J+n}r$8Y;}%0Dg1 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

o}q3yQpoN>sqVQct>p^y<1t;B-V(u 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