e3sm-siteview 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. e3sm_siteview-1.0.0/.gitignore +26 -0
  2. e3sm_siteview-1.0.0/LICENSE +15 -0
  3. e3sm_siteview-1.0.0/PKG-INFO +102 -0
  4. e3sm_siteview-1.0.0/README.rst +64 -0
  5. e3sm_siteview-1.0.0/pyproject.toml +135 -0
  6. e3sm_siteview-1.0.0/src/e3sm_siteview/__init__.py +1 -0
  7. e3sm_siteview-1.0.0/src/e3sm_siteview/analysis/__init__.py +37 -0
  8. e3sm_siteview-1.0.0/src/e3sm_siteview/analysis/time.py +203 -0
  9. e3sm_siteview-1.0.0/src/e3sm_siteview/analysis/viz3d.py +219 -0
  10. e3sm_siteview-1.0.0/src/e3sm_siteview/app.py +37 -0
  11. e3sm_siteview-1.0.0/src/e3sm_siteview/assets/__init__.py +4 -0
  12. e3sm_siteview-1.0.0/src/e3sm_siteview/cli.py +20 -0
  13. e3sm_siteview-1.0.0/src/e3sm_siteview/components/__init__.py +0 -0
  14. e3sm_siteview-1.0.0/src/e3sm_siteview/components/controls.py +208 -0
  15. e3sm_siteview-1.0.0/src/e3sm_siteview/components/field_selection.py +120 -0
  16. e3sm_siteview-1.0.0/src/e3sm_siteview/components/footer.py +86 -0
  17. e3sm_siteview-1.0.0/src/e3sm_siteview/components/site_selection.py +194 -0
  18. e3sm_siteview-1.0.0/src/e3sm_siteview/components/tools.py +330 -0
  19. e3sm_siteview-1.0.0/src/e3sm_siteview/constants.py +637 -0
  20. e3sm_siteview-1.0.0/src/e3sm_siteview/data_models.py +211 -0
  21. e3sm_siteview-1.0.0/src/e3sm_siteview/io/__init__.py +14 -0
  22. e3sm_siteview-1.0.0/src/e3sm_siteview/io/_perf.py +13 -0
  23. e3sm_siteview-1.0.0/src/e3sm_siteview/io/_sm_compat.py +58 -0
  24. e3sm_siteview-1.0.0/src/e3sm_siteview/io/eam_filters.py +268 -0
  25. e3sm_siteview-1.0.0/src/e3sm_siteview/io/eam_reader.py +676 -0
  26. e3sm_siteview-1.0.0/src/e3sm_siteview/module/__init__.py +15 -0
  27. e3sm_siteview-1.0.0/src/e3sm_siteview/pages/__init__.py +9 -0
  28. e3sm_siteview-1.0.0/src/e3sm_siteview/pages/field_selection.py +29 -0
  29. e3sm_siteview-1.0.0/src/e3sm_siteview/pages/site_selection.py +29 -0
  30. e3sm_siteview-1.0.0/src/e3sm_siteview/pages/visualization.py +49 -0
  31. e3sm_siteview-1.0.0/src/e3sm_siteview/viewer.py +134 -0
