babelplot 2025.6__tar.gz → 2025.7__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.
- {babelplot-2025.6 → babelplot-2025.7}/PKG-INFO +1 -1
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/catalog/bokeh_.py +6 -3
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/catalog/matplotlib_.py +87 -73
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/catalog/plotly_.py +220 -147
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/catalog/vedo_.py +4 -1
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/helper/validation.py +2 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/task/showing.py +33 -30
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/backend.py +26 -9
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/figure.py +12 -12
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/plot_type.py +2 -2
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/version.py +1 -1
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot.egg-info/PKG-INFO +1 -1
- {babelplot-2025.6 → babelplot-2025.7}/MANIFEST.in +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/README-COPYRIGHT-utf8.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/README-LICENCE-utf8.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/README.rst +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/documentation/wiki/description.asciidoc +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/__init__.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/api/backend.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/api/definition.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/api/help.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/backend/helper/creation.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/constant/backend.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/constant/path.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/constant/project.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/extension/enum_.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/extension/function.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/runtime/backends.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/runtime/figure.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/task/help.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/task/instantiation.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/dimension.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/ffp_base.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/frame.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/plot.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot/type/translator.py +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot.egg-info/SOURCES.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot.egg-info/dependency_links.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot.egg-info/requires.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/package/babelplot.egg-info/top_level.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/pyproject.toml +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/requirements.txt +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/setup.cfg +0 -0
- {babelplot-2025.6 → babelplot-2025.7}/setup.py +0 -0
|
@@ -7,7 +7,7 @@ SEE COPYRIGHT NOTICE BELOW
|
|
|
7
7
|
import dataclasses as d
|
|
8
8
|
import typing as h
|
|
9
9
|
|
|
10
|
-
from babelplot.task.showing import
|
|
10
|
+
from babelplot.task.showing import ShowHTMLWithPyQt
|
|
11
11
|
from babelplot.type.dimension import dim_e
|
|
12
12
|
from babelplot.type.figure import figure_t as base_figure_t
|
|
13
13
|
from babelplot.type.frame import frame_t as base_frame_t
|
|
@@ -59,8 +59,11 @@ class frame_t(base_frame_t):
|
|
|
59
59
|
class figure_t(base_figure_t):
|
|
60
60
|
layout: h.Any = None
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
_BackendShow = ShowHTMLWithPyQt
|
|
63
|
+
|
|
64
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_t:
|
|
65
|
+
""""""
|
|
66
|
+
return backend_figure_t(*args, **kwargs)
|
|
64
67
|
|
|
65
68
|
def _NewFrame(
|
|
66
69
|
self,
|
|
@@ -124,10 +124,13 @@ class figure_t(base_figure_t):
|
|
|
124
124
|
_BackendSetProperty: h.ClassVar[h.Callable] = _SetProperty
|
|
125
125
|
_BackendProperty: h.ClassVar[h.Callable] = _Property
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
def _NewBackendFigure(*args, **kwargs) -> backend_figure_t:
|
|
127
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_t:
|
|
129
128
|
""""""
|
|
130
|
-
|
|
129
|
+
output = NewBackendFigure(*args, num=None, **kwargs)
|
|
130
|
+
|
|
131
|
+
output.canvas.mpl_connect("close_event", lambda *_, **__: _OnCloseEvent(self))
|
|
132
|
+
|
|
133
|
+
return output
|
|
131
134
|
|
|
132
135
|
def _NewFrame(
|
|
133
136
|
self,
|
|
@@ -199,27 +202,27 @@ class figure_t(base_figure_t):
|
|
|
199
202
|
)
|
|
200
203
|
frame.raw.set_position((left, bottom, width, height))
|
|
201
204
|
|
|
202
|
-
def _BackendShow(self) -> None:
|
|
205
|
+
def _BackendShow(self, modal: bool, /) -> None:
|
|
203
206
|
""""""
|
|
204
207
|
raw = self.raw
|
|
205
|
-
|
|
206
208
|
raw.show()
|
|
207
209
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
210
|
+
if modal:
|
|
211
|
+
title = raw.get_suptitle()
|
|
212
|
+
if title.__len__() > 0:
|
|
213
|
+
title = f"{title} [MASTER FIGURE]"
|
|
214
|
+
else:
|
|
215
|
+
title = "MASTER FIGURE"
|
|
216
|
+
raw.suptitle(title)
|
|
213
217
|
|
|
218
|
+
raw.canvas.start_event_loop()
|
|
214
219
|
|
|
215
|
-
def _Polygon(
|
|
216
|
-
frame: backend_frame_2d_t, xs: array_t, ys: array_t, *_, **kwargs
|
|
217
|
-
) -> polygon_t:
|
|
218
|
-
""""""
|
|
219
|
-
output = polygon_t(nmpy.vstack((xs, ys)).T, **kwargs)
|
|
220
|
-
frame.add_patch(output)
|
|
221
220
|
|
|
222
|
-
|
|
221
|
+
def _OnCloseEvent(figure: figure_t, /) -> None:
|
|
222
|
+
""""""
|
|
223
|
+
# Hopefully, the event loop does not mind being stopped several times.
|
|
224
|
+
figure.raw.canvas.stop_event_loop()
|
|
225
|
+
figure.AcknowledgeClosure()
|
|
223
226
|
|
|
224
227
|
|
|
225
228
|
def _Arrows2(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
@@ -268,6 +271,54 @@ def _Arrows3(frame: backend_frame_3d_t, *args, **kwargs) -> backend_plot_t:
|
|
|
268
271
|
return frame.quiver(x, y, z, u, v, w, **kwargs)
|
|
269
272
|
|
|
270
273
|
|
|
274
|
+
def _Bar3(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
275
|
+
""""""
|
|
276
|
+
if args.__len__() == 1:
|
|
277
|
+
counts = nmpy.asarray(args[0])
|
|
278
|
+
x, y = counts.shape
|
|
279
|
+
else:
|
|
280
|
+
x, y, counts = args
|
|
281
|
+
counts = nmpy.asarray(counts)
|
|
282
|
+
if isinstance(x, int):
|
|
283
|
+
x, y = nmpy.meshgrid(range(x), range(y), indexing="ij")
|
|
284
|
+
if counts.ndim == 1:
|
|
285
|
+
x = x.ravel()
|
|
286
|
+
y = y.ravel()
|
|
287
|
+
|
|
288
|
+
width = kwargs.get("width", 0.8)
|
|
289
|
+
depth = kwargs.get("depth", 0.8)
|
|
290
|
+
offset = kwargs.get("offset", 0.0)
|
|
291
|
+
kwargs = {
|
|
292
|
+
_key: _vle
|
|
293
|
+
for _key, _vle in kwargs.items()
|
|
294
|
+
if _key not in ("width", "depth", "offset")
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return frame.bar3d(x, y, offset, width, depth, counts, **kwargs)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _BarH(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plots_t:
|
|
301
|
+
""""""
|
|
302
|
+
if args.__len__() == 1:
|
|
303
|
+
counts = args[0]
|
|
304
|
+
positions = range(counts.__len__())
|
|
305
|
+
else:
|
|
306
|
+
positions, counts = args
|
|
307
|
+
|
|
308
|
+
return frame.barh(positions, counts, **kwargs)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _BarV(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plots_t:
|
|
312
|
+
""""""
|
|
313
|
+
if args.__len__() == 1:
|
|
314
|
+
counts = args[0]
|
|
315
|
+
positions = range(counts.__len__())
|
|
316
|
+
else:
|
|
317
|
+
positions, counts = args
|
|
318
|
+
|
|
319
|
+
return frame.bar(positions, counts, **kwargs)
|
|
320
|
+
|
|
321
|
+
|
|
271
322
|
def _ElevationSurface(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
272
323
|
""""""
|
|
273
324
|
if args.__len__() == 1:
|
|
@@ -319,52 +370,14 @@ def _Mesh(
|
|
|
319
370
|
)
|
|
320
371
|
|
|
321
372
|
|
|
322
|
-
def
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
counts = args[0]
|
|
326
|
-
positions = range(counts.__len__())
|
|
327
|
-
else:
|
|
328
|
-
positions, counts = args
|
|
329
|
-
|
|
330
|
-
return frame.barh(positions, counts, **kwargs)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def _BarV(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plots_t:
|
|
334
|
-
""""""
|
|
335
|
-
if args.__len__() == 1:
|
|
336
|
-
counts = args[0]
|
|
337
|
-
positions = range(counts.__len__())
|
|
338
|
-
else:
|
|
339
|
-
positions, counts = args
|
|
340
|
-
|
|
341
|
-
return frame.bar(positions, counts, **kwargs)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
def _Bar3(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
373
|
+
def _Polygon(
|
|
374
|
+
frame: backend_frame_2d_t, xs: array_t, ys: array_t, *_, **kwargs
|
|
375
|
+
) -> polygon_t:
|
|
345
376
|
""""""
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
x, y = counts.shape
|
|
349
|
-
else:
|
|
350
|
-
x, y, counts = args
|
|
351
|
-
counts = nmpy.asarray(counts)
|
|
352
|
-
if isinstance(x, int):
|
|
353
|
-
x, y = nmpy.meshgrid(range(x), range(y), indexing="ij")
|
|
354
|
-
if counts.ndim == 1:
|
|
355
|
-
x = x.ravel()
|
|
356
|
-
y = y.ravel()
|
|
357
|
-
|
|
358
|
-
width = kwargs.get("width", 0.8)
|
|
359
|
-
depth = kwargs.get("depth", 0.8)
|
|
360
|
-
offset = kwargs.get("offset", 0.0)
|
|
361
|
-
kwargs = {
|
|
362
|
-
_key: _vle
|
|
363
|
-
for _key, _vle in kwargs.items()
|
|
364
|
-
if _key not in ("width", "depth", "offset")
|
|
365
|
-
}
|
|
377
|
+
output = polygon_t(nmpy.vstack((xs, ys)).T, **kwargs)
|
|
378
|
+
frame.add_patch(output)
|
|
366
379
|
|
|
367
|
-
return
|
|
380
|
+
return output
|
|
368
381
|
|
|
369
382
|
|
|
370
383
|
def _Text2(frame: backend_frame_2d_t, text, x, y, *_, **kwargs) -> backend_plot_t:
|
|
@@ -379,24 +392,23 @@ def _Text3(frame: backend_frame_2d_t, text, x, y, z, *_, **kwargs) -> backend_pl
|
|
|
379
392
|
|
|
380
393
|
PLOTS = plot_e.NewPlotsTemplate()
|
|
381
394
|
|
|
382
|
-
PLOTS[plot_e.SCATTER][1] = backend_frame_2d_t.scatter
|
|
383
|
-
PLOTS[plot_e.POLYLINE][1] = backend_frame_2d_t.plot
|
|
384
|
-
PLOTS[plot_e.POLYGON][1] = _Polygon
|
|
385
395
|
PLOTS[plot_e.ARROWS][1] = _Arrows2
|
|
386
|
-
PLOTS[plot_e.
|
|
396
|
+
PLOTS[plot_e.ARROWS][2] = _Arrows3
|
|
397
|
+
PLOTS[plot_e.BAR3][2] = _Bar3
|
|
387
398
|
PLOTS[plot_e.BARH][1] = _BarH
|
|
388
399
|
PLOTS[plot_e.BARV][1] = _BarV
|
|
389
|
-
PLOTS[plot_e.PIE][1] = backend_frame_2d_t.pie
|
|
390
|
-
PLOTS[plot_e.IMAGE][1] = backend_frame_2d_t.matshow
|
|
391
|
-
PLOTS[plot_e.TEXT][1] = _Text2
|
|
392
|
-
|
|
393
|
-
PLOTS[plot_e.SCATTER][2] = backend_frame_3d_t.scatter
|
|
394
|
-
PLOTS[plot_e.POLYLINE][2] = backend_frame_3d_t.plot
|
|
395
|
-
PLOTS[plot_e.ARROWS][2] = _Arrows3
|
|
396
400
|
PLOTS[plot_e.ELEVATION][2] = _ElevationSurface
|
|
401
|
+
PLOTS[plot_e.IMAGE][1] = backend_frame_2d_t.matshow
|
|
402
|
+
PLOTS[plot_e.ISOSET][1] = _IsoContour
|
|
397
403
|
PLOTS[plot_e.ISOSET][2] = _IsoSurface
|
|
398
404
|
PLOTS[plot_e.MESH][2] = _Mesh
|
|
399
|
-
PLOTS[plot_e.
|
|
405
|
+
PLOTS[plot_e.PIE][1] = backend_frame_2d_t.pie
|
|
406
|
+
PLOTS[plot_e.POLYGON][1] = _Polygon
|
|
407
|
+
PLOTS[plot_e.POLYLINE][1] = backend_frame_2d_t.plot
|
|
408
|
+
PLOTS[plot_e.POLYLINE][2] = backend_frame_3d_t.plot
|
|
409
|
+
PLOTS[plot_e.SCATTER][1] = backend_frame_2d_t.scatter
|
|
410
|
+
PLOTS[plot_e.SCATTER][2] = backend_frame_3d_t.scatter
|
|
411
|
+
PLOTS[plot_e.TEXT][1] = _Text2
|
|
400
412
|
PLOTS[plot_e.TEXT][2] = _Text3
|
|
401
413
|
|
|
402
414
|
|
|
@@ -407,7 +419,9 @@ TRANSLATIONS = {
|
|
|
407
419
|
"color_max": "vmax",
|
|
408
420
|
"color_min": "vmin",
|
|
409
421
|
"color_scaling": "norm",
|
|
422
|
+
"colormap": "cmap",
|
|
410
423
|
"depth_shade": "depthshade",
|
|
424
|
+
"opacity": "alpha",
|
|
411
425
|
"plot_non_finite": "plotnonfinite",
|
|
412
426
|
"size": "s",
|
|
413
427
|
"width_edge": "linewidths",
|
|
@@ -5,12 +5,15 @@ SEE COPYRIGHT NOTICE BELOW
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import dataclasses as d
|
|
8
|
+
import gzip
|
|
9
|
+
import typing as h
|
|
10
|
+
from multiprocessing import Process as process_t
|
|
8
11
|
from pathlib import Path as path_t
|
|
9
12
|
|
|
10
13
|
import numpy as nmpy
|
|
11
14
|
import plotly.figure_factory as fcry # noqa
|
|
12
15
|
import plotly.graph_objects as plly # noqa
|
|
13
|
-
from babelplot.task.showing import
|
|
16
|
+
from babelplot.task.showing import ShowHTMLWithPyQt
|
|
14
17
|
from babelplot.type.dimension import dim_e
|
|
15
18
|
from babelplot.type.figure import figure_t as base_figure_t
|
|
16
19
|
from babelplot.type.frame import frame_t as base_frame_t
|
|
@@ -64,8 +67,10 @@ class frame_t(base_frame_t):
|
|
|
64
67
|
|
|
65
68
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
66
69
|
class figure_t(base_figure_t):
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
|
|
71
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_t:
|
|
72
|
+
""""""
|
|
73
|
+
return backend_figure_t(*args, **kwargs)
|
|
69
74
|
|
|
70
75
|
def _NewFrame(
|
|
71
76
|
self,
|
|
@@ -128,7 +133,7 @@ class figure_t(base_figure_t):
|
|
|
128
133
|
if self.title is not None:
|
|
129
134
|
raw.update_layout(title_text=self.title + title_postfix)
|
|
130
135
|
|
|
131
|
-
def
|
|
136
|
+
def _BackendShow(self, modal: bool, /) -> None:
|
|
132
137
|
"""
|
|
133
138
|
Note on include_plotlyjs:
|
|
134
139
|
- "cdn": works but must be online.
|
|
@@ -136,35 +141,16 @@ class figure_t(base_figure_t):
|
|
|
136
141
|
PySide6.QtWebEngineWidgets.QWebEngineView.setHtml because of html size limit.
|
|
137
142
|
See note in babelplot.task.html.Show.
|
|
138
143
|
"""
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return plly.Scatter3d(x=x, y=y, z=z, mode="markers", **kwargs)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def _Polyline2(x: array_t, y: array_t, *_, **kwargs) -> backend_plot_t:
|
|
153
|
-
""""""
|
|
154
|
-
return plly.Scatter(x=x, y=y, mode="lines", **kwargs)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def _Polyline3(x: array_t, y: array_t, z: array_t, *_, **kwargs) -> backend_plot_t:
|
|
158
|
-
""""""
|
|
159
|
-
return plly.Scatter3d(x=x, y=y, z=z, mode="lines", **kwargs)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def _Polygon(x: array_t, y: array_t, *_, **kwargs) -> backend_plot_t:
|
|
163
|
-
""""""
|
|
164
|
-
x = nmpy.concatenate((x, [x[0]]))
|
|
165
|
-
y = nmpy.concatenate((y, [y[0]]))
|
|
166
|
-
|
|
167
|
-
return plly.Scatter(x=x, y=y, mode="lines", fill="toself", **kwargs)
|
|
144
|
+
html = self.raw.to_html(include_plotlyjs=True, config=_FIGURE_CONFIG)
|
|
145
|
+
uid = id(self)
|
|
146
|
+
if modal:
|
|
147
|
+
ShowHTMLWithPyQt(html, uid)
|
|
148
|
+
self.AcknowledgeClosure()
|
|
149
|
+
else:
|
|
150
|
+
html = gzip.compress(html.encode())
|
|
151
|
+
process = process_t(target=lambda: ShowHTMLWithPyQt(html, uid))
|
|
152
|
+
process.start()
|
|
153
|
+
self.showing_process = process
|
|
168
154
|
|
|
169
155
|
|
|
170
156
|
def _Arrows2(*args, **kwargs) -> backend_plot_t:
|
|
@@ -205,105 +191,6 @@ def _Arrows3(*args, **kwargs) -> backend_plot_t:
|
|
|
205
191
|
)
|
|
206
192
|
|
|
207
193
|
|
|
208
|
-
def _ElevationSurface(*args, **kwargs) -> backend_plot_t:
|
|
209
|
-
""""""
|
|
210
|
-
if args.__len__() == 1:
|
|
211
|
-
elevation = args[0]
|
|
212
|
-
x, y = nmpy.meshgrid(
|
|
213
|
-
range(elevation.shape[0]), range(elevation.shape[1]), indexing="ij"
|
|
214
|
-
)
|
|
215
|
-
else:
|
|
216
|
-
x, y, elevation = args
|
|
217
|
-
|
|
218
|
-
return plly.Surface(contours={}, x=x, y=y, z=elevation, **kwargs)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def _IsoContour(*args, **kwargs) -> backend_plot_t:
|
|
222
|
-
""""""
|
|
223
|
-
parameters = {
|
|
224
|
-
"contours_coloring": "lines",
|
|
225
|
-
"line_width": 2,
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if args.__len__() == 2:
|
|
229
|
-
values, value = args
|
|
230
|
-
else:
|
|
231
|
-
x, y, values, value = args
|
|
232
|
-
parameters["x"] = x
|
|
233
|
-
parameters["y"] = y
|
|
234
|
-
parameters["z"] = values
|
|
235
|
-
parameters["contours"] = {
|
|
236
|
-
"start": value,
|
|
237
|
-
"end": value,
|
|
238
|
-
"size": 1,
|
|
239
|
-
"showlabels": True,
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
parameters.update(kwargs)
|
|
243
|
-
|
|
244
|
-
return plly.Contour(**parameters)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def _IsoSurface(values: array_t, value: float, *args, **kwargs) -> backend_plot_t:
|
|
248
|
-
""""""
|
|
249
|
-
if args.__len__() == 3:
|
|
250
|
-
x, y, z = args
|
|
251
|
-
else:
|
|
252
|
-
x, y, z = nmpy.meshgrid(
|
|
253
|
-
range(values.shape[0]),
|
|
254
|
-
range(values.shape[1]),
|
|
255
|
-
range(values.shape[2]),
|
|
256
|
-
indexing="ij",
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
parameters = {
|
|
260
|
-
"surface": {"count": 1},
|
|
261
|
-
"caps": {"x_show": False, "y_show": False, "z_show": False},
|
|
262
|
-
}
|
|
263
|
-
parameters.update(kwargs)
|
|
264
|
-
|
|
265
|
-
return plly.Isosurface(
|
|
266
|
-
x=x.ravel(),
|
|
267
|
-
y=y.ravel(),
|
|
268
|
-
z=z.ravel(),
|
|
269
|
-
value=values.ravel(),
|
|
270
|
-
isomin=value,
|
|
271
|
-
isomax=value,
|
|
272
|
-
**parameters,
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) -> backend_plot_t:
|
|
277
|
-
""""""
|
|
278
|
-
return plly.Mesh3d(
|
|
279
|
-
x=vertices[:, 0],
|
|
280
|
-
y=vertices[:, 1],
|
|
281
|
-
z=vertices[:, 2],
|
|
282
|
-
i=triangles[:, 0],
|
|
283
|
-
j=triangles[:, 1],
|
|
284
|
-
k=triangles[:, 2],
|
|
285
|
-
**kwargs,
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
def _BarH(*args, **kwargs) -> backend_plot_t:
|
|
290
|
-
""""""
|
|
291
|
-
return _BarV(*args, orientation="h", **kwargs)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def _BarV(*args, **kwargs) -> backend_plot_t:
|
|
295
|
-
""""""
|
|
296
|
-
if args.__len__() == 1:
|
|
297
|
-
counts = args[0]
|
|
298
|
-
positions = tuple(range(counts.__len__()))
|
|
299
|
-
else:
|
|
300
|
-
positions, counts = args
|
|
301
|
-
if kwargs.get("orientation") == "h":
|
|
302
|
-
positions, counts = counts, positions
|
|
303
|
-
|
|
304
|
-
return plly.Bar(x=positions, y=counts, **kwargs)
|
|
305
|
-
|
|
306
|
-
|
|
307
194
|
def _Bar3(*args, **kwargs) -> backend_plot_t:
|
|
308
195
|
""""""
|
|
309
196
|
if args.__len__() == 1:
|
|
@@ -406,9 +293,35 @@ def _Bar3(*args, **kwargs) -> backend_plot_t:
|
|
|
406
293
|
)
|
|
407
294
|
|
|
408
295
|
|
|
409
|
-
def
|
|
296
|
+
def _BarH(*args, **kwargs) -> backend_plot_t:
|
|
410
297
|
""""""
|
|
411
|
-
return
|
|
298
|
+
return _BarV(*args, orientation="h", **kwargs)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _BarV(*args, **kwargs) -> backend_plot_t:
|
|
302
|
+
""""""
|
|
303
|
+
if args.__len__() == 1:
|
|
304
|
+
counts = args[0]
|
|
305
|
+
positions = tuple(range(counts.__len__()))
|
|
306
|
+
else:
|
|
307
|
+
positions, counts = args
|
|
308
|
+
if kwargs.get("orientation") == "h":
|
|
309
|
+
positions, counts = counts, positions
|
|
310
|
+
|
|
311
|
+
return plly.Bar(x=positions, y=counts, **kwargs)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _ElevationSurface(*args, **kwargs) -> backend_plot_t:
|
|
315
|
+
""""""
|
|
316
|
+
if args.__len__() == 1:
|
|
317
|
+
elevation = args[0]
|
|
318
|
+
x, y = nmpy.meshgrid(
|
|
319
|
+
range(elevation.shape[0]), range(elevation.shape[1]), indexing="ij"
|
|
320
|
+
)
|
|
321
|
+
else:
|
|
322
|
+
x, y, elevation = args
|
|
323
|
+
|
|
324
|
+
return plly.Surface(contours={}, x=x, y=y, z=elevation, **kwargs)
|
|
412
325
|
|
|
413
326
|
|
|
414
327
|
def _Image(image: array_t, *_, **kwargs) -> backend_plot_t:
|
|
@@ -419,6 +332,107 @@ def _Image(image: array_t, *_, **kwargs) -> backend_plot_t:
|
|
|
419
332
|
return plly.Image(z=image, **kwargs)
|
|
420
333
|
|
|
421
334
|
|
|
335
|
+
def _IsoContour(*args, **kwargs) -> backend_plot_t:
|
|
336
|
+
""""""
|
|
337
|
+
parameters = {
|
|
338
|
+
"contours_coloring": "lines",
|
|
339
|
+
"line_width": 2,
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if args.__len__() == 2:
|
|
343
|
+
values, value = args
|
|
344
|
+
else:
|
|
345
|
+
x, y, values, value = args
|
|
346
|
+
parameters["x"] = x
|
|
347
|
+
parameters["y"] = y
|
|
348
|
+
parameters["z"] = values
|
|
349
|
+
parameters["contours"] = {
|
|
350
|
+
"start": value,
|
|
351
|
+
"end": value,
|
|
352
|
+
"size": 1,
|
|
353
|
+
"showlabels": True,
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
parameters.update(kwargs)
|
|
357
|
+
|
|
358
|
+
return plly.Contour(**parameters)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _IsoSurface(values: array_t, value: float, *args, **kwargs) -> backend_plot_t:
|
|
362
|
+
""""""
|
|
363
|
+
if args.__len__() == 3:
|
|
364
|
+
x, y, z = args
|
|
365
|
+
else:
|
|
366
|
+
x, y, z = nmpy.meshgrid(
|
|
367
|
+
range(values.shape[0]),
|
|
368
|
+
range(values.shape[1]),
|
|
369
|
+
range(values.shape[2]),
|
|
370
|
+
indexing="ij",
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
parameters = {
|
|
374
|
+
"surface": {"count": 1},
|
|
375
|
+
"caps": {"x_show": False, "y_show": False, "z_show": False},
|
|
376
|
+
}
|
|
377
|
+
parameters.update(kwargs)
|
|
378
|
+
|
|
379
|
+
return plly.Isosurface(
|
|
380
|
+
x=x.ravel(),
|
|
381
|
+
y=y.ravel(),
|
|
382
|
+
z=z.ravel(),
|
|
383
|
+
value=values.ravel(),
|
|
384
|
+
isomin=value,
|
|
385
|
+
isomax=value,
|
|
386
|
+
**parameters,
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) -> backend_plot_t:
|
|
391
|
+
""""""
|
|
392
|
+
return plly.Mesh3d(
|
|
393
|
+
x=vertices[:, 0],
|
|
394
|
+
y=vertices[:, 1],
|
|
395
|
+
z=vertices[:, 2],
|
|
396
|
+
i=triangles[:, 0],
|
|
397
|
+
j=triangles[:, 1],
|
|
398
|
+
k=triangles[:, 2],
|
|
399
|
+
**kwargs,
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _Pie(values: array_t, *_, **kwargs) -> backend_plot_t:
|
|
404
|
+
""""""
|
|
405
|
+
return plly.Pie(values=values, **kwargs)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _Polygon(x: array_t, y: array_t, *_, **kwargs) -> backend_plot_t:
|
|
409
|
+
""""""
|
|
410
|
+
x = nmpy.concatenate((x, [x[0]]))
|
|
411
|
+
y = nmpy.concatenate((y, [y[0]]))
|
|
412
|
+
|
|
413
|
+
return plly.Scatter(x=x, y=y, mode="lines", fill="toself", **kwargs)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def _Polyline2(x: array_t, y: array_t, *_, **kwargs) -> backend_plot_t:
|
|
417
|
+
""""""
|
|
418
|
+
return plly.Scatter(x=x, y=y, mode="lines", **kwargs)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _Polyline3(x: array_t, y: array_t, z: array_t, *_, **kwargs) -> backend_plot_t:
|
|
422
|
+
""""""
|
|
423
|
+
return plly.Scatter3d(x=x, y=y, z=z, mode="lines", **kwargs)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _Scatter2(x: array_t, y: array_t, *_, **kwargs) -> backend_plot_t:
|
|
427
|
+
""""""
|
|
428
|
+
return plly.Scatter(x=x, y=y, mode="markers", **kwargs)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def _Scatter3(x: array_t, y: array_t, z: array_t, *_, **kwargs) -> backend_plot_t:
|
|
432
|
+
""""""
|
|
433
|
+
return plly.Scatter3d(x=x, y=y, z=z, mode="markers", **kwargs)
|
|
434
|
+
|
|
435
|
+
|
|
422
436
|
def _Text2(text: str, x: float, y: float, *_, **kwargs) -> backend_plot_t:
|
|
423
437
|
""""""
|
|
424
438
|
parameters = {"textposition": "top right"}
|
|
@@ -444,32 +458,91 @@ def _Text3(text: str, x: float, y: float, z: float, *_, **kwargs) -> backend_plo
|
|
|
444
458
|
|
|
445
459
|
PLOTS = plot_e.NewPlotsTemplate()
|
|
446
460
|
|
|
447
|
-
PLOTS[plot_e.SCATTER][1] = _Scatter2
|
|
448
|
-
PLOTS[plot_e.POLYLINE][1] = _Polyline2
|
|
449
|
-
PLOTS[plot_e.POLYGON][1] = _Polygon
|
|
450
461
|
PLOTS[plot_e.ARROWS][1] = _Arrows2
|
|
451
|
-
PLOTS[plot_e.
|
|
462
|
+
PLOTS[plot_e.ARROWS][2] = _Arrows3
|
|
463
|
+
PLOTS[plot_e.BAR3][2] = _Bar3
|
|
452
464
|
PLOTS[plot_e.BARH][1] = _BarH
|
|
453
465
|
PLOTS[plot_e.BARV][1] = _BarV
|
|
454
|
-
PLOTS[plot_e.PIE][1] = _Pie
|
|
455
|
-
PLOTS[plot_e.IMAGE][1] = _Image
|
|
456
|
-
PLOTS[plot_e.TEXT][1] = _Text2
|
|
457
|
-
|
|
458
|
-
PLOTS[plot_e.SCATTER][2] = _Scatter3
|
|
459
|
-
PLOTS[plot_e.POLYLINE][2] = _Polyline3
|
|
460
|
-
PLOTS[plot_e.ARROWS][2] = _Arrows3
|
|
461
466
|
PLOTS[plot_e.ELEVATION][2] = _ElevationSurface
|
|
467
|
+
PLOTS[plot_e.IMAGE][1] = _Image
|
|
468
|
+
PLOTS[plot_e.ISOSET][1] = _IsoContour
|
|
462
469
|
PLOTS[plot_e.ISOSET][2] = _IsoSurface
|
|
463
470
|
PLOTS[plot_e.MESH][2] = _Mesh
|
|
464
|
-
PLOTS[plot_e.
|
|
471
|
+
PLOTS[plot_e.PIE][1] = _Pie
|
|
472
|
+
PLOTS[plot_e.POLYGON][1] = _Polygon
|
|
473
|
+
PLOTS[plot_e.POLYLINE][1] = _Polyline2
|
|
474
|
+
PLOTS[plot_e.POLYLINE][2] = _Polyline3
|
|
475
|
+
PLOTS[plot_e.SCATTER][1] = _Scatter2
|
|
476
|
+
PLOTS[plot_e.SCATTER][2] = _Scatter3
|
|
477
|
+
PLOTS[plot_e.TEXT][1] = _Text2
|
|
465
478
|
PLOTS[plot_e.TEXT][2] = _Text3
|
|
466
479
|
|
|
467
480
|
|
|
481
|
+
def _ApplyGlobalTranslation(
|
|
482
|
+
kwargs: dict[str, h.Any], who_s_asking: str | h.Callable | None, /
|
|
483
|
+
) -> None:
|
|
484
|
+
""""""
|
|
485
|
+
if who_s_asking in (_Scatter2, _Scatter3):
|
|
486
|
+
marker = {}
|
|
487
|
+
for passed, wanted in zip(
|
|
488
|
+
("color", "opacity", "size", "shape"),
|
|
489
|
+
("color", "opacity", "size", "symbol"),
|
|
490
|
+
):
|
|
491
|
+
if (value := kwargs.get(passed)) is not None:
|
|
492
|
+
marker[wanted] = value
|
|
493
|
+
del kwargs[passed]
|
|
494
|
+
if who_s_asking is _Scatter3:
|
|
495
|
+
# /!\\ Passing one size per sample makes all of them disappear.
|
|
496
|
+
if ("size" in marker) and not isinstance(marker["size"], int | float):
|
|
497
|
+
marker["size"] = 0.5 * (min(marker["size"]) + max(marker["size"]))
|
|
498
|
+
# /!\\ Opacity seems to be all-or-nothing.
|
|
499
|
+
if "opacity" in marker:
|
|
500
|
+
del marker["opacity"]
|
|
501
|
+
|
|
502
|
+
kwargs["marker"] = marker
|
|
503
|
+
#
|
|
504
|
+
elif who_s_asking in (_Arrows2, _Polyline2, _Polyline3):
|
|
505
|
+
line = {}
|
|
506
|
+
for passed, wanted in zip(
|
|
507
|
+
("color", "opacity", "line_width", "line_style"),
|
|
508
|
+
("color", "opacity", "width", "symbol"),
|
|
509
|
+
):
|
|
510
|
+
if (value := kwargs.get(passed)) is not None:
|
|
511
|
+
line[wanted] = value
|
|
512
|
+
del kwargs[passed]
|
|
513
|
+
|
|
514
|
+
kwargs["line"] = line
|
|
515
|
+
#
|
|
516
|
+
elif who_s_asking is _Pie:
|
|
517
|
+
marker = {}
|
|
518
|
+
for passed, wanted in zip(("color",), ("colors",)):
|
|
519
|
+
if (value := kwargs.get(passed)) is not None:
|
|
520
|
+
marker[wanted] = value
|
|
521
|
+
del kwargs[passed]
|
|
522
|
+
|
|
523
|
+
kwargs["marker"] = marker
|
|
524
|
+
|
|
525
|
+
|
|
468
526
|
TRANSLATIONS = {
|
|
469
|
-
"alpha": "opacity",
|
|
470
527
|
"color_face": "surfacecolor",
|
|
528
|
+
(_Arrows3, "color"): None,
|
|
529
|
+
(_BarH, "color"): None,
|
|
530
|
+
(_BarV, "color"): None,
|
|
531
|
+
(_ElevationSurface, "color_edge"): None,
|
|
532
|
+
(_ElevationSurface, "color_face"): None,
|
|
533
|
+
(_ElevationSurface, "width_edge"): None,
|
|
534
|
+
(_Image, "colormap"): None,
|
|
535
|
+
(_IsoContour, "color"): "fillcolor",
|
|
536
|
+
(_IsoSurface, "color_edge"): None,
|
|
471
537
|
(_IsoSurface, "color_face"): None,
|
|
538
|
+
(_IsoSurface, "step_size"): None,
|
|
539
|
+
(_IsoSurface, "width_edge"): None,
|
|
540
|
+
(_Mesh, "color_edge"): None,
|
|
472
541
|
(_Mesh, "color_face"): "facecolor",
|
|
542
|
+
(_Mesh, "width_edge"): None,
|
|
543
|
+
(_Polygon, "color_edge"): None,
|
|
544
|
+
(_Polygon, "color_face"): "fillcolor",
|
|
545
|
+
None: _ApplyGlobalTranslation,
|
|
473
546
|
}
|
|
474
547
|
|
|
475
548
|
|
|
@@ -51,7 +51,10 @@ class frame_t(base_frame_t):
|
|
|
51
51
|
|
|
52
52
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
53
53
|
class figure_t(base_figure_t):
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_t:
|
|
56
|
+
""""""
|
|
57
|
+
return backend_figure_t(*args, **kwargs)
|
|
55
58
|
|
|
56
59
|
def _NewFrame(
|
|
57
60
|
self,
|
|
@@ -4,31 +4,33 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
|
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import gzip
|
|
7
8
|
import os as osys
|
|
8
9
|
import sys as s
|
|
9
10
|
import tempfile as tmpf
|
|
10
11
|
|
|
11
12
|
from babelplot.constant.project import NAME
|
|
12
13
|
from babelplot.runtime.figure import SHOWN_FIGURES, UN_SHOWN_FIGURES
|
|
13
|
-
from babelplot.type.figure import figure_t
|
|
14
14
|
from PyQt6.QtCore import QUrl as url_t
|
|
15
15
|
from PyQt6.QtWebEngineWidgets import QWebEngineView as widget_t
|
|
16
16
|
from PyQt6.QtWidgets import QApplication as application_t
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def
|
|
19
|
+
def ShowHTMLWithPyQt(html: str | bytes, uid: int, /) -> None:
|
|
20
20
|
""""""
|
|
21
|
+
if isinstance(html, bytes):
|
|
22
|
+
html = gzip.decompress(html).decode()
|
|
23
|
+
|
|
21
24
|
# The application must be instantiated in the same thread/process as the one running
|
|
22
25
|
# exec().
|
|
23
26
|
if (application := application_t.instance()) is None:
|
|
24
27
|
application = application_t(s.argv)
|
|
25
|
-
application.setApplicationName(f"{NAME}-{
|
|
26
|
-
widget = widget_t()
|
|
28
|
+
application.setApplicationName(f"{NAME}-{uid}")
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
widget.loadFinished.connect(
|
|
31
|
-
widget.setHtml(html)
|
|
30
|
+
widget = widget_t()
|
|
31
|
+
SetURLIfNeeded = lambda _: _SetURLIfNeeded(_, html, widget, application)
|
|
32
|
+
widget.loadFinished.connect(SetURLIfNeeded)
|
|
33
|
+
widget.setHtml(html) # Now attempt to set HTML; If failure, then SetURLIfNeeded.
|
|
32
34
|
|
|
33
35
|
widget.show()
|
|
34
36
|
application.exec()
|
|
@@ -39,35 +41,34 @@ def ShowAllFigures(
|
|
|
39
41
|
modal: bool = True,
|
|
40
42
|
) -> None:
|
|
41
43
|
""""""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
SHOWN_FIGURES.extend(UN_SHOWN_FIGURES) # /!\ Must be removed when closed.
|
|
48
|
-
UN_SHOWN_FIGURES.clear()
|
|
49
|
-
|
|
50
|
-
import matplotlib.pyplot as pypl # noqa
|
|
44
|
+
n_figures = UN_SHOWN_FIGURES.__len__()
|
|
45
|
+
while n_figures > 0:
|
|
46
|
+
UN_SHOWN_FIGURES[0].Show(modal=modal and (n_figures == 1))
|
|
47
|
+
n_figures -= 1
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
else:
|
|
54
|
-
while UN_SHOWN_FIGURES.__len__() > 1:
|
|
55
|
-
UN_SHOWN_FIGURES[0].Show(modal=False)
|
|
56
|
-
if UN_SHOWN_FIGURES.__len__() > 0:
|
|
57
|
-
UN_SHOWN_FIGURES[0].Show(modal=modal)
|
|
49
|
+
assert UN_SHOWN_FIGURES.__len__() == 0
|
|
58
50
|
|
|
51
|
+
if modal:
|
|
52
|
+
WaitForAllFiguresToBeClosed()
|
|
59
53
|
|
|
60
|
-
# def CloseFigure(figure: figure_t, /)->None:
|
|
61
|
-
# """"""
|
|
62
54
|
|
|
55
|
+
def WaitForAllFiguresToBeClosed() -> None:
|
|
56
|
+
""""""
|
|
57
|
+
if SHOWN_FIGURES.__len__() == 0:
|
|
58
|
+
return
|
|
63
59
|
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
with_processes = tuple(_ for _ in SHOWN_FIGURES if _.showing_process is not None)
|
|
61
|
+
for figure in with_processes:
|
|
62
|
+
figure.showing_process.join()
|
|
63
|
+
figure.AcknowledgeClosure()
|
|
66
64
|
|
|
67
65
|
|
|
68
|
-
def
|
|
66
|
+
def _SetURLIfNeeded(
|
|
67
|
+
success: bool, html: str, widget: widget_t, application: application_t, /
|
|
68
|
+
) -> None:
|
|
69
69
|
"""
|
|
70
|
-
From: https://doc.qt.io/qtforpython-6/PySide6/QtWebEngineWidgets/QWebEngineView.html
|
|
70
|
+
From: https://doc.qt.io/qtforpython-6/PySide6/QtWebEngineWidgets/QWebEngineView.html
|
|
71
|
+
#PySide6.QtWebEngineWidgets.PySide6.QtWebEngineWidgets.QWebEngineView.setHtml
|
|
71
72
|
Content larger than 2 MB cannot be displayed...
|
|
72
73
|
...
|
|
73
74
|
Thereby, the provided code becomes a URL that exceeds the 2 MB limit set by
|
|
@@ -82,9 +83,11 @@ def _SetHTMLFromFile(success: bool, widget: widget_t, html: str, /) -> None:
|
|
|
82
83
|
with open(transfer.name, "w") as accessor:
|
|
83
84
|
accessor.write(html)
|
|
84
85
|
url = url_t.fromLocalFile(transfer.name)
|
|
86
|
+
|
|
85
87
|
widget.setUrl(url)
|
|
88
|
+
|
|
86
89
|
DeleteTemporaryFile = lambda: osys.remove(transfer.name)
|
|
87
|
-
|
|
90
|
+
application.lastWindowClosed.connect(DeleteTemporaryFile)
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
"""
|
|
@@ -74,25 +74,42 @@ class backend_t:
|
|
|
74
74
|
out_kwargs = {}
|
|
75
75
|
|
|
76
76
|
for idx, value in enumerate(args):
|
|
77
|
-
if (translation := translations.get((who_s_asking, idx)))
|
|
78
|
-
#
|
|
77
|
+
if (translation := translations.get((who_s_asking, idx), -1)) == -1:
|
|
78
|
+
# No translation needed; Keeping the passed arg.
|
|
79
79
|
out_args.append(value)
|
|
80
|
-
|
|
80
|
+
elif translation is None:
|
|
81
|
+
# The argument should be discarded.
|
|
82
|
+
pass
|
|
83
|
+
else: # isinstance(translation, str)
|
|
81
84
|
# The passed arg should actually be a kwarg with name "translation".
|
|
82
85
|
out_kwargs[translation] = value
|
|
83
86
|
|
|
84
87
|
from_kwargs_to_args = []
|
|
85
88
|
for key, value in kwargs.items():
|
|
86
89
|
# Search for specific translation (who_s_asking, key) before key alone.
|
|
87
|
-
if (translation := translations.get((who_s_asking, key)))
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
if (translation := translations.get((who_s_asking, key), -1)) == -1:
|
|
91
|
+
if (translation := translations.get(key, -1)) == -1:
|
|
92
|
+
# No translation needed; Keeping the passed arg.
|
|
93
|
+
out_kwargs[key] = value
|
|
94
|
+
elif translation is None:
|
|
95
|
+
# The argument should be discarded.
|
|
96
|
+
pass
|
|
97
|
+
else: # isinstance(translation, str)
|
|
98
|
+
out_kwargs[translation] = value
|
|
99
|
+
elif translation is None:
|
|
100
|
+
# The argument should be discarded.
|
|
101
|
+
pass
|
|
102
|
+
elif isinstance(translation, str):
|
|
92
103
|
out_kwargs[translation] = value
|
|
93
|
-
|
|
104
|
+
else: # isinstance(translation, int)
|
|
105
|
+
from_kwargs_to_args.append((translation, value))
|
|
106
|
+
|
|
107
|
+
for idx, value in sorted(from_kwargs_to_args, key=ItemAt(0)):
|
|
94
108
|
out_args.insert(idx, value)
|
|
95
109
|
|
|
110
|
+
if (ApplyGlobalTranslation := translations.get(None)) is not None:
|
|
111
|
+
ApplyGlobalTranslation(out_kwargs, who_s_asking)
|
|
112
|
+
|
|
96
113
|
return out_args, out_kwargs
|
|
97
114
|
|
|
98
115
|
def __str__(self) -> str:
|
|
@@ -30,6 +30,7 @@ class figure_t(base_t):
|
|
|
30
30
|
frames: list[frame_t] = d.field(init=False, default_factory=list)
|
|
31
31
|
locations: list[tuple[int, int]] = d.field(init=False, default_factory=list)
|
|
32
32
|
shape: list[int] = d.field(init=False, default_factory=_DefaultShape)
|
|
33
|
+
showing_process: process_t | None = d.field(init=False, default=None)
|
|
33
34
|
|
|
34
35
|
def __post_init__(self) -> None:
|
|
35
36
|
""""""
|
|
@@ -62,8 +63,7 @@ class figure_t(base_t):
|
|
|
62
63
|
|
|
63
64
|
return output
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
def _NewBackendFigure(*args, **kwargs) -> backend_figure_h:
|
|
66
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_h:
|
|
67
67
|
""""""
|
|
68
68
|
raise NotImplementedError
|
|
69
69
|
|
|
@@ -180,10 +180,6 @@ class figure_t(base_t):
|
|
|
180
180
|
""""""
|
|
181
181
|
raise NotImplementedError
|
|
182
182
|
|
|
183
|
-
def AsHTML(self) -> str:
|
|
184
|
-
""""""
|
|
185
|
-
raise NotImplementedError
|
|
186
|
-
|
|
187
183
|
def Clear(self) -> None:
|
|
188
184
|
""""""
|
|
189
185
|
# Do not use a for-loop since self.frames will be modified during looping.
|
|
@@ -211,16 +207,20 @@ class figure_t(base_t):
|
|
|
211
207
|
SHOWN_FIGURES.append(self) # /!\ Must be removed when closed.
|
|
212
208
|
UN_SHOWN_FIGURES.remove(self)
|
|
213
209
|
|
|
214
|
-
|
|
215
|
-
self._BackendShow()
|
|
216
|
-
else:
|
|
217
|
-
thread = process_t(target=lambda: self._BackendShow())
|
|
218
|
-
thread.start()
|
|
210
|
+
self._BackendShow(modal)
|
|
219
211
|
|
|
220
|
-
def _BackendShow(self) -> None:
|
|
212
|
+
def _BackendShow(self, modal: bool, /) -> None:
|
|
221
213
|
""""""
|
|
222
214
|
raise NotImplementedError
|
|
223
215
|
|
|
216
|
+
def AcknowledgeClosure(self) -> None:
|
|
217
|
+
""""""
|
|
218
|
+
if self in SHOWN_FIGURES:
|
|
219
|
+
SHOWN_FIGURES.remove(self)
|
|
220
|
+
else:
|
|
221
|
+
assert self in UN_SHOWN_FIGURES
|
|
222
|
+
UN_SHOWN_FIGURES.remove(self)
|
|
223
|
+
|
|
224
224
|
|
|
225
225
|
"""
|
|
226
226
|
COPYRIGHT NOTICE
|
|
@@ -145,10 +145,10 @@ class plot_e(enum_t):
|
|
|
145
145
|
)
|
|
146
146
|
SCATTER = (
|
|
147
147
|
"Set of Points",
|
|
148
|
-
"A set of points
|
|
148
|
+
"A set of points (X, Y) or (X, Y, Z) depending on the dimension. They are plotted using a so-called "
|
|
149
149
|
"marker.\n"
|
|
150
150
|
"Required arguments: X coordinates, Y coordinates, Z coordinates (depending on the dimension).",
|
|
151
|
-
(
|
|
151
|
+
(2, 3),
|
|
152
152
|
)
|
|
153
153
|
TEXT = (
|
|
154
154
|
"Text annotation",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|