nova-trame 1.0.0rc2__py3-none-any.whl → 1.0.0rc4__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.
@@ -70,6 +70,13 @@ class _MPLApplication(tornado.web.Application):
70
70
  data_uri = "data:image/png;base64," + blob.encode("base64").replace("\n", "")
71
71
  self.write_message(data_uri)
72
72
 
73
+ def write_message(self, *args: Any, **kwargs: Any) -> Any:
74
+ # We need the websocket to remain alive if a message fails to write.
75
+ try:
76
+ super().write_message(*args, **kwargs)
77
+ except Exception:
78
+ pass
79
+
73
80
  def __init__(self, figure: Figure) -> None:
74
81
  self.figure = figure
75
82
  self.manager = new_figure_manager_given_figure(id(figure), figure)
@@ -218,9 +225,9 @@ class MatplotlibFigure(matplotlib.Figure):
218
225
  self._server = get_server(None, client_type="vue3")
219
226
  self._webagg = webagg
220
227
  if "classes" in kwargs:
221
- kwargs["classes"] += " h-100 w-100 overflow-hidden"
228
+ kwargs["classes"] += " flex-1-1"
222
229
  else:
223
- kwargs["classes"] = "h-100 w-100 overflow-hidden"
230
+ kwargs["classes"] = "flex-1-1"
224
231
  if webagg:
225
232
  self._initial_resize = True
226
233
  if "id" in kwargs:
@@ -247,17 +254,28 @@ class MatplotlibFigure(matplotlib.Figure):
247
254
 
248
255
  self._query_selector = f"window.document.querySelector('#{self._id}')"
249
256
  self._trigger = (
257
+ f"if ({self._query_selector} === null) {{ return; }}"
258
+ # webagg figures receive a fixed width and height. This blocks the flexbox scaling, so I temporarily hide
259
+ # the figure to allow the container to grow/shrink naturally in flexbox.
260
+ f"window.document.querySelectorAll('.nova-mpl').forEach((item) => {{ item.style.display = 'none'; }});"
261
+ f"const height = {self._query_selector}.parentNode.offsetHeight;"
262
+ f"const width = {self._query_selector}.parentNode.offsetWidth;"
263
+ # Revert the display value to allow the figure to render again.
264
+ f"window.document.querySelectorAll('.nova-mpl').forEach((item) => {{ item.style.display = ''; }});"
250
265
  "window.trame.trigger("
251
266
  f" '{self._id}_resize',"
252
- f" [{self._query_selector}.offsetHeight, {self._query_selector}.offsetWidth, window.devicePixelRatio]"
267
+ f" [height, width, window.devicePixelRatio]"
253
268
  ");"
254
269
  )
255
270
  self._resize_figure = client.JSEval(exec=self._trigger).exec
256
271
  self._resize_listener = client.JSEval(
257
272
  exec=(
258
- "window.addEventListener('resize', function() {"
273
+ # ResizeObserver is necessary to detect changes in size unrelated to the viewport size such as when
274
+ # content is conditionally rendered that changes the size of the figure's container.
275
+ "const resizeObserver = new window.ResizeObserver(() => {"
259
276
  f" window.delay_manager.debounce('{self._id}', function() {{ {self._trigger} }}, 500);"
260
277
  "});"
278
+ f"resizeObserver.observe({self._query_selector}.parentNode);"
261
279
  )
262
280
  ).exec
263
281
 
@@ -278,10 +296,18 @@ class MatplotlibFigure(matplotlib.Figure):
278
296
  height = int(height * device_pixel_ratio)
279
297
  width = int(width * device_pixel_ratio)
280
298
 
299
+ if height <= 0 or width <= 0:
300
+ return
301
+
302
+ if self._webagg:
281
303
  self._initial_resize = False
282
304
 
283
305
  self._figure.set_dpi(dpi)
284
- self._figure.set_size_inches(width / dpi, height / dpi)
306
+ new_width = width / dpi
307
+ new_height = height / dpi
308
+ current_size = self._figure.get_size_inches()
309
+ if current_size[0] != new_width or current_size[1] != new_height:
310
+ self._figure.set_size_inches(new_width, new_height)
285
311
 
286
312
  self.update(skip_resize=True)
287
313
 
@@ -1,6 +1,7 @@
1
1
  """Trame implementation of the GridLayout class."""
2
2
 
3
3
  from typing import Any, Optional, Union
4
+ from warnings import warn
4
5
 
5
6
  from trame.widgets import html
6
7
  from trame_client.widgets.core import AbstractElement
@@ -39,7 +40,8 @@ class GridLayout(html.Div):
39
40
  <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>`__ for available options.
40
41
  valign : optional[str]
41
42
  The vertical alignment of items in the grid. See `MDN
42
- <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options.
43
+ <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options. Note that this
44
+ parameter is ignored when stretch=True.
43
45
  gap : optional[str]
44
46
  The gap to place between items (works both horizontally and vertically). Can be any CSS gap value (e.g.
45
47
  "4px" or "0.25em"). Defaults to no gap between items.
@@ -74,7 +76,12 @@ class GridLayout(html.Div):
74
76
  classes = " ".join(classes)
75
77
  classes += " d-grid"
76
78
  if stretch:
79
+ if valign:
80
+ warn("Ignoring valign parameter to GridLayout since stretch=True.", stacklevel=1)
81
+ valign = "stretch"
77
82
  classes += " flex-1-1 overflow-y-auto"