@@ -0,0 +1,26 @@
1
+ .DS_Store
2
+ node_modules
3
+ .venv
4
+
5
+ # local env files
6
+ .env.local
7
+ .env.*.local
8
+
9
+ # Log files
10
+ npm-debug.log*
11
+ yarn-debug.log*
12
+ yarn-error.log*
13
+ pnpm-debug.log*
14
+
15
+ # Editor directories and files
16
+ .idea
17
+ .vscode
18
+ *.suo
19
+ *.ntvs*
20
+ *.njsproj
21
+ *.sln
22
+ *.sw?
23
+
24
+ __pycache__
25
+ *egg-info
26
+ *pyc
@@ -0,0 +1,15 @@
1
+ Apache Software License 2.0
2
+
3
+ Copyright (c) 2026, Kitware Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: e3sm-siteview
3
+ Version: 1.0.0
4
+ Summary: E3SM Column Explorer
5
+ Author: Kitware Inc.
6
+ License: Apache Software License
7
+ License-File: LICENSE
8
+ Keywords: Application,Framework,Interactive,Python,Web
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Natural Language :: English
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.12
18
+ Requires-Dist: netcdf4>=1.6.5
19
+ Requires-Dist: pyproj>=3.6.1
20
+ Requires-Dist: trame-colormaps>=1.6.1
21
+ Requires-Dist: trame-dataclass>=2.1.3
22
+ Requires-Dist: trame-dockview
23
+ Requires-Dist: trame-plotly
24
+ Requires-Dist: trame-rca[turbo]>=2.6
25
+ Requires-Dist: trame-vtk
26
+ Requires-Dist: trame-vuetify
27
+ Requires-Dist: trame>=3.13.2
28
+ Requires-Dist: vtk>=9.6
29
+ Provides-Extra: app
30
+ Requires-Dist: pywebview; extra == 'app'
31
+ Provides-Extra: dev
32
+ Requires-Dist: nox; extra == 'dev'
33
+ Requires-Dist: pre-commit; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=3; extra == 'dev'
35
+ Requires-Dist: pytest>=6; extra == 'dev'
36
+ Requires-Dist: ruff; extra == 'dev'
37
+ Description-Content-Type: text/x-rst
38
+
39
+ E3SM Site View
40
+ ----------------------------------------
41
+
42
+ E3SM Column Explorer
43
+
44
+ License
45
+ ----------------------------------------
46
+
47
+ This library is OpenSource and follow the Apache Software License
48
+
49
+ Installation
50
+ ----------------------------------------
51
+
52
+ Install the application/library
53
+
54
+ .. code-block:: console
55
+
56
+ pip install e3sm-siteview
57
+
58
+ Run the application
59
+
60
+ .. code-block:: console
61
+
62
+ e3sm-siteview --cf ../data/connectivity.nc --df ../data/file_1.nc [...] ../data/file_n.nc
63
+
64
+ Development setup
65
+ ----------------------------------------
66
+
67
+ We recommend using uv for setting up and managing a virtual environment for your development.
68
+
69
+ .. code-block:: console
70
+
71
+ # Create venv and install all dependencies
72
+ uv sync --all-extras --dev
73
+
74
+ # Activate environment
75
+ source .venv/bin/activate
76
+
77
+ # Install commit analysis
78
+ pre-commit install
79
+ pre-commit install --hook-type commit-msg
80
+
81
+
82
+
83
+
84
+ For running tests and checks, you can run ``nox``.
85
+
86
+ .. code-block:: console
87
+
88
+ # run all
89
+ nox
90
+
91
+ # lint
92
+ nox -s lint
93
+
94
+ # tests
95
+ nox -s tests
96
+
97
+ Professional Support
98
+ ----------------------------------------
99
+
100
+ * `Training <https://www.kitware.com/courses/trame/>`_: Learn how to confidently use trame from the expert developers at Kitware.
101
+ * `Support <https://www.kitware.com/trame/support/>`_: Our experts can assist your team as you build your web application and establish in-house expertise.
102
+ * `Custom Development <https://www.kitware.com/trame/support/>`_: Leverage Kitware’s 25+ years of experience to quickly build your web application.
@@ -0,0 +1,64 @@
1
+ E3SM Site View
2
+ ----------------------------------------
3
+
4
+ E3SM Column Explorer
5
+
6
+ License
7
+ ----------------------------------------
8
+
9
+ This library is OpenSource and follow the Apache Software License
10
+
11
+ Installation
12
+ ----------------------------------------
13
+
14
+ Install the application/library
15
+
16
+ .. code-block:: console
17
+
18
+ pip install e3sm-siteview
19
+
20
+ Run the application
21
+
22
+ .. code-block:: console
23
+
24
+ e3sm-siteview --cf ../data/connectivity.nc --df ../data/file_1.nc [...] ../data/file_n.nc
25
+
26
+ Development setup
27
+ ----------------------------------------
28
+
29
+ We recommend using uv for setting up and managing a virtual environment for your development.
30
+
31
+ .. code-block:: console
32
+
33
+ # Create venv and install all dependencies
34
+ uv sync --all-extras --dev
35
+
36
+ # Activate environment
37
+ source .venv/bin/activate
38
+
39
+ # Install commit analysis
40
+ pre-commit install
41
+ pre-commit install --hook-type commit-msg
42
+
43
+
44
+
45
+
46
+ For running tests and checks, you can run ``nox``.
47
+
48
+ .. code-block:: console
49
+
50
+ # run all
51
+ nox
52
+
53
+ # lint
54
+ nox -s lint
55
+
56
+ # tests
57
+ nox -s tests
58
+
59
+ Professional Support
60
+ ----------------------------------------
61
+
62
+ * `Training <https://www.kitware.com/courses/trame/>`_: Learn how to confidently use trame from the expert developers at Kitware.
63
+ * `Support <https://www.kitware.com/trame/support/>`_: Our experts can assist your team as you build your web application and establish in-house expertise.
64
+ * `Custom Development <https://www.kitware.com/trame/support/>`_: Leverage Kitware’s 25+ years of experience to quickly build your web application.
@@ -0,0 +1,135 @@
1
+ [project]
2
+ name = "e3sm-siteview"
3
+ version = "1.0.0"
4
+ description = "E3SM Column Explorer"
5
+ authors = [
6
+ {name = "Kitware Inc."},
7
+ ]
8
+ dependencies = [
9
+ "vtk>=9.6",
10
+ "trame >=3.13.2",
11
+ "trame-vuetify",
12
+ "trame-rca[turbo] >=2.6",
13
+ "trame-vtk", # FIXME use RCA instead
14
+ "trame-plotly",
15
+ "trame-colormaps >=1.6.1",
16
+ "trame-dockview",
17
+ "trame-dataclass >=2.1.3",
18
+ "pyproj>=3.6.1",
19
+ "netCDF4>=1.6.5",
20
+ ]
21
+ requires-python = ">=3.12"
22
+ readme = "README.rst"
23
+ license = {text = "Apache Software License"}
24
+ keywords = ["Python", "Interactive", "Web", "Application", "Framework"]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Environment :: Web Environment",
28
+ "License :: OSI Approved :: Apache Software License",
29
+ "Natural Language :: English",
30
+ "Operating System :: OS Independent",
31
+ "Programming Language :: Python :: 3 :: Only",
32
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
33
+ "Topic :: Software Development :: Libraries :: Python Modules",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ app = [
38
+ "pywebview",
39
+ ]
40
+ dev = [
41
+ "pre-commit",
42
+ "ruff",
43
+ "pytest >=6",
44
+ "pytest-cov >=3",
45
+ "nox",
46
+ ]
47
+
48
+ [project.scripts]
49
+ e3sm-siteview = "e3sm_siteview.app:main"
50
+
51
+ [build-system]
52
+ requires = ["hatchling"]
53
+ build-backend = "hatchling.build"
54
+
55
+
56
+ [tool.hatch.build]
57
+ include = [
58
+ "/src/**/*.py",
59
+ "/src/e3sm_site_view/**/*.js",
60
+ "/src/e3sm_site_view/**/*.css",
61
+ ]
62
+
63
+ [tool.hatch.build.targets.wheel]
64
+ packages = [
65
+ "src/e3sm_siteview",
66
+ ]
67
+
68
+ [tool.ruff]
69
+ # Vendored copy of QuickView's EAM VTK algorithms — keep upstream style, don't
70
+ # relint. Reconcile into a shared package later (see io/ module docstrings).
71
+ extend-exclude = ["src/e3sm_siteview/io"]
72
+
73
+ [tool.ruff.lint]
74
+ extend-select = [
75
+ "ARG", # flake8-unused-arguments
76
+ "B", # flake8-bugbear
77
+ "C4", # flake8-comprehensions
78
+ "EM", # flake8-errmsg
79
+ "EXE", # flake8-executable
80
+ "G", # flake8-logging-format
81
+ "I", # isort
82
+ "ICN", # flake8-import-conventions
83
+ "NPY", # NumPy specific rules
84
+ "PD", # pandas-vet
85
+ "PGH", # pygrep-hooks
86
+ "PIE", # flake8-pie
87
+ "PL", # pylint
88
+ "PT", # flake8-pytest-style
89
+ "PTH", # flake8-use-pathlib
90
+ "RET", # flake8-return
91
+ "RUF", # Ruff-specific
92
+ "SIM", # flake8-simplify
93
+ "T20", # flake8-print
94
+ "UP", # pyupgrade
95
+ "YTT", # flake8-2020
96
+ ]
97
+ ignore = [
98
+ "PLR09", # Too many <...>
99
+ "PLR2004", # Magic value used in comparison
100
+ "ISC001", # Conflicts with formatter
101
+ ]
102
+ isort.required-imports = []
103
+
104
+ [tool.ruff.lint.per-file-ignores]
105
+ "tests/**" = ["T20", "PLC0415"]
106
+ "noxfile.py" = ["T20"]
107
+ "examples/**" = ["T20", "INP001"]
108
+ "src/**" = ["SIM117", "T"]
109
+ "src/e3sm_siteview/plugins/**" = [
110
+ "PLW",
111
+ "ARG",
112
+ "RET",
113
+ "PLC",
114
+ "SIM",
115
+ "EM",
116
+ "PGH",
117
+ "T",
118
+ ]
119
+
120
+ [tool.semantic_release]
121
+ version_toml = [
122
+ "pyproject.toml:project.version",
123
+ ]
124
+ version_variables = [
125
+ "src/e3sm_siteview/__init__.py:__version__",
126
+ ]
127
+
128
+ build_command = """
129
+ python -m pip install uv
130
+ uv build
131
+ """
132
+
133
+ [tool.semantic_release.publish]
134
+ dist_glob_patterns = ["dist/*"]
135
+ upload_to_vcs_release = true
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,37 @@
1
+ import importlib.util
2
+ from pathlib import Path
3
+
4
+ REGISTRY = {}
5
+
6
+
7
+ def create_analysis(type, server, reader):
8
+ klass = REGISTRY.get(type)
9
+ if klass:
10
+ return klass(server, reader)
11
+ return None
12
+
13
+
14
+ def register_analysis(type, klass):
15
+ REGISTRY[type] = klass
16
+
17
+
18
+ def create_id_generator():
19
+ count = 0
20
+ while True:
21
+ count += 1
22
+ yield f"analysis_{count}"
23
+
24
+
25
+ def load_all_analysis():
26
+ for module_path in Path(__file__).parent.glob("*.py"):
27
+ if module_path.stem[0] == "_":
28
+ continue
29
+ name = module_path.stem
30
+ spec = importlib.util.spec_from_file_location(name, module_path)
31
+ module = importlib.util.module_from_spec(spec)
32
+ spec.loader.exec_module(module)
33
+
34
+
35
+ ANALYSIS_ID = create_id_generator()
36
+
37
+ __all__ = ["ANALYSIS_ID", "create_analysis", "load_all_analysis", "register_analysis"]
@@ -0,0 +1,203 @@
1
+ import json
2
+
3
+ import numpy as np
4
+ import plotly.graph_objects as go
5
+ from trame.app import TrameComponent
6
+ from trame.ui.html import DivLayout
7
+ from trame.widgets import html, plotly
8
+ from trame.widgets import vuetify3 as v3
9
+ from vtkmodules.util import numpy_support
10
+
11
+ from e3sm_siteview.analysis import ANALYSIS_ID, register_analysis
12
+ from e3sm_siteview.io import EAMColumnSource
13
+
14
+ NAME = "time"
15
+
16
+
17
+ class TimeCharts(TrameComponent):
18
+ def __init__(self, server, column_reader):
19
+ super().__init__(server)
20
+ self._id = next(ANALYSIS_ID)
21
+ self._subscriptions = []
22
+
23
+ self.columns = column_reader
24
+ self.single_column_reader = EAMColumnSource()
25
+ self.single_column_reader.SetDataFileName(self.columns.GetDataFileName())
26
+
27
+ self.ctx.setup.surface_chart.column = self.ctx.setup.col_ids.GetId(0)
28
+
29
+ self._build_ui()
30
+ self.bind_reactivity()
31
+
32
+ @property
33
+ def name(self):
34
+ return self._id
35
+
36
+ def _subscribe(self, obj, watch, callback, eager=False, sync=False):
37
+ self._subscriptions.append(obj.watch(watch, callback, eager=eager, sync=sync))
38
+
39
+ def bind_reactivity(self):
40
+ self._subscribe(
41
+ self.ctx.setup.surface_chart, ["color_by", "column"], self._compute_heatmap
42
+ )
43
+ self._subscribe(
44
+ self.ctx.setup.column, ["altitude_range"], self._compute_heatmap
45
+ )
46
+ self._subscribe(self.ctx.setup.volume, ["color_by"], self._sync_color_by)
47
+
48
+ def unbind_reactivity(self):
49
+ while self._subscriptions:
50
+ self._subscriptions.pop()()
51
+
52
+ def _sync_color_by(self, color_by):
53
+ self.ctx.setup.surface_chart.color_by = color_by
54
+
55
+ def _compute_heatmap(self, *_):
56
+ field = self.ctx.setup.surface_chart.color_by
57
+ col_id = self.ctx.setup.surface_chart.column
58
+ altitude_range = self.ctx.setup.column.altitude_range
59
+
60
+ if field is None:
61
+ return
62
+
63
+ col = self.single_column_reader
64
+ col.SetColumnIds(json.dumps([col_id]))
65
+ select_arrays = col.GetProfileVariables()
66
+
67
+ select_arrays.DisableAllArrays()
68
+ select_arrays.EnableArray(field)
69
+
70
+ series = []
71
+ levels = None
72
+ for t in range(self.ctx.setup.time_index_max):
73
+ col.SetSlicing(json.dumps({"time": t}))
74
+ col.Update()
75
+ table = col.GetOutputDataObject(0)
76
+ array = table.GetColumnByName(field)
77
+ profile = numpy_support.vtk_to_numpy(array)[0] # (n_lev,)
78
+ series.append(profile[altitude_range[0] : altitude_range[1]])
79
+
80
+ if levels is None:
81
+ levels = table.field_data["lev"][0][
82
+ altitude_range[0] : altitude_range[1]
83
+ ]
84
+
85
+ series = np.array(series) # (time, level)
86
+ # fig = px.imshow(
87
+ # series.T,
88
+ # aspect="auto",
89
+ # origin="lower",
90
+ # color_continuous_scale="Viridis",
91
+ # )
92
+ fig = go.Figure(
93
+ data=go.Heatmap(
94
+ z=series.T,
95
+ y=levels,
96
+ colorscale="Viridis",
97
+ )
98
+ )
99
+ fig.update_layout(
100
+ xaxis_title="time",
101
+ yaxis={"title": field, "autorange": "reversed"},
102
+ showlegend=False,
103
+ margin={"b": 0, "l": 0, "r": 0, "t": 0},
104
+ )
105
+ fig.update_xaxes(side="top")
106
+
107
+ with self.state:
108
+ self.update_figure(fig)
109
+
110
+ def shift_col_id(self, delta):
111
+ all_ids = self.ctx.setup.col_ids
112
+ current_col_id = self.ctx.setup.surface_chart.column
113
+ num_ids = all_ids.GetNumberOfIds()
114
+ for i in range(num_ids):
115
+ local_id = all_ids.GetId(i)
116
+ if current_col_id == local_id:
117
+ target_idx = min(max(0, i + delta), num_ids - 1)
118
+ self.ctx.setup.surface_chart.column = all_ids.GetId(target_idx)
119
+ return
120
+
121
+ self.ctx.setup.surface_chart.column = all_ids.GetId(0)
122
+
123
+ def _build_ui(self):
124
+ with DivLayout(self.server, self.name, classes="h-100") as self.ui:
125
+ with (
126
+ self.ctx.setup.provide_as("global"),
127
+ html.Div(
128
+ style="position:absolute;top:0;left:0;width:100%;height:100%;",
129
+ classes="d-flex flex-column",
130
+ ),
131
+ ):
132
+ with v3.VToolbar(
133
+ density="compact", classes="px-2 d-flex ga-2 bg-grey-darken-3"
134
+ ):
135
+ v3.VIcon("mdi-timeline-clock-outline")
136
+ v3.VSelect(
137
+ v_model="global.surface_chart.color_by",
138
+ items=(
139
+ "global.variables_3d.filter(v => v.selected).map(v => v.name)",
140
+ ),
141
+ density="compact",
142
+ hide_details=True,
143
+ variant="flat",
144
+ classes="w-100",
145
+ )
146
+ v3.VSpacer()
147
+ v3.VSelect(
148
+ prepend_inner_icon="mdi-map-marker-outline",
149
+ v_model="global.surface_chart.column",
150
+ items=("JSON.parse(global.col_ids_str)",),
151
+ density="compact",
152
+ hide_details=True,
153
+ variant="flat",
154
+ style="width:190px;",
155
+ )
156
+ v3.VBtn(
157
+ icon="mdi-chevron-left",
158
+ click=(self.shift_col_id, "[-1]"),
159
+ classes="rounded",
160
+ density="compact",
161
+ )
162
+ v3.VBtn(
163
+ icon="mdi-chevron-right",
164
+ click=(self.shift_col_id, "[+1]"),
165
+ classes="rounded",
166
+ density="compact",
167
+ )
168
+
169
+ with html.Div(classes="flex-fill pa-2 br-red"):
170
+ self.update_figure = plotly.Figure(
171
+ display_mode_bar=("false",)
172
+ ).update
173
+
174
+ with self.ctx.setup.provide_as("controls"):
175
+ with html.Div(
176
+ style="position:absolute;left:1rem;top:1rem;z-index:100;",
177
+ classes="d-flex flex-column ga-2 align-start",
178
+ ):
179
+ with v3.VCard(
180
+ classes="d-flex align-center",
181
+ v_if="controls.active_viz.includes('cloud')",
182
+ ):
183
+ v3.VBtn(
184
+ icon="mdi-weather-cloudy",
185
+ density="comfortable",
186
+ variant="plain",
187
+ classes="rounded ma-1",
188
+ click="controls.cloud.show = !controls.cloud.show",
189
+ )
190
+ v3.VSlider(
191
+ v_show="controls.cloud.show",
192
+ v_model="controls.cloud.opacity",
193
+ min=0,
194
+ max=1,
195
+ step=0.01,
196
+ style="width: 300px",
197
+ density="compact",
198
+ hide_details=True,
199
+ classes="mr-4",
200
+ )
201
+
202
+
203
+ register_analysis(NAME, TimeCharts)