nova-trame 0.26.2__py3-none-any.whl → 1.0.0rc0__py3-none-any.whl

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.
@@ -317,9 +317,3 @@ class NeutronDataSelector(DataSelector):
317
317
  experiment=set_state_param(self.state, (self._selected_experiment_name,), experiment),
318
318
  )
319
319
  self._vm.reset()
320
-
321
- def set_state(self, *args: Any, **kwargs: Any) -> None:
322
- raise TypeError(
323
- "The set_state method has been removed. Please use update_facility, update_instrument, and "
324
- "update_experiment instead."
325
- )
@@ -9,6 +9,7 @@ from mimetypes import types_map
9
9
  from pathlib import Path
10
10
  from threading import Thread
11
11
  from typing import Any, Optional
12
+ from warnings import warn
12
13
 
13
14
  import tornado
14
15
  from aiohttp import ClientSession, WSMsgType, web
@@ -214,17 +215,23 @@ class MatplotlibFigure(matplotlib.Figure):
214
215
  -------
215
216
  None
216
217
  """ # noqa: E501
218
+ self._server = get_server(None, client_type="vue3")
217
219
  self._webagg = webagg
220
+ if "classes" in kwargs:
221
+ kwargs["classes"] += " h-100 w-100 overflow-hidden"
222
+ else:
223
+ kwargs["classes"] = "h-100 w-100 overflow-hidden"
218
224
  if webagg:
219
- self._port = MatplotlibFigure._get_free_port()
220
- if "classes" in kwargs:
221
- kwargs["classes"] += " nova-mpl"
222
- else:
223
- kwargs["classes"] = "nova-mpl"
225
+ self._initial_resize = True
226
+ if "id" in kwargs:
227
+ kwargs.pop("id")
228
+ warn("id parameter to MatplotlibFigure is ignored when webagg=True.", stacklevel=1)
224
229
 
225
- html.Div(id=f"nova_mpl_{self._port}", **kwargs)
230
+ self._port = MatplotlibFigure._get_free_port()
231
+ self._id = f"nova_mpl_{self._port}"
232
+ kwargs["classes"] += " nova-mpl"
226
233
 
227
- self._server = get_server(None, client_type="vue3")
234
+ html.Div(id=self._id, **kwargs)
228
235
 
229
236
  self._figure = figure
230
237
  self._initialized = False
@@ -236,8 +243,52 @@ class MatplotlibFigure(matplotlib.Figure):
236
243
  self.update()
237
244
  else:
238
245
  super().__init__(figure, **kwargs)
246
+ self._id = self._key
247
+
248
+ self._query_selector = f"window.document.querySelector('#{self._id}')"
249
+ self._trigger = (
250
+ "window.trame.trigger("
251
+ f" '{self._id}_resize',"
252
+ f" [{self._query_selector}.offsetHeight, {self._query_selector}.offsetWidth, window.devicePixelRatio]"
253
+ ");"
254
+ )
255
+ self._resize_figure = client.JSEval(exec=self._trigger).exec
256
+ self._resize_listener = client.JSEval(
257
+ exec=(
258
+ "window.addEventListener('resize', function() {"
259
+ f" window.delay_manager.debounce('{self._id}', function() {{ {self._trigger} }}, 500);"
260
+ "});"
261
+ )
262
+ ).exec
263
+
264
+ @self._server.controller.trigger(f"{self._id}_resize")
265
+ def resize_figure(height: int, width: int, device_pixel_ratio: float) -> None:
266
+ if self._figure:
267
+ # This is the browser standard assumption for DPI.
268
+ dpi = 96
269
+
270
+ if self._webagg:
271
+ # Reserve space for the controls injected by webagg.
272
+ height -= 48
273
+ width -= 4
239
274
 
240
- def update(self, figure: Optional[Figure] = None) -> None:
275
+ if not self._initial_resize:
276
+ # Handle device pixel ratio for retina displays
277
+ dpi = int(dpi * device_pixel_ratio)
278
+ height = int(height * device_pixel_ratio)
279
+ width = int(width * device_pixel_ratio)
280
+
281
+ self._initial_resize = False
282
+
283
+ self._figure.set_dpi(dpi)
284
+ self._figure.set_size_inches(width / dpi, height / dpi)
285
+
286
+ self.update(skip_resize=True)
287
+
288
+ client.ClientTriggers(mounted=self._resize_listener)
289
+ client.ClientTriggers(mounted=self._resize_figure)
290
+
291
+ def update(self, figure: Optional[Figure] = None, skip_resize: bool = False) -> None:
241
292
  if self._webagg:
242
293
  if figure:
243
294
  self._figure = figure
@@ -255,7 +306,10 @@ class MatplotlibFigure(matplotlib.Figure):
255
306
  else:
256
307
  super().update(figure)
257
308
 
258
- self._server.state.flush()
309
+ if not skip_resize and hasattr(self, "_resize_figure"):
310
+ self._resize_figure()
311
+ else:
312
+ self._server.state.flush()
259
313
 
260
314
  def _setup_figure_websocket(self) -> None:
261
315
  thread = Thread(target=self._mpl_run_ws_server, daemon=True)
@@ -19,6 +19,7 @@ class GridLayout(html.Div):
19
19
  halign: Optional[str] = None,
20
20
  valign: Optional[str] = None,
21
21
  gap: Optional[Union[int, str]] = "0em",
22
+ stretch: bool = False,
22
23
  **kwargs: Any,
23
24
  ) -> None:
24
25
  """Constructor for GridLayout.
