babelplot 2025.4__tar.gz → 2025.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {babelplot-2025.4 → babelplot-2025.5}/PKG-INFO +1 -1
  2. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/__init__.py +2 -0
  3. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/api/backend.py +0 -1
  4. babelplot-2025.5/package/babelplot/api/definition.py +54 -0
  5. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/backend/catalog/bokeh_.py +90 -90
  6. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/backend/catalog/matplotlib_.py +161 -163
  7. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/backend/catalog/plotly_.py +109 -105
  8. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/backend/catalog/vedo_.py +72 -77
  9. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/backend/helper/creation.py +7 -5
  10. babelplot-2025.4/package/babelplot/constant/backend.py → babelplot-2025.5/package/babelplot/backend/helper/validation.py +38 -40
  11. babelplot-2025.4/package/babelplot/api/definition.py → babelplot-2025.5/package/babelplot/constant/backend.py +13 -3
  12. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/extension/function.py +0 -51
  13. babelplot-2025.5/package/babelplot/runtime/backends.py +55 -0
  14. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/task/help.py +9 -7
  15. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/task/instantiation.py +21 -47
  16. babelplot-2025.5/package/babelplot/type/backend.py +190 -0
  17. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/type/base.py +26 -30
  18. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/type/figure.py +62 -68
  19. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/type/frame.py +52 -57
  20. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/type/plot.py +21 -14
  21. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/version.py +1 -1
  22. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot.egg-info/PKG-INFO +1 -1
  23. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot.egg-info/SOURCES.txt +5 -6
  24. babelplot-2025.4/package/babelplot/backend/definition/backend.py +0 -113
  25. babelplot-2025.4/package/babelplot/backend/definition/runtime.py +0 -77
  26. babelplot-2025.4/package/babelplot/backend/helper/validation.py +0 -130
  27. babelplot-2025.4/package/babelplot/extension/ast_.py +0 -155
  28. {babelplot-2025.4 → babelplot-2025.5}/MANIFEST.in +0 -0
  29. {babelplot-2025.4 → babelplot-2025.5}/README-COPYRIGHT-utf8.txt +0 -0
  30. {babelplot-2025.4 → babelplot-2025.5}/README-LICENCE-utf8.txt +0 -0
  31. {babelplot-2025.4 → babelplot-2025.5}/README.rst +0 -0
  32. {babelplot-2025.4 → babelplot-2025.5}/documentation/wiki/description.asciidoc +0 -0
  33. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/api/help.py +0 -0
  34. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/constant/path.py +0 -0
  35. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/constant/project.py +0 -0
  36. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/extension/enum_.py +0 -0
  37. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot/task/show_pyqt6.py +0 -0
  38. {babelplot-2025.4/package/babelplot/definition → babelplot-2025.5/package/babelplot/type}/dimension.py +0 -0
  39. /babelplot-2025.4/package/babelplot/definition/plot.py → /babelplot-2025.5/package/babelplot/type/plot_definition.py +0 -0
  40. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot.egg-info/dependency_links.txt +0 -0
  41. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot.egg-info/requires.txt +0 -0
  42. {babelplot-2025.4 → babelplot-2025.5}/package/babelplot.egg-info/top_level.txt +0 -0
  43. {babelplot-2025.4 → babelplot-2025.5}/pyproject.toml +0 -0
  44. {babelplot-2025.4 → babelplot-2025.5}/requirements.txt +0 -0
  45. {babelplot-2025.4 → babelplot-2025.5}/setup.cfg +0 -0
  46. {babelplot-2025.4 → babelplot-2025.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: babelplot
3
- Version: 2025.4
3
+ Version: 2025.5
4
4
  Summary: A Meta Plotting Library That Speaks Several Backends
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/babelplot/
6
6
  Author: Eric Debreuve
@@ -18,7 +18,9 @@ else:
18
18
  beartype_this_package()
19
19
 
20
20
  from babelplot.task.instantiation import NewFigure, NewPlot
21
+ from babelplot.type.dimension import dim_e
21
22
  from babelplot.type.figure import ShowAllFigures
23
+ from babelplot.type.plot_definition import plot_e
22
24
  from babelplot.version import __version__
23
25
 
24
26
  """
@@ -4,7 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from babelplot.backend.definition.runtime import AddBackendSpecification # noqa
8
7
  from babelplot.backend.helper.creation import PrintBackendDraft # noqa
9
8
  from babelplot.backend.helper.validation import CheckBackend # noqa
10
9
 
@@ -0,0 +1,54 @@
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
+ from babelplot.type.dimension import dim_e # noqa
8
+ from babelplot.type.plot_definition import plot_e # noqa
9
+
10
+ """
11
+ COPYRIGHT NOTICE
12
+
13
+ This software is governed by the CeCILL license under French law and
14
+ abiding by the rules of distribution of free software. You can use,
15
+ modify and/ or redistribute the software under the terms of the CeCILL
16
+ license as circulated by CEA, CNRS and INRIA at the following URL
17
+ "http://www.cecill.info".
18
+
19
+ As a counterpart to the access to the source code and rights to copy,
20
+ modify and redistribute granted by the license, users are provided only
21
+ with a limited warranty and the software's author, the holder of the
22
+ economic rights, and the successive licensors have only limited
23
+ liability.
24
+
25
+ In this respect, the user's attention is drawn to the risks associated
26
+ with loading, using, modifying and/or developing or reproducing the
27
+ software by the user in light of its specific status of free software,
28
+ that may mean that it is complicated to manipulate, and that also
29
+ therefore means that it is reserved for developers and experienced
30
+ professionals having in-depth computer knowledge. Users are therefore
31
+ encouraged to load and test the software's suitability as regards their
32
+ requirements in conditions enabling the security of their systems and/or
33
+ data to be ensured and, more generally, to use and operate it in the
34
+ same conditions as regards security.
35
+
36
+ The fact that you are presently reading this means that you have had
37
+ knowledge of the CeCILL license and that you accept its terms.
38
+
39
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
40
+
41
+ This software is being developed by Eric Debreuve, a CNRS employee and
42
+ member of team Morpheme.
43
+ Team Morpheme is a joint team between Inria, CNRS, and UniCA.
44
+ It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
45
+ I3S, and Laboratory iBV.
46
+
47
+ CNRS: https://www.cnrs.fr/index.php/en
48
+ Inria: https://www.inria.fr/en/
49
+ UniCA: https://univ-cotedazur.eu/
50
+ Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
51
+ I3S: https://www.i3s.unice.fr/en/
52
+ iBV: http://ibv.unice.fr/
53
+ Team Morpheme: https://team.inria.fr/morpheme/
54
+ """
@@ -4,19 +4,16 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from __future__ import annotations
8
-
7
+ import dataclasses as d
9
8
  import typing as h
10
9
 
11
- from babelplot.backend.definition.backend import backend_e
12
- from babelplot.definition.dimension import dim_e
13
- from babelplot.definition.plot import PlotsFromTemplate, plot_e, plot_type_h
14
10
  from babelplot.task.show_pyqt6 import Show
11
+ from babelplot.type.dimension import dim_e
15
12
  from babelplot.type.figure import figure_t as base_figure_t
16
13
  from babelplot.type.frame import frame_t as base_frame_t
17
14
  from babelplot.type.plot import plot_t as base_plot_t
15
+ from babelplot.type.plot_definition import PlotsFromTemplate, plot_e, plot_type_h
18
16
  from bokeh.embed import file_html as HTMLofBackendContent # noqa
19
- from bokeh.layouts import LayoutDOM as backend_content_t # noqa
20
17
  from bokeh.layouts import column as NewBackendColLayout # noqa
21
18
  from bokeh.layouts import grid as NewBackendGridLayout # noqa
22
19
  from bokeh.layouts import row as NewBackendRowLayout # noqa
@@ -24,96 +21,99 @@ from bokeh.models.renderers import GlyphRenderer as backend_plot_t # noqa
24
21
  from bokeh.plotting import figure as backend_figure_t # noqa
25
22
  from bokeh.resources import INLINE # noqa
26
23
 
27
- NAME = backend_e.BOKEH.value
24
+ # from bokeh.layouts import LayoutDOM as backend_content_t # noqa
25
+
26
+ NAME = "bokeh"
28
27
 
29
28
 
30
29
  backend_frame_t = backend_figure_t
31
30
 
32
31
 
33
- def _NewPlot(
34
- frame: backend_frame_t,
35
- type_: plot_type_h | type[backend_plot_t],
36
- plot_function: (
37
- type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any] | None
38
- ),
39
- *args,
40
- title: str | None = None, # If _, then it is swallowed by kwargs!
41
- **kwargs,
42
- ) -> tuple[
43
- backend_plot_t | h.Any,
44
- type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any],
45
- ]:
46
- """"""
47
- if plot_function is None:
48
- if hasattr(backend_frame_t, type_):
49
- plot_function = getattr(backend_frame_t, type_)
50
- else:
51
- raise ValueError(f"{type_}: Unknown {NAME} graph object.")
52
-
53
- return plot_function(frame, *args, **kwargs), plot_function
54
-
55
-
56
- def _NewFrame(
57
- _: backend_figure_t,
58
- __: int,
59
- ___: int,
60
- *args,
61
- title: str | None = None,
62
- dim: dim_e = dim_e.XY, # If _, then it is swallowed by kwargs!
63
- **kwargs,
64
- ) -> backend_frame_t:
65
- """"""
66
- return backend_frame_t(*args, title=title, **kwargs)
67
-
68
-
69
- def _AdjustLayout(figure: figure_t, /) -> None:
70
- """"""
71
- n_rows, n_cols = figure.shape
72
- arranged_frames = [n_cols * [None] for _ in range(n_rows)]
73
- for frame, (row, col) in zip(figure.frames, figure.locations):
74
- arranged_frames[row][col] = frame.backend
75
- arranged_frames: list[list[backend_frame_t]]
76
-
77
- if n_rows > 1:
78
- if n_cols > 1:
79
- layout = NewBackendGridLayout(arranged_frames)
32
+ @d.dataclass(slots=True, repr=False, eq=False)
33
+ class plot_t(base_plot_t): ...
34
+
35
+
36
+ @d.dataclass(slots=True, repr=False, eq=False)
37
+ class frame_t(base_frame_t):
38
+
39
+ def _NewPlot(
40
+ self,
41
+ type_: plot_type_h | type[backend_plot_t],
42
+ plot_function: (
43
+ type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any] | None
44
+ ),
45
+ *args,
46
+ title: str | None = None, # If _, then it is swallowed by kwargs!
47
+ **kwargs,
48
+ ) -> plot_t:
49
+ """"""
50
+ output = plot_t(
51
+ title=title,
52
+ property=kwargs.copy(),
53
+ backend_name=self.backend_name,
54
+ )
55
+
56
+ if plot_function is None:
57
+ if hasattr(backend_frame_t, type_):
58
+ plot_function = getattr(backend_frame_t, type_)
59
+ else:
60
+ raise ValueError(f"{type_}: Unknown {NAME} graph object.")
61
+
62
+ output.backend_type = plot_function
63
+ output.raw = plot_function(self.raw, *args, **kwargs)
64
+
65
+ return output
66
+
67
+
68
+ @d.dataclass(slots=True, repr=False, eq=False)
69
+ class figure_t(base_figure_t):
70
+ layout: h.Any = None
71
+
72
+ _NewBackendFigure = backend_figure_t
73
+ _BackendShow = Show
74
+
75
+ def _NewFrame(
76
+ self,
77
+ row: int,
78
+ col: int,
79
+ *args,
80
+ title: str | None = None,
81
+ dim: dim_e = dim_e.XY, # If _, then it is swallowed by kwargs!
82
+ **kwargs,
83
+ ) -> frame_t:
84
+ """"""
85
+ output = frame_t(
86
+ title=title,
87
+ dim=dim,
88
+ backend_name=self.backend_name,
89
+ )
90
+
91
+ output.raw = backend_frame_t(*args, title=title, **kwargs)
92
+
93
+ return output
94
+
95
+ def AdjustLayout(self) -> None:
96
+ """"""
97
+ n_rows, n_cols = self.shape
98
+ arranged_frames = [n_cols * [None] for _ in range(n_rows)]
99
+ for frame, (row, col) in zip(self.frames, self.locations):
100
+ arranged_frames[row][col] = frame.raw
101
+ arranged_frames: list[list[backend_frame_t]]
102
+
103
+ if n_rows > 1:
104
+ if n_cols > 1:
105
+ layout = NewBackendGridLayout(arranged_frames)
106
+ else:
107
+ column = [_row[0] for _row in arranged_frames]
108
+ layout = NewBackendColLayout(column)
80
109
  else:
81
- column = [_row[0] for _row in arranged_frames]
82
- layout = NewBackendColLayout(column)
83
- else:
84
- layout = NewBackendRowLayout(arranged_frames[0])
85
-
86
- figure.layout = layout
87
-
88
-
89
- def _AsHTML(figure: figure_t, /) -> str:
90
- """"""
91
-
92
- return HTMLofBackendContent(figure.layout, INLINE)
93
-
94
-
95
- # noinspection PyTypeChecker
96
- plot_t: type[base_plot_t] = type("plot_t", (base_plot_t,), {})
97
- # noinspection PyTypeChecker
98
- frame_t: type[base_frame_t] = type(
99
- "frame_t",
100
- (base_frame_t,),
101
- {"plot_class": plot_t, "NewBackendPlot": staticmethod(_NewPlot)},
102
- )
103
- # noinspection PyTypeChecker
104
- figure_t: type[base_figure_t] = type(
105
- "figure_t",
106
- (base_figure_t,),
107
- {
108
- "frame_class": frame_t,
109
- "NewBackendFigure": backend_figure_t,
110
- "NewBackendFrame": staticmethod(_NewFrame),
111
- "AdjustLayout": _AdjustLayout,
112
- "BackendShow": Show,
113
- "layout": None,
114
- "AsHTML": _AsHTML,
115
- },
116
- )
110
+ layout = NewBackendRowLayout(arranged_frames[0])
111
+
112
+ self.layout = layout
113
+
114
+ def AsHTML(self) -> str:
115
+ """"""
116
+ return HTMLofBackendContent(self.layout, INLINE)
117
117
 
118
118
 
119
119
  PLOTS = PlotsFromTemplate()
@@ -4,20 +4,18 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2022
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from __future__ import annotations
8
-
7
+ import dataclasses as d
9
8
  import typing as h
10
9
 
11
10
  import matplotlib.pyplot as pypl # noqa
12
11
  import numpy as nmpy
13
12
  import skimage.measure as msre
14
- from babelplot.backend.definition.backend import backend_e
15
- from babelplot.definition.dimension import dim_e
16
- from babelplot.definition.plot import PlotsFromTemplate, plot_e, plot_type_h
17
13
  from babelplot.type.base import backend_element_h
14
+ from babelplot.type.dimension import dim_e
18
15
  from babelplot.type.figure import figure_t as base_figure_t
19
16
  from babelplot.type.frame import frame_t as base_frame_t
20
17
  from babelplot.type.plot import plot_t as base_plot_t
18
+ from babelplot.type.plot_definition import PlotsFromTemplate, plot_e, plot_type_h
21
19
  from logger_36 import L
22
20
  from matplotlib.artist import Artist as backend_plot_t # noqa
23
21
  from matplotlib.container import Container as backend_plots_t # noqa
@@ -31,108 +29,13 @@ from mpl_toolkits.mplot3d import Axes3D as backend_frame_3d_t # noqa
31
29
 
32
30
  import matplotlib as mlpl # noqa
33
31
 
34
- NAME = backend_e.MATPLOTLIB.value
32
+ NAME = "matplotlib"
35
33
 
36
34
 
37
35
  array_t = nmpy.ndarray
38
36
  backend_frame_h = backend_frame_2d_t | backend_frame_3d_t
39
37
 
40
38
 
41
- def _NewPlot(
42
- frame: backend_frame_h,
43
- type_: plot_type_h | type[backend_plot_t],
44
- plot_function: (
45
- type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any] | None
46
- ),
47
- *args,
48
- title: str | None = None, # /!\ If _, then it is swallowed by kwargs!
49
- **kwargs,
50
- ) -> tuple[
51
- backend_plot_t | h.Any,
52
- type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any],
53
- ]:
54
- """"""
55
- if plot_function is None:
56
- # Next, priority is given to 2-D plots... which might be a problem if a 2-D and
57
- # 3-D frame have plot types with the same name. For example, scatter in 2-D and
58
- # 3-D.
59
- if hasattr(backend_frame_2d_t, type_):
60
- plot_function = getattr(backend_frame_2d_t, type_)
61
- elif hasattr(backend_frame_3d_t, type_):
62
- plot_function = getattr(backend_frame_3d_t, type_)
63
- else:
64
- raise ValueError(f"{type_}: Unknown {NAME} graph object.")
65
-
66
- return plot_function(frame, *args, **kwargs), plot_function
67
-
68
-
69
- def _NewFrame(
70
- figure: backend_figure_t,
71
- _: int,
72
- __: int,
73
- *args,
74
- title: str | None = None,
75
- dim: dim_e = dim_e.XY,
76
- **kwargs,
77
- ) -> backend_frame_h:
78
- """"""
79
- if dim is dim_e.XY:
80
- output = figure.subplots(*args, **kwargs)
81
- elif dim is dim_e.XYZ:
82
- # See note below
83
- output = backend_frame_3d_t(figure, *args, auto_add_to_figure=False, **kwargs)
84
- figure.add_axes(output)
85
- else:
86
- raise NotImplementedError(f"{dim}: Dimension management not implemented yet")
87
- if title is not None:
88
- output.set_title(title)
89
-
90
- return output
91
-
92
-
93
- def _AdjustLayout(figure: figure_t, /) -> None:
94
- """"""
95
- raw_figure = figure.backend
96
-
97
- if figure.title is not None:
98
- raw_figure.suptitle(figure.title)
99
- for frame in figure.frames:
100
- if frame.title is not None:
101
- frame.backend.set_title(frame.title)
102
- for plot in frame.plots:
103
- if plot.title is not None:
104
- plot.backend.set_label(plot.title)
105
-
106
- if figure.frames.__len__() < 2:
107
- return
108
-
109
- grid_spec = grid_spec_t(*figure.shape, figure=raw_figure)
110
- bottoms, tops, lefts, rights = grid_spec.get_grid_positions(raw_figure)
111
-
112
- for frame, (row, col) in zip(figure.frames, figure.locations):
113
- left, bottom, width, height = (
114
- lefts[col],
115
- bottoms[row],
116
- rights[col] - lefts[col],
117
- tops[row] - bottoms[row],
118
- )
119
- frame.backend.set_position((left, bottom, width, height))
120
-
121
-
122
- def _Show(
123
- figure: figure_t,
124
- /,
125
- ) -> None:
126
- """"""
127
- raw = figure.backend
128
-
129
- raw.show()
130
-
131
- event_manager = raw.canvas
132
- event_manager.mpl_connect("close_event", lambda _: event_manager.stop_event_loop())
133
- event_manager.start_event_loop()
134
-
135
-
136
39
  def _DefaultProperties(type_: h.Callable, /) -> dict[str, h.Any]:
137
40
  """"""
138
41
  name = type_.__name__
@@ -151,16 +54,16 @@ def _SetProperty(
151
54
  if isinstance(element, h.Sequence):
152
55
  elements = element
153
56
  for element in elements:
154
- _SetProperty(element, name, value)
57
+ _SetProperty(element.raw, name, value)
155
58
  return
156
59
 
157
60
  if name == "marker":
158
61
  new_marker = marker_style_t(value)
159
- element.set_paths((new_marker.get_path(),))
62
+ element.raw.set_paths((new_marker.get_path(),))
160
63
  else:
161
64
  property_ = {name: value}
162
65
  try:
163
- pypl.setp(element, **property_)
66
+ pypl.setp(element.raw, **property_)
164
67
  except AttributeError:
165
68
  L.error(
166
69
  f'Property "{name}": Invalid property for element of type "{type(element).__name__}"'
@@ -172,10 +75,10 @@ def _Property(
172
75
  ) -> h.Any:
173
76
  """"""
174
77
  if isinstance(element, h.Sequence):
175
- return _Property(element[0], name)
78
+ return _Property(element[0].raw, name)
176
79
 
177
80
  try:
178
- output = pypl.getp(element, property=name)
81
+ output = pypl.getp(element.raw, property=name)
179
82
  except AttributeError:
180
83
  output = None
181
84
  L.error(
@@ -185,41 +88,136 @@ def _Property(
185
88
  return output
186
89
 
187
90
 
188
- # noinspection PyTypeChecker
189
- plot_t: type[base_plot_t] = type(
190
- "plot_t",
191
- (base_plot_t,),
192
- {
193
- "BackendDefaultProperties": staticmethod(_DefaultProperties),
194
- "BackendSetProperty": staticmethod(_SetProperty),
195
- "BackendProperty": staticmethod(_Property),
196
- },
197
- )
198
- # noinspection PyTypeChecker
199
- frame_t: type[base_frame_t] = type(
200
- "frame_t",
201
- (base_frame_t,),
202
- {
203
- "plot_class": plot_t,
204
- "NewBackendPlot": staticmethod(_NewPlot),
205
- "BackendSetProperty": staticmethod(_SetProperty),
206
- "BackendProperty": staticmethod(_Property),
207
- },
208
- )
209
- # noinspection PyTypeChecker
210
- figure_t: type[base_figure_t] = type(
211
- "figure_t",
212
- (base_figure_t,),
213
- {
214
- "frame_class": frame_t,
215
- "NewBackendFigure": staticmethod(NewBackendFigure),
216
- "NewBackendFrame": staticmethod(_NewFrame),
217
- "AdjustLayout": _AdjustLayout,
218
- "BackendShow": _Show,
219
- "BackendSetProperty": staticmethod(_SetProperty),
220
- "BackendProperty": staticmethod(_Property),
221
- },
222
- )
91
+ @d.dataclass(slots=True, repr=False, eq=False)
92
+ class plot_t(base_plot_t):
93
+ _BackendDefaultProperties: h.ClassVar[h.Callable] = _DefaultProperties
94
+ _BackendSetProperty: h.ClassVar[h.Callable] = _SetProperty
95
+ _BackendProperty: h.ClassVar[h.Callable] = _Property
96
+
97
+
98
+ @d.dataclass(slots=True, repr=False, eq=False)
99
+ class frame_t(base_frame_t):
100
+ _BackendSetProperty: h.ClassVar[h.Callable] = _SetProperty
101
+ _BackendProperty: h.ClassVar[h.Callable] = _Property
102
+
103
+ def _NewPlot(
104
+ self,
105
+ type_: plot_type_h | type[backend_plot_t],
106
+ plot_function: (
107
+ type[backend_plot_t] | h.Callable[..., backend_plot_t | h.Any] | None
108
+ ),
109
+ *args,
110
+ title: str | None = None, # /!\ If _, then it is swallowed by kwargs!
111
+ **kwargs,
112
+ ) -> plot_t:
113
+ """"""
114
+ output = plot_t(
115
+ title=title,
116
+ property=kwargs.copy(),
117
+ backend_name=self.backend_name,
118
+ )
119
+
120
+ if plot_function is None:
121
+ # Next, priority is given to 2-D plots... which might be a problem if a 2-D and
122
+ # 3-D frame have plot types with the same name. For example, scatter in 2-D and
123
+ # 3-D.
124
+ if hasattr(backend_frame_2d_t, type_):
125
+ plot_function = getattr(backend_frame_2d_t, type_)
126
+ elif hasattr(backend_frame_3d_t, type_):
127
+ plot_function = getattr(backend_frame_3d_t, type_)
128
+ else:
129
+ raise ValueError(f"{type_}: Unknown {NAME} graph object.")
130
+
131
+ output.backend_type = plot_function
132
+ output.raw = plot_function(self.raw, *args, **kwargs)
133
+
134
+ return output
135
+
136
+
137
+ @d.dataclass(slots=True, repr=False, eq=False)
138
+ class figure_t(base_figure_t):
139
+ _BackendSetProperty: h.ClassVar[h.Callable] = _SetProperty
140
+ _BackendProperty: h.ClassVar[h.Callable] = _Property
141
+
142
+ @staticmethod
143
+ def _NewBackendFigure(*args, **kwargs) -> backend_figure_t:
144
+ """"""
145
+ return NewBackendFigure(*args, num=None, **kwargs)
146
+
147
+ def _NewFrame(
148
+ self,
149
+ title: str | None,
150
+ dim: dim_e,
151
+ row: int,
152
+ col: int,
153
+ *args,
154
+ **kwargs,
155
+ ) -> frame_t:
156
+ """"""
157
+ output = frame_t(
158
+ title=title,
159
+ dim=dim,
160
+ backend_name=self.backend_name,
161
+ )
162
+
163
+ if dim is dim_e.XY:
164
+ raw = self.raw.subplots(*args, **kwargs)
165
+ elif dim is dim_e.XYZ:
166
+ # See note below
167
+ raw = backend_frame_3d_t(
168
+ self.raw, *args, auto_add_to_figure=False, **kwargs
169
+ )
170
+ self.raw.add_axes(raw)
171
+ else:
172
+ raise NotImplementedError(
173
+ f"{dim}: Dimension management not implemented yet"
174
+ )
175
+ if title is not None:
176
+ raw.set_title(title)
177
+
178
+ output.raw = raw
179
+
180
+ return output
181
+
182
+ def AdjustLayout(self) -> None:
183
+ """"""
184
+ raw = self.raw
185
+
186
+ if self.title is not None:
187
+ raw.suptitle(self.title)
188
+ for frame in self.frames:
189
+ if frame.title is not None:
190
+ frame.raw.set_title(frame.title)
191
+ for plot in frame.plots:
192
+ if plot.title is not None:
193
+ plot.raw.set_label(plot.title)
194
+
195
+ if self.frames.__len__() < 2:
196
+ return
197
+
198
+ grid_spec = grid_spec_t(*self.shape, figure=raw)
199
+ bottoms, tops, lefts, rights = grid_spec.get_grid_positions(raw)
200
+
201
+ for frame, (row, col) in zip(self.frames, self.locations):
202
+ left, bottom, width, height = (
203
+ lefts[col],
204
+ bottoms[row],
205
+ rights[col] - lefts[col],
206
+ tops[row] - bottoms[row],
207
+ )
208
+ frame.raw.set_position((left, bottom, width, height))
209
+
210
+ def _BackendShow(self) -> None:
211
+ """"""
212
+ raw = self.raw
213
+
214
+ raw.show()
215
+
216
+ event_manager = raw.canvas
217
+ event_manager.mpl_connect(
218
+ "close_event", lambda _: event_manager.stop_event_loop()
219
+ )
220
+ event_manager.start_event_loop()
223
221
 
224
222
 
225
223
  def _Polygon(
@@ -442,30 +440,30 @@ TRANSLATIONS = {
442
440
  (backend_frame_3d_t.scatter, 2): "zs",
443
441
  }
444
442
 
443
+ """
444
+ From: https://matplotlib.org/stable/api/prev_api_changes/api_changes_3.4.0.html
445
+ *Axes3D automatically adding itself to Figure is deprecated*
445
446
 
446
- # From: https://matplotlib.org/stable/api/prev_api_changes/api_changes_3.4.0.html
447
- # *Axes3D automatically adding itself to Figure is deprecated*
448
- #
449
- # New Axes3D objects previously added themselves to figures when they were created,
450
- # unlike all other Axes classes, which lead to them being added twice if
451
- # fig.add_subplot(111, projection='3d') was called.
452
- #
453
- # This behavior is now deprecated and will warn. The new keyword argument
454
- # auto_add_to_figure controls the behavior and can be used to suppress the warning. The
455
- # default value will change to False in Matplotlib 3.5, and any non-False value will be
456
- # an error in Matplotlib 3.6.
457
- #
458
- # In the future, Axes3D will need to be explicitly added to the figure
459
- #
460
- # fig = Figure()
461
- # ax = Axes3d(fig)
462
- # fig.add_axes(ax)
463
- #
464
- # as needs to be done for other axes.Axes subclasses. Or, a 3D projection can be made
465
- # via:
466
- #
467
- # fig.add_subplot(projection='3d')
447
+ New Axes3D objects previously added themselves to figures when they were created,
448
+ unlike all other Axes classes, which lead to them being added twice if
449
+ fig.add_subplot(111, projection='3d') was called.
468
450
 
451
+ This behavior is now deprecated and will warn. The new keyword argument
452
+ auto_add_to_figure controls the behavior and can be used to suppress the warning. The
453
+ default value will change to False in Matplotlib 3.5, and any non-False value will be
454
+ an error in Matplotlib 3.6.
455
+
456
+ In the future, Axes3D will need to be explicitly added to the figure
457
+
458
+ fig = Figure()
459
+ ax = Axes3d(fig)
460
+ fig.add_axes(ax)
461
+
462
+ as needs to be done for other axes.Axes subclasses. Or, a 3D projection can be made
463
+ via:
464
+
465
+ fig.add_subplot(projection='3d')
466
+ """
469
467
 
470
468
  """
471
469
  COPYRIGHT NOTICE