babelplot 2025.11__tar.gz → 2025.13__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.11 → babelplot-2025.13}/PKG-INFO +1 -1
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/catalog/bokeh_.py +71 -15
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/catalog/matplotlib_.py +57 -37
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/catalog/plotly_.py +46 -27
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/catalog/vedo_.py +105 -29
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/task/plotting.py +3 -4
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/backend.py +44 -21
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/figure.py +2 -2
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/frame.py +4 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/plot.py +24 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/version.py +1 -1
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot.egg-info/PKG-INFO +1 -1
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot.egg-info/SOURCES.txt +0 -1
- babelplot-2025.11/package/babelplot/task/color.py +0 -112
- {babelplot-2025.11 → babelplot-2025.13}/MANIFEST.in +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/README-COPYRIGHT-utf8.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/README-LICENCE-utf8.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/README.rst +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/documentation/wiki/description.asciidoc +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/__init__.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/api/type.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/helper/creation.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/backend/helper/validation.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/constant/backend.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/constant/path.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/constant/project.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/extension/enum_.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/extension/function.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/runtime/backends.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/task/help.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/task/instantiation.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/task/showing.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/dimension.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/ffp_base.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/plot_function.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/plot_type.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot/type/translator.py +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot.egg-info/dependency_links.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot.egg-info/requires.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/package/babelplot.egg-info/top_level.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/pyproject.toml +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/requirements.txt +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/setup.cfg +0 -0
- {babelplot-2025.11 → babelplot-2025.13}/setup.py +0 -0
|
@@ -9,6 +9,7 @@ import gzip
|
|
|
9
9
|
import typing as h
|
|
10
10
|
from multiprocessing import Process as process_t
|
|
11
11
|
|
|
12
|
+
import numpy as nmpy
|
|
12
13
|
from babelplot.task.plotting import NewPlotFunctionsTemplate, SetDefaultPlotFunction
|
|
13
14
|
from babelplot.task.showing import ShowHTMLPlotWithPyQt
|
|
14
15
|
from babelplot.type.dimension import dim_e
|
|
@@ -16,7 +17,7 @@ from babelplot.type.figure import figure_t as base_figure_t
|
|
|
16
17
|
from babelplot.type.frame import frame_t as base_frame_t
|
|
17
18
|
from babelplot.type.plot import plot_t as base_plot_t
|
|
18
19
|
from babelplot.type.plot_function import plot_function_h
|
|
19
|
-
from babelplot.type.plot_type import plot_e
|
|
20
|
+
from babelplot.type.plot_type import plot_e, plot_type_h
|
|
20
21
|
from bokeh.embed import file_html as HTMLofBackendContent # noqa
|
|
21
22
|
from bokeh.layouts import column as NewBackendColLayout # noqa
|
|
22
23
|
from bokeh.layouts import grid as NewBackendGridLayout # noqa
|
|
@@ -27,6 +28,8 @@ from bokeh.resources import INLINE # noqa
|
|
|
27
28
|
|
|
28
29
|
NAME = "bokeh"
|
|
29
30
|
|
|
31
|
+
array_t = nmpy.ndarray
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
class backend_figure_t: ...
|
|
32
35
|
|
|
@@ -43,6 +46,7 @@ class frame_t(base_frame_t):
|
|
|
43
46
|
plot_function: plot_function_h,
|
|
44
47
|
*args,
|
|
45
48
|
title: str | None = None, # If _, then it is swallowed by kwargs!
|
|
49
|
+
type_: tuple[plot_type_h | plot_function_h, int],
|
|
46
50
|
**kwargs,
|
|
47
51
|
) -> plot_t:
|
|
48
52
|
""""""
|
|
@@ -59,9 +63,9 @@ class figure_t(base_figure_t):
|
|
|
59
63
|
|
|
60
64
|
layout: h.Any = d.field(init=False, default=None)
|
|
61
65
|
|
|
62
|
-
def _NewBackendFigure(self, *args, **kwargs) ->
|
|
66
|
+
def _NewBackendFigure(self, *args, **kwargs) -> None:
|
|
63
67
|
""""""
|
|
64
|
-
return
|
|
68
|
+
return None
|
|
65
69
|
|
|
66
70
|
def _NewFrame(
|
|
67
71
|
self,
|
|
@@ -85,7 +89,7 @@ class figure_t(base_figure_t):
|
|
|
85
89
|
# arranged_frames must be composed of list since Bokeh does not support tuples
|
|
86
90
|
# here!
|
|
87
91
|
n_rows, n_cols = self.shape
|
|
88
|
-
arranged_frames = [n_cols * [None] for _ in range(n_rows)]
|
|
92
|
+
arranged_frames: list[list[h.Any]] = [n_cols * [None] for _ in range(n_rows)]
|
|
89
93
|
for frame, (row, col) in zip(self.frames, self.locations):
|
|
90
94
|
raw = frame.raw
|
|
91
95
|
if raw.renderers.__len__() == 0:
|
|
@@ -153,18 +157,15 @@ def _DefaultFunction(type_: plot_e, frame_dim: int, /) -> plot_function_h:
|
|
|
153
157
|
""""""
|
|
154
158
|
|
|
155
159
|
def Actual(frame: backend_frame_t, *args, **kwargs) -> backend_plot_t:
|
|
156
|
-
|
|
157
|
-
args = ", ".join(map(lambda _: type(_).__name__, args))
|
|
158
|
-
kwargs = ", ".join(
|
|
159
|
-
f"{_key}={type(_vle).__name__}" for _key, _vle in kwargs.items()
|
|
160
|
-
)
|
|
161
|
-
|
|
160
|
+
#
|
|
162
161
|
return backend_frame_t.text(
|
|
163
162
|
frame,
|
|
164
163
|
x=(0,),
|
|
165
164
|
y=(0,),
|
|
166
165
|
text=(
|
|
167
|
-
|
|
166
|
+
plot_t.UnhandledRequestMessage(
|
|
167
|
+
type_, *args, frame_dim=frame_dim, **kwargs
|
|
168
|
+
),
|
|
168
169
|
),
|
|
169
170
|
text_font_size="30px",
|
|
170
171
|
text_align="center",
|
|
@@ -174,16 +175,71 @@ def _DefaultFunction(type_: plot_e, frame_dim: int, /) -> plot_function_h:
|
|
|
174
175
|
return Actual
|
|
175
176
|
|
|
176
177
|
|
|
178
|
+
def _BarH(frame: backend_frame_t, *args, **kwargs) -> backend_plot_t:
|
|
179
|
+
""""""
|
|
180
|
+
if args.__len__() == 1:
|
|
181
|
+
counts = args[0]
|
|
182
|
+
positions = tuple(range(counts.__len__()))
|
|
183
|
+
else:
|
|
184
|
+
positions, counts = args
|
|
185
|
+
|
|
186
|
+
return frame.hbar(y=positions, right=counts, **kwargs)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _BarV(frame: backend_frame_t, *args, **kwargs) -> backend_plot_t:
|
|
190
|
+
""""""
|
|
191
|
+
if args.__len__() == 1:
|
|
192
|
+
counts = args[0]
|
|
193
|
+
positions = tuple(range(counts.__len__()))
|
|
194
|
+
else:
|
|
195
|
+
positions, counts = args
|
|
196
|
+
|
|
197
|
+
return frame.vbar(x=positions, top=counts, **kwargs)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _Image(frame: backend_frame_t, image: array_t, *args, **kwargs) -> backend_plot_t:
|
|
201
|
+
""""""
|
|
202
|
+
if nmpy.issubdtype(image.dtype, nmpy.floating):
|
|
203
|
+
image = nmpy.round(255.0 * (image / image.max())).astype(nmpy.uint8)
|
|
204
|
+
|
|
205
|
+
for_bokeh = nmpy.empty(image.shape[:2], dtype=nmpy.uint32)
|
|
206
|
+
view = for_bokeh.view(dtype=nmpy.uint8).reshape(image.shape[:2] + (4,))
|
|
207
|
+
|
|
208
|
+
if (image.ndim == 2) or (image.shape[2] != 4):
|
|
209
|
+
if (image.ndim == 2) or (image.shape[2] == 1):
|
|
210
|
+
planes = (image, image, image)
|
|
211
|
+
else:
|
|
212
|
+
planes = (image[..., 0], image[..., 1], image[..., 2])
|
|
213
|
+
for d_idx in range(3):
|
|
214
|
+
view[..., d_idx] = planes[d_idx]
|
|
215
|
+
view[..., 3] = nmpy.full_like(image, 255)
|
|
216
|
+
else:
|
|
217
|
+
view[...] = image[...]
|
|
218
|
+
|
|
219
|
+
frame.x_range.range_padding = frame.y_range.range_padding = 0
|
|
220
|
+
|
|
221
|
+
return frame.image_rgba(
|
|
222
|
+
image=(for_bokeh,), x=0, y=0, dw=image.shape[1], dh=image.shape[0]
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
177
226
|
PLOTS = NewPlotFunctionsTemplate()
|
|
227
|
+
PLOTS[plot_e.BARH][0] = _BarH
|
|
228
|
+
PLOTS[plot_e.BARV][0] = _BarV
|
|
229
|
+
PLOTS[plot_e.IMAGE][0] = _Image
|
|
178
230
|
PLOTS[plot_e.SCATTER][0] = backend_frame_t.scatter
|
|
179
231
|
SetDefaultPlotFunction(PLOTS, _DefaultFunction)
|
|
180
232
|
|
|
181
233
|
|
|
182
234
|
TRANSLATIONS = {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
235
|
+
None: {
|
|
236
|
+
"color_face": "fill_color",
|
|
237
|
+
"opacity": "alpha",
|
|
238
|
+
},
|
|
239
|
+
"_NewFrame": {
|
|
240
|
+
"azimuth": None,
|
|
241
|
+
"elevation": None,
|
|
242
|
+
},
|
|
187
243
|
}
|
|
188
244
|
|
|
189
245
|
|
|
@@ -10,7 +10,7 @@ import typing as h
|
|
|
10
10
|
import matplotlib.pyplot as pypl # noqa
|
|
11
11
|
import numpy as nmpy
|
|
12
12
|
import skimage.measure as msre
|
|
13
|
-
from
|
|
13
|
+
from color_spec_changer.translation import NewTranslatedColor
|
|
14
14
|
from babelplot.task.plotting import NewPlotFunctionsTemplate
|
|
15
15
|
from babelplot.type.dimension import dim_e
|
|
16
16
|
from babelplot.type.ffp_base import backend_element_h
|
|
@@ -108,6 +108,7 @@ class frame_t(base_frame_t):
|
|
|
108
108
|
plot_function: plot_function_h,
|
|
109
109
|
*args,
|
|
110
110
|
title: str | None = None, # /!\ If _, then it is swallowed by kwargs!
|
|
111
|
+
type_: tuple[plot_type_h | plot_function_h, int],
|
|
111
112
|
**kwargs,
|
|
112
113
|
) -> plot_t:
|
|
113
114
|
""""""
|
|
@@ -271,7 +272,7 @@ def _Arrows3(frame: backend_frame_3d_t, *args, **kwargs) -> backend_plot_t:
|
|
|
271
272
|
return frame.quiver(x, y, z, u, v, w, **kwargs)
|
|
272
273
|
|
|
273
274
|
|
|
274
|
-
def _Bar3(frame:
|
|
275
|
+
def _Bar3(frame: backend_frame_3d_t, *args, **kwargs) -> backend_plot_t:
|
|
275
276
|
""""""
|
|
276
277
|
if args.__len__() == 1:
|
|
277
278
|
counts = nmpy.asarray(args[0])
|
|
@@ -319,7 +320,7 @@ def _BarV(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plots_t:
|
|
|
319
320
|
return frame.bar(positions, counts, **kwargs)
|
|
320
321
|
|
|
321
322
|
|
|
322
|
-
def _ElevationSurface(frame:
|
|
323
|
+
def _ElevationSurface(frame: backend_frame_3d_t, *args, **kwargs) -> backend_plot_t:
|
|
323
324
|
""""""
|
|
324
325
|
if args.__len__() == 1:
|
|
325
326
|
elevation = args[0]
|
|
@@ -347,7 +348,7 @@ def _IsoContour(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
|
347
348
|
return output
|
|
348
349
|
|
|
349
350
|
|
|
350
|
-
def _IsoSurface(frame:
|
|
351
|
+
def _IsoSurface(frame: backend_frame_3d_t, *args, **kwargs) -> backend_plot_t:
|
|
351
352
|
""""""
|
|
352
353
|
if "step_size" in kwargs:
|
|
353
354
|
mc_kwargs = {"step_size": kwargs["step_size"]}
|
|
@@ -362,9 +363,13 @@ def _IsoSurface(frame: backend_frame_2d_t, *args, **kwargs) -> backend_plot_t:
|
|
|
362
363
|
|
|
363
364
|
|
|
364
365
|
def _Mesh(
|
|
365
|
-
frame:
|
|
366
|
+
frame: backend_frame_3d_t, triangles: array_t, vertices: array_t, *_, **kwargs
|
|
366
367
|
) -> backend_plot_t:
|
|
367
|
-
"""
|
|
368
|
+
"""
|
|
369
|
+
Note: As of 3.9.2, plot_trisurf does not support custom triangle colors yet (see
|
|
370
|
+
https://github.com/matplotlib/matplotlib/blob/v3.9.2/lib/mpl_toolkits/mplot3d/axes3d.py,
|
|
371
|
+
line 2291).
|
|
372
|
+
"""
|
|
368
373
|
return frame.plot_trisurf(
|
|
369
374
|
vertices[:, 0], vertices[:, 1], triangles, vertices[:, 2], **kwargs
|
|
370
375
|
)
|
|
@@ -413,37 +418,52 @@ PLOTS[plot_e.TEXT][1] = _Text3
|
|
|
413
418
|
|
|
414
419
|
|
|
415
420
|
TRANSLATIONS = {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
421
|
+
None: {
|
|
422
|
+
"color": "c",
|
|
423
|
+
"color_edge": "edgecolors",
|
|
424
|
+
"color_face": "facecolors",
|
|
425
|
+
"color_max": "vmax",
|
|
426
|
+
"color_min": "vmin",
|
|
427
|
+
"color_scaling": "norm",
|
|
428
|
+
"colormap": "cmap",
|
|
429
|
+
"depth_shade": "depthshade",
|
|
430
|
+
"opacity": "alpha",
|
|
431
|
+
"plot_non_finite": "plotnonfinite",
|
|
432
|
+
"size": "s",
|
|
433
|
+
"width_edge": "linewidths",
|
|
434
|
+
},
|
|
435
|
+
"_NewFrame": {
|
|
436
|
+
"azimuth": "azim",
|
|
437
|
+
"elevation": "elev",
|
|
438
|
+
},
|
|
439
|
+
_Arrows2: {"c": "color"},
|
|
440
|
+
_Arrows3: {"c": "color"},
|
|
441
|
+
_Bar3: {"c": "color"},
|
|
442
|
+
_BarH: {
|
|
443
|
+
"c": "color",
|
|
444
|
+
"offset": "left",
|
|
445
|
+
},
|
|
446
|
+
_BarV: {
|
|
447
|
+
"c": "color",
|
|
448
|
+
"offset": "bottom",
|
|
449
|
+
},
|
|
450
|
+
_ElevationSurface: {"facecolors": "color"},
|
|
451
|
+
_IsoContour: {"c": "colors"},
|
|
452
|
+
_IsoSurface: {"facecolors": "color"},
|
|
453
|
+
_Mesh: {
|
|
454
|
+
"facecolors": (
|
|
455
|
+
"color",
|
|
456
|
+
lambda _: NewTranslatedColor(_, "hex", index_or_reduction=0)[0],
|
|
457
|
+
)
|
|
458
|
+
},
|
|
459
|
+
_Polygon: {
|
|
460
|
+
"edgecolors": "edgecolor",
|
|
461
|
+
"facecolors": "facecolor",
|
|
462
|
+
},
|
|
463
|
+
backend_frame_2d_t.pie: {"c": "colors"},
|
|
464
|
+
backend_frame_2d_t.quiver: {"c": "color"},
|
|
465
|
+
backend_frame_3d_t.quiver: {"c": "colors"},
|
|
466
|
+
backend_frame_3d_t.scatter: {2: "zs"},
|
|
447
467
|
}
|
|
448
468
|
|
|
449
469
|
"""
|
|
@@ -13,6 +13,8 @@ from pathlib import Path as path_t
|
|
|
13
13
|
import numpy as nmpy
|
|
14
14
|
import plotly.figure_factory as fcry # noqa
|
|
15
15
|
import plotly.graph_objects as plly # noqa
|
|
16
|
+
from color_spec_changer.analysis import NColorsAndFormat
|
|
17
|
+
from color_spec_changer.translation import NewTranslatedColor
|
|
16
18
|
from babelplot.task.plotting import NewPlotFunctionsTemplate
|
|
17
19
|
from babelplot.task.showing import ShowHTMLPlotWithPyQt
|
|
18
20
|
from babelplot.type.dimension import dim_e
|
|
@@ -20,8 +22,8 @@ from babelplot.type.figure import figure_t as base_figure_t
|
|
|
20
22
|
from babelplot.type.frame import frame_t as base_frame_t
|
|
21
23
|
from babelplot.type.plot import plot_t as base_plot_t
|
|
22
24
|
from babelplot.type.plot_function import plot_function_h
|
|
23
|
-
from babelplot.type.plot_type import plot_e
|
|
24
|
-
from plotly.basedatatypes import
|
|
25
|
+
from babelplot.type.plot_type import plot_e, plot_type_h
|
|
26
|
+
from plotly.basedatatypes import BaseTraceType as backend_plot_t # noqa
|
|
25
27
|
from plotly.graph_objects import Figure as backend_figure_t # noqa
|
|
26
28
|
from plotly.subplots import make_subplots as NewMultiAxesFigure # noqa
|
|
27
29
|
|
|
@@ -53,6 +55,7 @@ class frame_t(base_frame_t):
|
|
|
53
55
|
plot_function: plot_function_h,
|
|
54
56
|
*args,
|
|
55
57
|
title: str | None = None, # If _, then it is swallowed by kwargs!
|
|
58
|
+
type_: tuple[plot_type_h | plot_function_h, int],
|
|
56
59
|
**kwargs,
|
|
57
60
|
) -> plot_t:
|
|
58
61
|
""""""
|
|
@@ -94,7 +97,9 @@ class figure_t(base_figure_t):
|
|
|
94
97
|
n_rows, n_cols = self.shape
|
|
95
98
|
if (n_rows > 1) or (n_cols > 1):
|
|
96
99
|
frame_titles = (n_rows * n_cols) * [""]
|
|
97
|
-
arranged_plots
|
|
100
|
+
arranged_plots: list[list[list[backend_plot_t] | None]] = [
|
|
101
|
+
n_cols * [None] for _ in range(n_rows)
|
|
102
|
+
]
|
|
98
103
|
for frame, (row, col) in zip(self.frames, self.locations):
|
|
99
104
|
if frame.title is not None:
|
|
100
105
|
frame_titles[row * n_cols + col] = frame.title
|
|
@@ -106,6 +111,7 @@ class figure_t(base_figure_t):
|
|
|
106
111
|
frame_types = [n_cols * [{}] for _ in range(n_rows)]
|
|
107
112
|
for row, plot_row in enumerate(arranged_plots):
|
|
108
113
|
for col, plot_cell in enumerate(plot_row):
|
|
114
|
+
# Note: Subclasses of backend_plot_t have a type property.
|
|
109
115
|
frame_types[row][col] = {"type": plot_cell[0].type}
|
|
110
116
|
|
|
111
117
|
raw = NewMultiAxesFigure(
|
|
@@ -334,7 +340,7 @@ def _Image(image: array_t, *_, **kwargs) -> backend_plot_t:
|
|
|
334
340
|
|
|
335
341
|
def _IsoContour(*args, **kwargs) -> backend_plot_t:
|
|
336
342
|
""""""
|
|
337
|
-
parameters = {
|
|
343
|
+
parameters: dict[str, h.Any] = {
|
|
338
344
|
"contours_coloring": "lines",
|
|
339
345
|
"line_width": 2,
|
|
340
346
|
}
|
|
@@ -388,7 +394,10 @@ def _IsoSurface(values: array_t, value: float, *args, **kwargs) -> backend_plot_
|
|
|
388
394
|
|
|
389
395
|
|
|
390
396
|
def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) -> backend_plot_t:
|
|
391
|
-
"""
|
|
397
|
+
"""
|
|
398
|
+
Note: Mesh3d does not support setting edge colors. It can be done indirectly by
|
|
399
|
+
adding a Scatter3d plot.
|
|
400
|
+
"""
|
|
392
401
|
return plly.Mesh3d(
|
|
393
402
|
x=vertices[:, 0],
|
|
394
403
|
y=vertices[:, 1],
|
|
@@ -491,6 +500,17 @@ def _ApplyGlobalTranslation(
|
|
|
491
500
|
if (value := kwargs.get(passed)) is not None:
|
|
492
501
|
marker[wanted] = value
|
|
493
502
|
del kwargs[passed]
|
|
503
|
+
if "color" in marker:
|
|
504
|
+
format_ = NColorsAndFormat(marker["color"])
|
|
505
|
+
n_colors = format_.n_colors
|
|
506
|
+
if n_colors > 1:
|
|
507
|
+
translated, _ = NewTranslatedColor(marker["color"], "function_rgb255")
|
|
508
|
+
colorscale = [
|
|
509
|
+
[_idx / (n_colors - 1), _clr]
|
|
510
|
+
for _idx, _clr in enumerate(translated)
|
|
511
|
+
]
|
|
512
|
+
marker["colorscale"] = colorscale
|
|
513
|
+
marker["color"] = tuple(_[0] for _ in colorscale)
|
|
494
514
|
if who_s_asking is _Scatter3:
|
|
495
515
|
# /!\\ Passing one size per sample makes all of them disappear.
|
|
496
516
|
if ("size" in marker) and not isinstance(marker["size"], int | float):
|
|
@@ -501,11 +521,11 @@ def _ApplyGlobalTranslation(
|
|
|
501
521
|
|
|
502
522
|
kwargs["marker"] = marker
|
|
503
523
|
#
|
|
504
|
-
elif who_s_asking in (_Arrows2, _Polyline2, _Polyline3):
|
|
524
|
+
elif who_s_asking in (_Arrows2, _Polygon, _Polyline2, _Polyline3):
|
|
505
525
|
line = {}
|
|
506
526
|
for passed, wanted in zip(
|
|
507
|
-
("color", "opacity", "line_width", "line_style"),
|
|
508
|
-
("color", "opacity", "width", "symbol"),
|
|
527
|
+
("color", "color_edge", "opacity", "line_width", "line_style"),
|
|
528
|
+
("color", "color", "opacity", "width", "symbol"),
|
|
509
529
|
):
|
|
510
530
|
if (value := kwargs.get(passed)) is not None:
|
|
511
531
|
line[wanted] = value
|
|
@@ -524,25 +544,24 @@ def _ApplyGlobalTranslation(
|
|
|
524
544
|
|
|
525
545
|
|
|
526
546
|
TRANSLATIONS = {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
None: _ApplyGlobalTranslation,
|
|
547
|
+
None: {
|
|
548
|
+
"color_face": "surfacecolor",
|
|
549
|
+
None: _ApplyGlobalTranslation,
|
|
550
|
+
},
|
|
551
|
+
_Arrows3: {"color": None},
|
|
552
|
+
_BarH: {"color": None},
|
|
553
|
+
_BarV: {"color": None},
|
|
554
|
+
_ElevationSurface: {"color_edge": None, "surfacecolor": None, "width_edge": None},
|
|
555
|
+
_Image: {"colormap": None},
|
|
556
|
+
_IsoContour: {"color": "fillcolor"},
|
|
557
|
+
_IsoSurface: {
|
|
558
|
+
"color_edge": None,
|
|
559
|
+
"surfacecolor": None,
|
|
560
|
+
"step_size": None,
|
|
561
|
+
"width_edge": None,
|
|
562
|
+
},
|
|
563
|
+
_Mesh: {"color_edge": None, "surfacecolor": "facecolor", "width_edge": None},
|
|
564
|
+
_Polygon: {"surfacecolor": "fillcolor"},
|
|
546
565
|
}
|
|
547
566
|
|
|
548
567
|
|
|
@@ -5,23 +5,30 @@ SEE COPYRIGHT NOTICE BELOW
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import dataclasses as d
|
|
8
|
+
import typing as h
|
|
8
9
|
from multiprocessing import Process as process_t
|
|
9
10
|
|
|
10
|
-
from
|
|
11
|
-
from babelplot.task.plotting import NewPlotFunctionsTemplate
|
|
11
|
+
from color_spec_changer.translation import NewTranslatedColor
|
|
12
|
+
from babelplot.task.plotting import NewPlotFunctionsTemplate, SetDefaultPlotFunction
|
|
12
13
|
from babelplot.type.dimension import dim_e
|
|
13
14
|
from babelplot.type.figure import figure_t as base_figure_t
|
|
14
15
|
from babelplot.type.frame import frame_t as base_frame_t
|
|
15
16
|
from babelplot.type.plot import plot_t as base_plot_t
|
|
16
17
|
from babelplot.type.plot_function import plot_function_h
|
|
17
|
-
from babelplot.type.plot_type import plot_e
|
|
18
|
+
from babelplot.type.plot_type import plot_e, plot_type_h
|
|
18
19
|
from numpy import ndarray as array_t
|
|
19
|
-
from vedo import Mesh as
|
|
20
|
-
from vedo import
|
|
20
|
+
from vedo import Mesh as backend_mesh_t # noqa
|
|
21
|
+
from vedo import Text2D as text_2d_t # noqa
|
|
21
22
|
from vedo import Volume as volume_t # noqa
|
|
23
|
+
from vedo import show as BackendShow # noqa
|
|
24
|
+
from vedo.pyplot import plot as NewBackendPlot # noqa
|
|
22
25
|
|
|
23
26
|
NAME = "vedo"
|
|
24
27
|
|
|
28
|
+
_MIN_HEIGHT_RATIO = 0.4
|
|
29
|
+
|
|
30
|
+
backend_plot_h = h.TypeVar("backend_plot_h")
|
|
31
|
+
|
|
25
32
|
|
|
26
33
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
27
34
|
class plot_t(base_plot_t): ...
|
|
@@ -30,33 +37,47 @@ class plot_t(base_plot_t): ...
|
|
|
30
37
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
31
38
|
class frame_t(base_frame_t):
|
|
32
39
|
|
|
40
|
+
@property
|
|
41
|
+
def backend_plots(self) -> list[backend_plot_h]:
|
|
42
|
+
""""""
|
|
43
|
+
output = []
|
|
44
|
+
|
|
45
|
+
for plot in self.plots:
|
|
46
|
+
if plot.title is None:
|
|
47
|
+
output.append(plot.raw)
|
|
48
|
+
else:
|
|
49
|
+
output.append((plot.raw, plot.title))
|
|
50
|
+
|
|
51
|
+
return output
|
|
52
|
+
|
|
33
53
|
def _NewPlot(
|
|
34
54
|
self,
|
|
35
55
|
plot_function: plot_function_h,
|
|
36
56
|
*args,
|
|
37
57
|
title: str | None = None, # If _, then it is swallowed by kwargs!
|
|
58
|
+
type_: tuple[plot_type_h | plot_function_h, int],
|
|
38
59
|
**kwargs,
|
|
39
60
|
) -> plot_t:
|
|
40
61
|
""""""
|
|
41
|
-
|
|
62
|
+
return plot_t(
|
|
42
63
|
title=title,
|
|
43
64
|
property=kwargs.copy(),
|
|
44
65
|
backend_name=self.backend_name,
|
|
45
66
|
raw=plot_function(*args, **kwargs),
|
|
46
67
|
)
|
|
47
68
|
|
|
48
|
-
if output.raw is not None:
|
|
49
|
-
self.raw.__iadd__(output.raw)
|
|
50
|
-
|
|
51
|
-
return output
|
|
52
|
-
|
|
53
69
|
|
|
54
70
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
55
71
|
class figure_t(base_figure_t):
|
|
56
72
|
|
|
57
|
-
|
|
73
|
+
@property
|
|
74
|
+
def backend_plots_s(self) -> list[list[backend_plot_h]]:
|
|
75
|
+
""""""
|
|
76
|
+
return [_.backend_plots for _ in self.frames]
|
|
77
|
+
|
|
78
|
+
def _NewBackendFigure(self, *args, **kwargs) -> None:
|
|
58
79
|
""""""
|
|
59
|
-
return
|
|
80
|
+
return None
|
|
60
81
|
|
|
61
82
|
def _NewFrame(
|
|
62
83
|
self,
|
|
@@ -68,22 +89,20 @@ class figure_t(base_figure_t):
|
|
|
68
89
|
**kwargs,
|
|
69
90
|
) -> frame_t:
|
|
70
91
|
""""""
|
|
71
|
-
|
|
92
|
+
return frame_t(
|
|
72
93
|
title=title,
|
|
73
94
|
dim=dim,
|
|
74
95
|
backend_name=self.backend_name,
|
|
75
96
|
)
|
|
76
97
|
|
|
77
|
-
output.raw = self.raw
|
|
78
|
-
|
|
79
|
-
return output
|
|
80
|
-
|
|
81
98
|
def _BackendShow(self, modal: bool, /) -> None:
|
|
82
99
|
""""""
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
_ShowAndClose = lambda: BackendShow(
|
|
101
|
+
self.backend_plots_s, shape=self.shape, sharecam=False
|
|
102
|
+
).close()
|
|
85
103
|
|
|
86
|
-
|
|
104
|
+
# Passing [...].close shows the figures one by one. Using _ShowAndClose instead.
|
|
105
|
+
process = process_t(target=_ShowAndClose)
|
|
87
106
|
process.start()
|
|
88
107
|
|
|
89
108
|
if modal:
|
|
@@ -92,14 +111,62 @@ class figure_t(base_figure_t):
|
|
|
92
111
|
self.showing_process = process
|
|
93
112
|
|
|
94
113
|
|
|
95
|
-
def
|
|
114
|
+
def _DefaultFunction(type_: plot_e, frame_dim: int, /) -> plot_function_h:
|
|
115
|
+
""""""
|
|
116
|
+
|
|
117
|
+
def Actual(*args, **kwargs) -> backend_plot_h:
|
|
118
|
+
#
|
|
119
|
+
return text_2d_t(
|
|
120
|
+
plot_t.UnhandledRequestMessage(type_, *args, frame_dim=frame_dim, **kwargs),
|
|
121
|
+
pos="middle-left",
|
|
122
|
+
s=1.0,
|
|
123
|
+
bold=True,
|
|
124
|
+
c="red",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return Actual
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _ElevationSurface(elevation: array_t, *args, **kwargs) -> backend_plot_h:
|
|
131
|
+
""""""
|
|
132
|
+
(n_rows, n_cols), min_z, max_z = elevation.shape, elevation.min(), elevation.max()
|
|
133
|
+
max_length = max(n_rows, n_cols)
|
|
134
|
+
height = max_z - min_z
|
|
135
|
+
|
|
136
|
+
if (height > 0) and (height / max_length < _MIN_HEIGHT_RATIO):
|
|
137
|
+
scaling = _MIN_HEIGHT_RATIO * max_length / height
|
|
138
|
+
if scaling.is_integer():
|
|
139
|
+
scaling = int(scaling)
|
|
140
|
+
equality = "="
|
|
141
|
+
else:
|
|
142
|
+
rounded = round(scaling)
|
|
143
|
+
rounded_length = str(rounded).__len__()
|
|
144
|
+
precision = max(3 - rounded_length, 0)
|
|
145
|
+
if precision > 0:
|
|
146
|
+
scaling = round(scaling, ndigits=precision)
|
|
147
|
+
else:
|
|
148
|
+
scaling = rounded
|
|
149
|
+
equality = "≈"
|
|
150
|
+
kwarg_axes = {"axes": {"ztitle": f"Scaling{equality}{scaling}"}}
|
|
151
|
+
else:
|
|
152
|
+
scaling = 1.0
|
|
153
|
+
kwarg_axes = {}
|
|
154
|
+
|
|
155
|
+
Elevation = lambda _row, _col: scaling * float(elevation[round(_row), round(_col)])
|
|
156
|
+
|
|
157
|
+
return NewBackendPlot(
|
|
158
|
+
Elevation, xlim=(0, n_rows), ylim=(0, n_cols), c="summer", **kwarg_axes
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _IsoSurface(volume: array_t, iso_value: float, *_, **kwargs) -> backend_mesh_t:
|
|
96
163
|
""""""
|
|
97
164
|
return volume_t(volume).isosurface(value=[iso_value], **kwargs)
|
|
98
165
|
|
|
99
166
|
|
|
100
|
-
def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) ->
|
|
167
|
+
def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) -> backend_mesh_t:
|
|
101
168
|
""""""
|
|
102
|
-
output =
|
|
169
|
+
output = backend_mesh_t((vertices, triangles))
|
|
103
170
|
|
|
104
171
|
if "width_edge" in kwargs:
|
|
105
172
|
output.linewidth(kwargs["width_edge"])
|
|
@@ -112,16 +179,25 @@ def _Mesh(triangles: array_t, vertices: array_t, *_, **kwargs) -> backend_plot_t
|
|
|
112
179
|
|
|
113
180
|
|
|
114
181
|
PLOTS = NewPlotFunctionsTemplate()
|
|
182
|
+
PLOTS[plot_e.ELEVATION][1] = _ElevationSurface
|
|
115
183
|
PLOTS[plot_e.ISOSET][1] = _IsoSurface
|
|
116
184
|
PLOTS[plot_e.MESH][1] = _Mesh
|
|
185
|
+
SetDefaultPlotFunction(PLOTS, _DefaultFunction)
|
|
117
186
|
|
|
118
187
|
|
|
119
188
|
TRANSLATIONS = {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
189
|
+
_IsoSurface: {
|
|
190
|
+
"color_edge": None,
|
|
191
|
+
"color_face": None,
|
|
192
|
+
"step_size": None,
|
|
193
|
+
"width_edge": None,
|
|
194
|
+
},
|
|
195
|
+
_Mesh: {
|
|
196
|
+
"color_face": (
|
|
197
|
+
"color_face",
|
|
198
|
+
lambda _: NewTranslatedColor(_, "hex", index_or_reduction=0)[0],
|
|
199
|
+
)
|
|
200
|
+
},
|
|
125
201
|
}
|
|
126
202
|
|
|
127
203
|
|
|
@@ -4,6 +4,7 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
|
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from babelplot.type.plot import plot_t
|
|
7
8
|
from babelplot.type.plot_function import plot_function_h, plot_functions_h
|
|
8
9
|
from babelplot.type.plot_type import plot_e
|
|
9
10
|
from logger_36 import L
|
|
@@ -29,11 +30,9 @@ def _FakePlotFunction(type_: plot_e, frame_dim: int, /) -> plot_function_h:
|
|
|
29
30
|
|
|
30
31
|
def Actual(*args, **kwargs) -> None:
|
|
31
32
|
#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
f"{_key}={type(_vle).__name__}" for _key, _vle in kwargs.items()
|
|
33
|
+
L.warning(
|
|
34
|
+
plot_t.UnhandledRequestMessage(type_, *args, frame_dim=frame_dim, **kwargs)
|
|
35
35
|
)
|
|
36
|
-
L.warning(f"Unhandled plot request: {type_.name}.{frame_dim}: {args}, {kwargs}")
|
|
37
36
|
|
|
38
37
|
return Actual
|
|
39
38
|
|
|
@@ -63,38 +63,45 @@ class backend_t:
|
|
|
63
63
|
if (translations is None) or (translations.__len__() == 0):
|
|
64
64
|
return args, kwargs
|
|
65
65
|
|
|
66
|
+
if (generics := translations.get(None)) is None:
|
|
67
|
+
generics = {}
|
|
68
|
+
if (for_who_s_asking := translations.get(who_s_asking)) is None:
|
|
69
|
+
for_who_s_asking = {}
|
|
70
|
+
|
|
66
71
|
out_args = []
|
|
67
72
|
out_kwargs = {}
|
|
68
73
|
|
|
74
|
+
from_args_to_args = []
|
|
69
75
|
for idx, value in enumerate(args):
|
|
70
|
-
if (translation :=
|
|
76
|
+
if (translation := for_who_s_asking.get(idx, -1)) == -1:
|
|
71
77
|
# No translation needed; Keeping the passed arg.
|
|
72
78
|
out_args.append(value)
|
|
73
79
|
elif translation is None:
|
|
74
80
|
# The argument should be discarded.
|
|
75
81
|
pass
|
|
76
|
-
else: # isinstance(translation, str | tuple[str, h.Callable])
|
|
77
|
-
# The passed arg should
|
|
82
|
+
else: # isinstance(translation, int|str | tuple[int|str, h.Callable])
|
|
83
|
+
# The passed arg should be placed at the position "translation", or
|
|
84
|
+
# should actually be a kwarg with name "translation".
|
|
78
85
|
if isinstance(translation, list | tuple):
|
|
79
86
|
translation, NewConvertedValue = translation
|
|
80
87
|
value = NewConvertedValue(value)
|
|
81
|
-
|
|
88
|
+
if isinstance(translation, int):
|
|
89
|
+
from_args_to_args.append([translation, value])
|
|
90
|
+
else:
|
|
91
|
+
out_kwargs[translation] = value
|
|
92
|
+
|
|
93
|
+
out_args = [[_pos, _vle] for _pos, _vle in enumerate(out_args, start=1)]
|
|
94
|
+
_InsertArguments(out_args, from_args_to_args)
|
|
82
95
|
|
|
83
96
|
from_kwargs_to_args = []
|
|
84
97
|
for key, value in kwargs.items():
|
|
85
|
-
#
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
pass
|
|
93
|
-
else: # isinstance(translation, str | tuple[str, h.Callable])
|
|
94
|
-
if isinstance(translation, list | tuple):
|
|
95
|
-
translation, NewConvertedValue = translation
|
|
96
|
-
value = NewConvertedValue(value)
|
|
97
|
-
out_kwargs[translation] = value
|
|
98
|
+
# Apply generic translation first, if any.
|
|
99
|
+
key = generics.get(key, key)
|
|
100
|
+
|
|
101
|
+
# Search for specific translation.
|
|
102
|
+
if (translation := for_who_s_asking.get(key, -1)) == -1:
|
|
103
|
+
# No translation needed; Keeping the passed kwarg.
|
|
104
|
+
out_kwargs[key] = value
|
|
98
105
|
elif translation is None:
|
|
99
106
|
# The argument should be discarded.
|
|
100
107
|
pass
|
|
@@ -105,12 +112,12 @@ class backend_t:
|
|
|
105
112
|
if isinstance(translation, str):
|
|
106
113
|
out_kwargs[translation] = value
|
|
107
114
|
else: # isinstance(translation, int)
|
|
108
|
-
from_kwargs_to_args.append(
|
|
115
|
+
from_kwargs_to_args.append([translation, value])
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
_InsertArguments(out_args, from_kwargs_to_args)
|
|
118
|
+
out_args = tuple(map(ItemAt(1), out_args))
|
|
112
119
|
|
|
113
|
-
if (ApplyGlobalTranslation :=
|
|
120
|
+
if (ApplyGlobalTranslation := generics.get(None)) is not None:
|
|
114
121
|
ApplyGlobalTranslation(out_kwargs, who_s_asking)
|
|
115
122
|
|
|
116
123
|
return out_args, out_kwargs
|
|
@@ -120,6 +127,22 @@ class backend_t:
|
|
|
120
127
|
return self.py_path
|
|
121
128
|
|
|
122
129
|
|
|
130
|
+
def _InsertArguments(
|
|
131
|
+
current: list[list[int | h.Any]], new: list[list[int | h.Any]], /
|
|
132
|
+
) -> None:
|
|
133
|
+
"""
|
|
134
|
+
Note: list[int | h.Any] should actually be mutable_tuple[int, h.Any].
|
|
135
|
+
"""
|
|
136
|
+
# Note: It is important to sort from_args_to_args so that a higher-positioned
|
|
137
|
+
# argument does not get shifted even higher by the insertion of a lower-positioned
|
|
138
|
+
# argument dealt with later.
|
|
139
|
+
for position, value in sorted(new, key=ItemAt(0)):
|
|
140
|
+
for argument in current:
|
|
141
|
+
if argument[0] >= position:
|
|
142
|
+
argument[0] += 1
|
|
143
|
+
current.append([position, value])
|
|
144
|
+
|
|
145
|
+
|
|
123
146
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
124
147
|
class backends_t(dict[str, backend_t]):
|
|
125
148
|
|
|
@@ -57,7 +57,7 @@ class figure_t(base_t):
|
|
|
57
57
|
|
|
58
58
|
return output
|
|
59
59
|
|
|
60
|
-
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_h:
|
|
60
|
+
def _NewBackendFigure(self, *args, **kwargs) -> backend_figure_h | None:
|
|
61
61
|
""""""
|
|
62
62
|
raise NotImplementedError
|
|
63
63
|
|
|
@@ -86,7 +86,7 @@ class figure_t(base_t):
|
|
|
86
86
|
col = self.shape[1]
|
|
87
87
|
|
|
88
88
|
args, kwargs = BACKENDS.TranslatedArguments(
|
|
89
|
-
self.backend_name, args, kwargs, self.
|
|
89
|
+
self.backend_name, args, kwargs, self._NewFrame.__name__
|
|
90
90
|
)
|
|
91
91
|
output = self._NewFrame(title, dim, row, col, *args, **kwargs)
|
|
92
92
|
|
|
@@ -33,6 +33,7 @@ class frame_t(base_t):
|
|
|
33
33
|
**kwargs,
|
|
34
34
|
) -> plot_t:
|
|
35
35
|
""""""
|
|
36
|
+
full_type = (type_, self.frame_dim)
|
|
36
37
|
plot_function = BACKENDS.PlotFunction(self.backend_name, type_, self.frame_dim)
|
|
37
38
|
args, kwargs = BACKENDS.TranslatedArguments(
|
|
38
39
|
self.backend_name, args, kwargs, plot_function
|
|
@@ -41,8 +42,10 @@ class frame_t(base_t):
|
|
|
41
42
|
plot_function,
|
|
42
43
|
*args,
|
|
43
44
|
title=title,
|
|
45
|
+
type_=full_type,
|
|
44
46
|
**kwargs,
|
|
45
47
|
)
|
|
48
|
+
plot.type_ = full_type
|
|
46
49
|
# Note: plot.__class__ is not plot_t; It is the subclass defined by a backend.
|
|
47
50
|
DefaultProperties = getattr(plot.__class__, "_BackendDefaultProperties", None)
|
|
48
51
|
if DefaultProperties is not None:
|
|
@@ -59,6 +62,7 @@ class frame_t(base_t):
|
|
|
59
62
|
plot_function: plot_function_h,
|
|
60
63
|
*args,
|
|
61
64
|
title: str | None = None, # /!\ If _, then it is swallowed by kwargs!
|
|
65
|
+
type_: tuple[plot_type_h | plot_function_h, int],
|
|
62
66
|
**kwargs,
|
|
63
67
|
) -> plot_t:
|
|
64
68
|
""""""
|
|
@@ -7,11 +7,35 @@ SEE COPYRIGHT NOTICE BELOW
|
|
|
7
7
|
import dataclasses as d
|
|
8
8
|
|
|
9
9
|
from babelplot.type.ffp_base import base_t
|
|
10
|
+
from babelplot.type.plot_function import plot_function_h
|
|
11
|
+
from babelplot.type.plot_type import plot_type_h
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
@d.dataclass(slots=True, repr=False, eq=False)
|
|
13
15
|
class plot_t(base_t):
|
|
14
16
|
title: str | None = None
|
|
17
|
+
type_: tuple[plot_type_h | plot_function_h, int] | None = None
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def UnhandledRequestMessage(
|
|
21
|
+
type_: plot_type_h | plot_function_h, *args, frame_dim: int = 0, **kwargs
|
|
22
|
+
) -> str:
|
|
23
|
+
""""""
|
|
24
|
+
if frame_dim > 0:
|
|
25
|
+
if isinstance(type_, str):
|
|
26
|
+
name = type_
|
|
27
|
+
else:
|
|
28
|
+
name = type_.name
|
|
29
|
+
request = f"{name}.{frame_dim}"
|
|
30
|
+
else:
|
|
31
|
+
request = str(type_)
|
|
32
|
+
|
|
33
|
+
args = ", ".join(map(lambda _: type(_).__name__, args))
|
|
34
|
+
kwargs = ", ".join(
|
|
35
|
+
f"{_key}={type(_vle).__name__}" for _key, _vle in kwargs.items()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return f"Unhandled Plot Request\n{request}\nargs: {args}\nkwargs: {kwargs}"
|
|
15
39
|
|
|
16
40
|
|
|
17
41
|
"""
|
|
@@ -26,7 +26,6 @@ package/babelplot/constant/project.py
|
|
|
26
26
|
package/babelplot/extension/enum_.py
|
|
27
27
|
package/babelplot/extension/function.py
|
|
28
28
|
package/babelplot/runtime/backends.py
|
|
29
|
-
package/babelplot/task/color.py
|
|
30
29
|
package/babelplot/task/help.py
|
|
31
30
|
package/babelplot/task/instantiation.py
|
|
32
31
|
package/babelplot/task/plotting.py
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Copyright CNRS/Inria/UniCA
|
|
3
|
-
Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
|
|
4
|
-
SEE COPYRIGHT NOTICE BELOW
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import typing as h
|
|
8
|
-
|
|
9
|
-
import numpy as nmpy
|
|
10
|
-
|
|
11
|
-
try:
|
|
12
|
-
import matplotlib.colors as colr
|
|
13
|
-
except ModuleNotFoundError:
|
|
14
|
-
colr = None
|
|
15
|
-
else:
|
|
16
|
-
AsHex = lambda _: colr.to_hex(_).upper()
|
|
17
|
-
AsRGB1 = colr.to_rgb
|
|
18
|
-
AsRGB255 = lambda _: nmpy.round(255.0 * nmpy.array(colr.to_rgb(_))).astype(
|
|
19
|
-
nmpy.uint8
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
assert colr, "No module found for color conversion."
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
array_t = nmpy.ndarray
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def NewConvertedColor(
|
|
30
|
-
color: h.Any | h.Sequence[h.Any],
|
|
31
|
-
format_color: h.Literal["hex", "rgb1", "rgb255"],
|
|
32
|
-
sequence_or_reduction: (
|
|
33
|
-
int | h.Literal["min", "mean", "median", "max"] | type | h.Callable
|
|
34
|
-
),
|
|
35
|
-
/,
|
|
36
|
-
) -> h.Any:
|
|
37
|
-
""""""
|
|
38
|
-
if format_color == "rgb1":
|
|
39
|
-
AsOutputFormat = AsRGB1
|
|
40
|
-
elif format_color == "rgb255":
|
|
41
|
-
AsOutputFormat = AsRGB255
|
|
42
|
-
elif format_color == "hex":
|
|
43
|
-
AsOutputFormat = AsHex
|
|
44
|
-
else:
|
|
45
|
-
raise ValueError(f"Unknown output format {format_color}.")
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
(not isinstance(color, str))
|
|
49
|
-
and (isinstance(color, h.Sequence) and isinstance(color[0], h.Sequence))
|
|
50
|
-
or (isinstance(color, array_t) and (color.ndim == 2))
|
|
51
|
-
):
|
|
52
|
-
# Notes: The first h.Sequence is implicitly tuple | list, or other "true" (i.e.
|
|
53
|
-
# not str) sequence types, and color can be of any length.
|
|
54
|
-
# The second h.Sequence is implicitly tuple | list, other "true" sequence types,
|
|
55
|
-
# or str. If str, then color is in Hex format. Its length is either 4 (e.g.,
|
|
56
|
-
# #ABC <=> #AABBCC), 5 (e.g., #ABCD <=> #AABBCCDD), 7 (e.g., #ABCDEF) or 9
|
|
57
|
-
# (e.g., #ABCDEF01). If not str, then color is a sequence of 3 or 4 integers or
|
|
58
|
-
# floats.
|
|
59
|
-
if isinstance(sequence_or_reduction, int):
|
|
60
|
-
return AsOutputFormat(color[sequence_or_reduction])
|
|
61
|
-
elif isinstance(sequence_or_reduction, str):
|
|
62
|
-
raise NotImplementedError
|
|
63
|
-
return sequence_or_reduction(tuple(AsOutputFormat(_) for _ in color))
|
|
64
|
-
|
|
65
|
-
return AsOutputFormat(color)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"""
|
|
69
|
-
COPYRIGHT NOTICE
|
|
70
|
-
|
|
71
|
-
This software is governed by the CeCILL license under French law and
|
|
72
|
-
abiding by the rules of distribution of free software. You can use,
|
|
73
|
-
modify and/ or redistribute the software under the terms of the CeCILL
|
|
74
|
-
license as circulated by CEA, CNRS and INRIA at the following URL
|
|
75
|
-
"http://www.cecill.info".
|
|
76
|
-
|
|
77
|
-
As a counterpart to the access to the source code and rights to copy,
|
|
78
|
-
modify and redistribute granted by the license, users are provided only
|
|
79
|
-
with a limited warranty and the software's author, the holder of the
|
|
80
|
-
economic rights, and the successive licensors have only limited
|
|
81
|
-
liability.
|
|
82
|
-
|
|
83
|
-
In this respect, the user's attention is drawn to the risks associated
|
|
84
|
-
with loading, using, modifying and/or developing or reproducing the
|
|
85
|
-
software by the user in light of its specific status of free software,
|
|
86
|
-
that may mean that it is complicated to manipulate, and that also
|
|
87
|
-
therefore means that it is reserved for developers and experienced
|
|
88
|
-
professionals having in-depth computer knowledge. Users are therefore
|
|
89
|
-
encouraged to load and test the software's suitability as regards their
|
|
90
|
-
requirements in conditions enabling the security of their systems and/or
|
|
91
|
-
data to be ensured and, more generally, to use and operate it in the
|
|
92
|
-
same conditions as regards security.
|
|
93
|
-
|
|
94
|
-
The fact that you are presently reading this means that you have had
|
|
95
|
-
knowledge of the CeCILL license and that you accept its terms.
|
|
96
|
-
|
|
97
|
-
SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
|
|
98
|
-
|
|
99
|
-
This software is being developed by Eric Debreuve, a CNRS employee and
|
|
100
|
-
member of team Morpheme.
|
|
101
|
-
Team Morpheme is a joint team between Inria, CNRS, and UniCA.
|
|
102
|
-
It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
|
|
103
|
-
I3S, and Laboratory iBV.
|
|
104
|
-
|
|
105
|
-
CNRS: https://www.cnrs.fr/index.php/en
|
|
106
|
-
Inria: https://www.inria.fr/en/
|
|
107
|
-
UniCA: https://univ-cotedazur.eu/
|
|
108
|
-
Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
|
|
109
|
-
I3S: https://www.i3s.unice.fr/en/
|
|
110
|
-
iBV: http://ibv.unice.fr/
|
|
111
|
-
Team Morpheme: https://team.inria.fr/morpheme/
|
|
112
|
-
"""
|
|
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
|