@@ -42,6 +43,9 @@ class GridLayout(html.Div):
42
43
  gap : optional[str]
43
44
  The gap to place between items (works both horizontally and vertically). Can be any CSS gap value (e.g.
44
45
  "4px" or "0.25em"). Defaults to no gap between items.
46
+ stretch : optional[bool]
47
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
48
+ Defaults to False.
45
49
  kwargs : Any
46
50
  Additional keyword arguments to pass to html.Div.
47
51
 
@@ -69,6 +73,8 @@ class GridLayout(html.Div):
69
73
  if isinstance(classes, list):
70
74
  classes = " ".join(classes)
71
75
  classes += " d-grid"
76
+ if stretch:
77
+ classes += " flex-1-1 overflow-y-auto"
72
78
 
73
79
  widget_style = self.get_root_styles(columns, height, width, halign, valign, gap)
74
80
  user_style = kwargs.pop("style", {})
@@ -18,6 +18,7 @@ class HBoxLayout(html.Div):
18
18
  valign: Optional[str] = None,
19
19
  gap: Optional[Union[int, str]] = "0em",
20
20
  vspace: Optional[Union[int, str]] = "0em",
21
+ stretch: bool = False,
21
22
  **kwargs: Any,
22
23
  ) -> None:
23
24
  """Constructor for HBoxLayout.
@@ -42,6 +43,9 @@ class HBoxLayout(html.Div):
42
43
  vspace : optional[str]
43
44
  The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
45
  gap between items.
46
+ stretch : optional[bool]
47
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
48
+ Defaults to False.
45
49
  kwargs : Any
46
50
  Additional keyword arguments to pass to html.Div.
47
51
 
@@ -60,6 +64,8 @@ class HBoxLayout(html.Div):
60
64
  if isinstance(classes, list):
61
65
  classes = " ".join(classes)
62
66
  classes += " d-flex flex-row"
67
+ if stretch:
68
+ classes += " flex-1-1 overflow-y-auto"
63
69
 
64
70
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
71
  user_style = kwargs.pop("style", {})
@@ -18,6 +18,7 @@ class VBoxLayout(html.Div):
18
18
  valign: Optional[str] = None,
19
19
  gap: Optional[Union[int, str]] = "0em",
20
20
  vspace: Optional[Union[int, str]] = "0em",
21
+ stretch: bool = False,
21
22
  **kwargs: Any,
22
23
  ) -> None:
23
24
  """Constructor for VBoxLayout.
@@ -42,6 +43,9 @@ class VBoxLayout(html.Div):
42
43
  vspace : optional[str]
43
44
  The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
45
  gap between items.
46
+ stretch : optional[bool]
47
+ If True, then this layout component will stretch to attempt to fill the space of it's parent container.
48
+ Defaults to False.
45
49
  kwargs : Any
46
50
  Additional keyword arguments to pass to html.Div.
47
51
 
@@ -60,6 +64,8 @@ class VBoxLayout(html.Div):
60
64
  if isinstance(classes, list):
61
65
  classes = " ".join(classes)
62
66
  classes += " d-flex flex-column"
67
+ if stretch:
68
+ classes += " flex-1-1 overflow-y-auto"
63
69
 
64
70
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
71
  user_style = kwargs.pop("style", {})
@@ -70,8 +70,18 @@ html {
70
70
  }
71
71
 
72
72
  .v-window {
73
+ display: flex;
74
+ flex: 1 1;
73
75
  overflow-x: visible !important;
74
76
  overflow-y: visible !important;
77
+
78
+ .v-window__container {
79
+ flex: 1 1;
80
+
81
+ .v-window-item {
82
+ flex: 1 1;
83
+ }
84
+ }
75
85
  }
76
86
 