83
+ else:
84
+ classes += " flex-0-1"
78
85
 
79
86
  widget_style = self.get_root_styles(columns, height, width, halign, valign, gap)
80
87
  user_style = kwargs.pop("style", {})
@@ -66,6 +66,8 @@ class HBoxLayout(html.Div):
66
66
  classes += " d-flex flex-row"
67
67
  if stretch:
68
68
  classes += " flex-1-1 overflow-y-auto"
69
+ else:
70
+ classes += " flex-0-1"
69
71
 
70
72
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
71
73
  user_style = kwargs.pop("style", {})
@@ -66,6 +66,8 @@ class VBoxLayout(html.Div):
66
66
  classes += " d-flex flex-column"
67
67
  if stretch:
68
68
  classes += " flex-1-1 overflow-y-auto"
69
+ else:
70
+ classes += " flex-0-1"
69
71
 
70
72
  widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
71
73
  user_style = kwargs.pop("style", {})
@@ -259,13 +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 flex-0-1 my-1 ")
262
+ layout.pre_content = vuetify.VSheet(classes="bg-background flex-0-1 mt-1 ")
263
263
  # [slot override example complete]
264
264
  with vuetify.VContainer(classes="flex-1-1 overflow-hidden pt-0 pb-2", fluid=True):
265
265
  layout.content = vuetify.VCard(
266
- classes="d-flex flex-column flex-1-1 h-100 my-1 overflow-y-auto pa-1 "
266
+ classes="d-flex flex-column flex-1-1 h-100 overflow-y-auto pa-1 "
267
267
  )
268
- layout.post_content = vuetify.VSheet(classes="bg-background flex-0-1 my-1 ")
268
+ layout.post_content = vuetify.VSheet(classes="bg-background flex-0-1 mb-1 ")
269
269
 
270
270
  with vuetify.VFooter(
271
271
  app=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nova-trame
3
- Version: 1.0.0rc2
3
+ Version: 1.0.0rc4
4
4
  Summary: A Python Package for injecting curated themes and custom components into Trame applications
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -18,12 +18,12 @@ nova/trame/view/components/remote_file_input.py,sha256=mcz_bmI2rD8gdmIOKLhlzfj-X
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=PhLZ95ofl78M2I5JMRdQeJZit9du-rW2H_km0jWF3Rg,14756
21
+ nova/trame/view/components/visualization/matplotlib_figure.py,sha256=GYfX7hlEWQ4Dghk8Z1dmUQr6jgktWirhOYb0drtonM4,16297
22
22
  nova/trame/view/layouts/__init__.py,sha256=cMrlB5YMUoK8EGB83b34UU0kPTVrH8AxsYvKRtpUNEc,141
23
- nova/trame/view/layouts/grid.py,sha256=lQVLnpmOvT2y6-gUEgmdE1VvodLxlul6i5Hov202uOo,5816
24
- nova/trame/view/layouts/hbox.py,sha256=RJphvkcdvcke1y_R85BR_DI54zPVRQFiU-S1m7U56LI,3801
23
+ nova/trame/view/layouts/grid.py,sha256=DU5u5JTE0ulzCaJsEWyTenBH9lOQD7mtoC6RZXxDTPE,6110
24
+ nova/trame/view/layouts/hbox.py,sha256=w6ow7Qzmq4slODz_9f7kEigCVPE2PhUmPODedYH34f4,3850
25
25
  nova/trame/view/layouts/utils.py,sha256=Hg34VQWTG3yHBsgNvmfatR4J-uL3cko7UxSJpT-h3JI,376
26
- nova/trame/view/layouts/vbox.py,sha256=V7bzDjznUNruHd5RDlbbS8eLKxfJvS9iUHTRW8twSVM,3802
26
+ nova/trame/view/layouts/vbox.py,sha256=Kkci79zDKF6qNH4HeDPYquJcixXx3BS63NVmS3FlOiw,3851
27
27
  nova/trame/view/theme/__init__.py,sha256=70_marDlTigIcPEOGiJb2JTs-8b2sGM5SlY7XBPtBDM,54
28
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
@@ -32,7 +32,7 @@ nova/trame/view/theme/assets/js/lodash.min.js,sha256=KCyAYJ-fsqtp_HMwbjhy6IKjlA5
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=gdmHWyYgLThv8_UHwstbSpBhHnlvIHdADIepxgqVy9Q,13274
35
+ nova/trame/view/theme/theme.py,sha256=Jeoi-qrokSO-dDYpEvicbqfwzalhhbG-4HplD8NFj6s,13269
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-1.0.0rc2.dist-info/METADATA,sha256=4pMFtoku0PIb83aIpNWcb_OObxTfWoqW_CTF_BcSUz8,1798
44
- nova_trame-1.0.0rc2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
45
- nova_trame-1.0.0rc2.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
46
- nova_trame-1.0.0rc2.dist-info/licenses/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
47
- nova_trame-1.0.0rc2.dist-info/RECORD,,
43
+ nova_trame-1.0.0rc4.dist-info/METADATA,sha256=ullsD538VJU9i_HleHEUd0U5NytxWHl7gKY8hk7XIYI,1798
44
+ nova_trame-1.0.0rc4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
45
+ nova_trame-1.0.0rc4.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
46
+ nova_trame-1.0.0rc4.dist-info/licenses/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
47
+ nova_trame-1.0.0rc4.dist-info/RECORD,,