77
87
  @media only screen and (max-width: 959px) {
@@ -259,11 +259,13 @@ class ThemedApp:
259
259
 
260
260
  with vuetify.VMain(classes="align-stretch d-flex flex-column h-screen"):
261
261
  # [slot override example]
262
- layout.pre_content = vuetify.VSheet(classes="bg-background ")
262
+ layout.pre_content = vuetify.VSheet(classes="bg-background flex-0-1 my-1 ")
263
263
  # [slot override example complete]
264
- with vuetify.VContainer(classes="flex-0-1 overflow-hidden pt-0 pb-0", fluid=True):
265
- layout.content = html.Div(classes="h-100 overflow-y-auto pb-1 ")
266
- layout.post_content = vuetify.VSheet(classes="bg-background ")
264
+ with vuetify.VContainer(classes="flex-1-1 overflow-hidden pt-0 pb-2", fluid=True):
265
+ layout.content = vuetify.VCard(
266
+ classes="d-flex flex-column flex-1-1 h-100 my-1 overflow-y-auto pa-1 "
267
+ )
268
+ layout.post_content = vuetify.VSheet(classes="bg-background flex-0-1 my-1 ")
267
269
 
268
270
  with vuetify.VFooter(
269
271
  app=True,
@@ -1,18 +1,19 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: nova-trame
3
- Version: 0.26.2
3
+ Version: 1.0.0rc0
4
4
  Summary: A Python Package for injecting curated themes and custom components into Trame applications
5
- License: MIT
5
+ License-Expression: MIT
6
+ License-File: LICENSE
6
7
  Keywords: NDIP,Python,Trame,Vuetify
7
8
  Author: John Duggan
8
9
  Author-email: dugganjw@ornl.gov
9
10
  Requires-Python: >=3.10,<4.0
10
- Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
16
17
  Requires-Dist: altair
17
18
  Requires-Dist: blinker (>=1.9.0,<2.0.0)
18
19
  Requires-Dist: libsass
@@ -12,27 +12,27 @@ nova/trame/view/components/execution_buttons.py,sha256=Br6uAmE5bY67TTYc5ZTHECNJ_
12
12
  nova/trame/view/components/file_upload.py,sha256=WOaFXeNNwN0DYZJr-W6vWdBiTpr7m-lq3WKJaHmeMe8,4560
13
13
  nova/trame/view/components/input_field.py,sha256=xzCmNEoB4ljGx99-gGgTV0UwriwtS8ce22zPA4QneZw,17372
14
14
  nova/trame/view/components/ornl/__init__.py,sha256=HnxzzSsxw0vQSDCVFfWsAxx1n3HnU37LMuQkfiewmSU,90
15
- nova/trame/view/components/ornl/neutron_data_selector.py,sha256=wVSLmRXiGOv2l-nZ0DgDwjrgTMZDu9e9ECm3k824k3o,16749
15
+ nova/trame/view/components/ornl/neutron_data_selector.py,sha256=ozGKzUeKWpn3KjV22AL0qmKeSD2PH_S6kBAchwbxdBY,16507
16
16
  nova/trame/view/components/progress_bar.py,sha256=zhbJwPy_HPQ8YL-ISN8sCRUQ7qY6qqo9wiV59BmvL8I,3038
17
17
  nova/trame/view/components/remote_file_input.py,sha256=mcz_bmI2rD8gdmIOKLhlzfj-XoWBwC99T9ZgQORaKqE,14674
18
18
  nova/trame/view/components/tool_outputs.py,sha256=IbYV4VjrkWAE354Bh5KH76SPsxGLIkOXChijS4-ce_Y,2408
19
19
  nova/trame/view/components/visualization/__init__.py,sha256=reqkkbhD5uSksHHlhVMy1qNUCwSekS5HlXk6wCREYxU,152
20
20
  nova/trame/view/components/visualization/interactive_2d_plot.py,sha256=z2s1janxAclpMEdDJk3z-CQ6r3KPNoR_SXPx9ppWnuQ,3481
21
- nova/trame/view/components/visualization/matplotlib_figure.py,sha256=q0HLaaLFjM3_V1oUk-VBHWvokFY6AQZzmnMcynTroik,12488
21
+ nova/trame/view/components/visualization/matplotlib_figure.py,sha256=PhLZ95ofl78M2I5JMRdQeJZit9du-rW2H_km0jWF3Rg,14756
22
22
  nova/trame/view/layouts/__init__.py,sha256=cMrlB5YMUoK8EGB83b34UU0kPTVrH8AxsYvKRtpUNEc,141
23
- nova/trame/view/layouts/grid.py,sha256=vqEX-jghs6j9_sVtijdRH7uhlD9loWNi90k2qgg4Dhg,5534
24
- nova/trame/view/layouts/hbox.py,sha256=cdwnGk93ec6dXAeEamRQx1WTj5T7Ygsmsy0xz130tWM,3519
23
+ nova/trame/view/layouts/grid.py,sha256=lQVLnpmOvT2y6-gUEgmdE1VvodLxlul6i5Hov202uOo,5816
24
+ nova/trame/view/layouts/hbox.py,sha256=RJphvkcdvcke1y_R85BR_DI54zPVRQFiU-S1m7U56LI,3801
25
25
  nova/trame/view/layouts/utils.py,sha256=Hg34VQWTG3yHBsgNvmfatR4J-uL3cko7UxSJpT-h3JI,376
26
- nova/trame/view/layouts/vbox.py,sha256=XRV14e32MY1HWc9FTVTv1vOatWWbhLMd0lYwZP-isTg,3520
26
+ nova/trame/view/layouts/vbox.py,sha256=V7bzDjznUNruHd5RDlbbS8eLKxfJvS9iUHTRW8twSVM,3802
27
27
  nova/trame/view/theme/__init__.py,sha256=70_marDlTigIcPEOGiJb2JTs-8b2sGM5SlY7XBPtBDM,54
28
- nova/trame/view/theme/assets/core_style.scss,sha256=3-3qMc5gpaDhfuVWAF_psBH5alxwiuK-hPGhVgi2cW0,4335
28
+ nova/trame/view/theme/assets/core_style.scss,sha256=lZK8zghy4ExmNuFI-rfq7qt2S7bqObzM_MBviOlWP5c,4481
29
29
  nova/trame/view/theme/assets/favicon.png,sha256=Xbp1nUmhcBDeObjsebEbEAraPDZ_M163M_ZLtm5AbQc,1927
30
30
  nova/trame/view/theme/assets/js/delay_manager.js,sha256=BN4OL88QsyZG4XQ1sTorHpN1rwD4GnWoVKHvl5F5ydo,776
31
31
  nova/trame/view/theme/assets/js/lodash.min.js,sha256=KCyAYJ-fsqtp_HMwbjhy6IKjlA5lrVrtWt1JdMsC57k,73016
32
32
  nova/trame/view/theme/assets/js/revo_grid.js,sha256=fbuEWO8etw-xgo9tjJGjJXdd5wL8qpgabPmrnU6Jp8k,4081
33
33
  nova/trame/view/theme/assets/vuetify_config.json,sha256=a0FSgpLYWGFlRGSMhMq61MyDFBEBwvz55G4qjkM08cs,5627
34
34
  nova/trame/view/theme/exit_button.py,sha256=Kqv1GVJZGrSsj6_JFjGU3vm3iNuMolLC2T1x2IsdmV0,3094
35
- nova/trame/view/theme/theme.py,sha256=8JqSrEbhxK1SccXE1_jUdel9Wtc2QNObVEwtbVWG_QY,13146
35
+ nova/trame/view/theme/theme.py,sha256=gdmHWyYgLThv8_UHwstbSpBhHnlvIHdADIepxgqVy9Q,13274
36
36
  nova/trame/view/utilities/local_storage.py,sha256=vD8f2VZIpxhIKjZwEaD7siiPCTZO4cw9AfhwdawwYLY,3218
37
37
  nova/trame/view_model/data_selector.py,sha256=jAtq5hpohQ6YiLBbgLJfNUzWZBpN2bjCG_c_FCJu2ns,3186
38
38
  nova/trame/view_model/execution_buttons.py,sha256=MfKSp95D92EqpD48C15cBo6dLO0Yld4FeRZMJNxJf7Y,3551
@@ -40,8 +40,8 @@ nova/trame/view_model/ornl/neutron_data_selector.py,sha256=PIKQyzcHpwu81DNk3d8Af
40
40
  nova/trame/view_model/progress_bar.py,sha256=6AUKHF3hfzbdsHqNEnmHRgDcBKY5TT8ywDx9S6ovnsc,2854
41
41
  nova/trame/view_model/remote_file_input.py,sha256=zWOflmCDJYYR_pacHphwzricV667GSRokh-mlxpBAOo,3646
42
42
  nova/trame/view_model/tool_outputs.py,sha256=ev6LY7fJ0H2xAJn9f5ww28c8Kpom2SYc2FbvFcoN4zg,829
43
- nova_trame-0.26.2.dist-info/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
44
- nova_trame-0.26.2.dist-info/METADATA,sha256=mDqDXOmyd5tFAnh7-VtPdiYu1ij7ajZcanzkgC6Ojps,1763
45
- nova_trame-0.26.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
46
- nova_trame-0.26.2.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
47
- nova_trame-0.26.2.dist-info/RECORD,,
43
+ nova_trame-1.0.0rc0.dist-info/METADATA,sha256=_PBPlbMJ08eEGXZD9voV4iFT9hf5tkmd3XWT5pTU0R8,1798
44
+ nova_trame-1.0.0rc0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
45
+ nova_trame-1.0.0rc0.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
46
+ nova_trame-1.0.0rc0.dist-info/licenses/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
47
+ nova_trame-1.0.0rc0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any