py-pluto 1.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. pyPLUTO/__init__.py +22 -0
  2. pyPLUTO/amr.py +745 -0
  3. pyPLUTO/baseloadmixin.py +258 -0
  4. pyPLUTO/baseloadstate.py +45 -0
  5. pyPLUTO/codes/echo_load.py +161 -0
  6. pyPLUTO/configure.py +261 -0
  7. pyPLUTO/gui/config.py +174 -0
  8. pyPLUTO/gui/custom_var.py +435 -0
  9. pyPLUTO/gui/globals.py +108 -0
  10. pyPLUTO/gui/main.py +17 -0
  11. pyPLUTO/gui/main_window.py +177 -0
  12. pyPLUTO/gui/panels.py +66 -0
  13. pyPLUTO/gui/utils.py +273 -0
  14. pyPLUTO/h_pypluto.py +84 -0
  15. pyPLUTO/image.py +302 -0
  16. pyPLUTO/imagefuncs/colorbar.py +240 -0
  17. pyPLUTO/imagefuncs/contour.py +254 -0
  18. pyPLUTO/imagefuncs/create_axes.py +464 -0
  19. pyPLUTO/imagefuncs/display.py +306 -0
  20. pyPLUTO/imagefuncs/figure.py +395 -0
  21. pyPLUTO/imagefuncs/imagetools.py +487 -0
  22. pyPLUTO/imagefuncs/interactive.py +403 -0
  23. pyPLUTO/imagefuncs/legend.py +250 -0
  24. pyPLUTO/imagefuncs/plot.py +311 -0
  25. pyPLUTO/imagefuncs/range.py +242 -0
  26. pyPLUTO/imagefuncs/scatter.py +270 -0
  27. pyPLUTO/imagefuncs/set_axis.py +497 -0
  28. pyPLUTO/imagefuncs/streamplot.py +297 -0
  29. pyPLUTO/imagefuncs/zoom.py +428 -0
  30. pyPLUTO/imagemixin.py +259 -0
  31. pyPLUTO/imagestate.py +45 -0
  32. pyPLUTO/load.py +447 -0
  33. pyPLUTO/loadfuncs/baseloadtools.py +71 -0
  34. pyPLUTO/loadfuncs/codeselection.py +48 -0
  35. pyPLUTO/loadfuncs/defpluto.py +123 -0
  36. pyPLUTO/loadfuncs/descriptor.py +102 -0
  37. pyPLUTO/loadfuncs/findfiles.py +182 -0
  38. pyPLUTO/loadfuncs/findformat.py +245 -0
  39. pyPLUTO/loadfuncs/initload.py +203 -0
  40. pyPLUTO/loadfuncs/loadvars.py +227 -0
  41. pyPLUTO/loadfuncs/offsetdata.py +87 -0
  42. pyPLUTO/loadfuncs/offsetfluid.py +408 -0
  43. pyPLUTO/loadfuncs/read_files.py +213 -0
  44. pyPLUTO/loadfuncs/readdata.py +619 -0
  45. pyPLUTO/loadfuncs/readdata_old.py +567 -0
  46. pyPLUTO/loadfuncs/readdefplini.py +101 -0
  47. pyPLUTO/loadfuncs/readfluid.py +479 -0
  48. pyPLUTO/loadfuncs/readformat.py +277 -0
  49. pyPLUTO/loadfuncs/readgridalone.py +224 -0
  50. pyPLUTO/loadfuncs/readgridfile.py +255 -0
  51. pyPLUTO/loadfuncs/readgridout.py +451 -0
  52. pyPLUTO/loadfuncs/readpart.py +419 -0
  53. pyPLUTO/loadfuncs/readtab.py +105 -0
  54. pyPLUTO/loadfuncs/write_files.py +283 -0
  55. pyPLUTO/loadmixin.py +419 -0
  56. pyPLUTO/loadpart.py +233 -0
  57. pyPLUTO/loadstate.py +68 -0
  58. pyPLUTO/newload.py +81 -0
  59. pyPLUTO/pytools.py +145 -0
  60. pyPLUTO/toolfuncs/findlines.py +551 -0
  61. pyPLUTO/toolfuncs/fourier.py +149 -0
  62. pyPLUTO/toolfuncs/nabla.py +676 -0
  63. pyPLUTO/toolfuncs/parttools.py +152 -0
  64. pyPLUTO/toolfuncs/transform.py +638 -0
  65. pyPLUTO/utils/annotator.py +27 -0
  66. pyPLUTO/utils/inspector.py +145 -0
  67. pyPLUTO/utils/make_docstrings.py +3 -0
  68. py_pluto-1.1.4.dist-info/METADATA +218 -0
  69. py_pluto-1.1.4.dist-info/RECORD +73 -0
  70. py_pluto-1.1.4.dist-info/WHEEL +5 -0
  71. py_pluto-1.1.4.dist-info/entry_points.txt +2 -0
  72. py_pluto-1.1.4.dist-info/licenses/LICENSE +27 -0
  73. py_pluto-1.1.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,306 @@
1
+ """Module to manage the display of 2D plots in the image."""
2
+
3
+ from typing import Any
4
+
5
+ import numpy as np
6
+ from matplotlib.collections import QuadMesh
7
+ from numpy.typing import ArrayLike
8
+
9
+ from pyPLUTO.imagefuncs.colorbar import ColorbarManager
10
+ from pyPLUTO.imagefuncs.imagetools import ImageToolsManager
11
+ from pyPLUTO.imagefuncs.range import RangeManager
12
+ from pyPLUTO.imagefuncs.set_axis import AxisManager
13
+ from pyPLUTO.imagemixin import ImageMixin
14
+ from pyPLUTO.imagestate import ImageState
15
+ from pyPLUTO.utils.inspector import track_kwargs
16
+
17
+
18
+ class DisplayManager(ImageMixin):
19
+ """Class to manage the display of 2D plots in the image.
20
+
21
+ This class provides methods to create and manage 2D plots using matplotlib's
22
+ pcolormesh function. It allows for customization of the plot's appearance,
23
+ colorbar, axes, and other properties.
24
+ """
25
+
26
+ exposed_methods = ("display",)
27
+
28
+ def __init__(self, state: ImageState) -> None:
29
+ """Initialize the DisplayManager with the given state."""
30
+ self.state = state
31
+ self.ColorbarManager = ColorbarManager(state)
32
+ self.ImageToolsManager = ImageToolsManager(state)
33
+ self.RangeManager = RangeManager(state)
34
+ self.AxisManager = AxisManager(state)
35
+
36
+ @track_kwargs
37
+ def display(
38
+ self,
39
+ var: ArrayLike,
40
+ check: bool = True,
41
+ **kwargs: Any,
42
+ ) -> QuadMesh:
43
+ """Plot for a 2D function using the matplotlib's pcolormesh function.
44
+
45
+ A simple figure and a single axis can also be
46
+ created.
47
+
48
+ Returns
49
+ -------
50
+ - The 2D plot
51
+
52
+ Parameters
53
+ ----------
54
+ - alpha: float, default 1.0
55
+ Sets the transparency of the plot.
56
+ - aspect: {'auto', 'equal', float}, default 'auto'
57
+ Sets the aspect ratio of the plot.
58
+ The 'auto' keyword is the default option (most likely the plot will
59
+ be squared). The 'equal' keyword will set the same scaling for
60
+ x and y. A float will fix the ratio between the y-scale and the
61
+ x-scale (1.0 is the same as 'equal').
62
+ - ax: ax | int | None, default None
63
+ The axis where to plot the lines. If None, a new axis is created.
64
+ If 'old', the last considered axis will be used.
65
+ - bottom: float, default 0.1
66
+ The space from the bottom border to the plot.
67
+ - clabel: str, default None
68
+ Sets the label of the colorbar.
69
+ - cmap: str, default 'plasma'
70
+ Selects the colormap. If not defined, the colormap 'plasma' will be
71
+ adopted. Some useful colormaps are: plasma, magma, seismic. Please
72
+ avoid using colorbars like jet or rainbow, which are not
73
+ perceptively uniform and not suited for people with vision
74
+ deficiencies.
75
+ - cpad: float, default 0.07
76
+ Fraction of original axes between colorbar and the axes (in case cax
77
+ is not defined).
78
+ - cpos: {'top','bottom','left','right'}, default None
79
+ Enables the colorbar (if defined), default position on the right.
80
+ - cscale: {'linear','log','symlog','twoslope'}, default 'linear'
81
+ Sets the colorbar scale. Default is the linear ('norm') scale.
82
+ - cticks: {[float], None}, default None
83
+ If enabled (and different from None), sets manually ticks on the
84
+ colorbar.
85
+ - ctickslabels: str, default None
86
+ If enabled, sets manually ticks labels on the colorbar.
87
+ - extend: {'neither','both','min','max'}, default 'neither'
88
+ Sets the extension of the triangular colorbar extension.
89
+ - extendrect: bool, default False
90
+ If True, the colorbar extension will be rectangular.
91
+ - figsize: [float, float], default [6*sqrt(ncol),5*sqrt(nrow)]
92
+ Sets the figure size. The default value is computed from the number
93
+ of rows and columns.
94
+ - fontsize: float, default 17.0
95
+ Sets the fontsize for all the axes.
96
+ - grid: Bool, default False
97
+ Enables the grid on the plot.
98
+ - labelsize: float, default fontsize
99
+ Sets the labels fontsize (which is the same for both labels).
100
+ The default value corresponds to the value of the keyword
101
+ 'fontsize'.
102
+ - left: float, default 0.125
103
+ The space from the left border to the plot.
104
+ - minorticks: str, default None
105
+ If not None enables the minor ticks on the plot (for both grid
106
+ axes).
107
+ - proj: str, default None
108
+ Custom projection for the plot (e.g. 3D). Recommended only if
109
+ needed.
110
+ This keyword should be used only if the axis is created.
111
+ WARNING: pyPLUTO does not support 3D plotting for now, only 3D axes.
112
+ The 3D plot feature will be available in future releases.
113
+ - right: float, default 0.9
114
+ The space from the right border to the plot.
115
+ - shading: {'flat,'nearest','auto','gouraud'}, default 'auto'
116
+ The shading between the grid points. If not defined, the shading
117
+ will one between 'flat' and 'nearest' depending on the size of the
118
+ x,y and z arrays. The 'flat' shading works only if, given a NxM
119
+ z-array, the x- and y-arrays have sizes of, respectively, N+1 and
120
+ M+1. All the other shadings require a N x-array and a M y-array.
121
+ - ticksdir: {'in', 'out'}, default 'in'
122
+ Sets the ticks direction. The default option is 'in'.
123
+ - tickssize: float, default fontsize
124
+ Sets the ticks fontsize (which is the same for both grid axes).
125
+ The default value corresponds to the value of the keyword
126
+ 'fontsize'.
127
+ - title: str, default None
128
+ Places the title of the plot on top of it.
129
+ - titlesize: float, default fontsize
130
+ Sets the title fontsize. The default value corresponds to the value
131
+ of the keyword 'fontsize'.
132
+ - top: float, default 0.9
133
+ The space from the top border to the plot.
134
+ - transpose: True/False, default False
135
+ Transposes the variable matrix. Use is not recommended if not really
136
+ necessary (e.g. in case of highly customized variables and plots)
137
+ - tresh: float, default max(abs(vmin),vmax)*0.01
138
+ Sets the threshold for the colormap. If not defined, the threshold
139
+ will be set to 1% of the maximum absolute value of the variable.
140
+ The default cases are the following:
141
+ - twoslope colorscale: sets the limit between the two linear
142
+ regimes.
143
+ - symlog: sets the limit between the logaitrhmic and the linear
144
+ regime.
145
+ - var (not optional): 2D array
146
+ The array to be plotted.
147
+ - vmax: float, default max(var)
148
+ The maximum value of the colormap. If not defined, the maximum value
149
+ of z will be taken.
150
+ - vmin: float, default min(var)
151
+ The minimum value of the colormap. If not defined, the minimum value
152
+ of z will be taken.
153
+ - x1: np.ndarray, default 'Default'
154
+ the 'x' array. If not defined, a default array will be generated
155
+ depending on the size of z.
156
+ - x2: np.ndarray, default 'Default'
157
+ the 'y' array. If not defined, a default array will be generated
158
+ depending on the size of z.
159
+ - xrange: [float, float], default 'Default'
160
+ Sets the range in the x-direction. If not defined or set to
161
+ 'Default' the code will compute the range while plotting the data by
162
+ taking the minimum and the maximum values of the x1-array.
163
+ - xscale: {'linear','log'}, default 'linear'
164
+ If enabled (and different from 'Default'), sets automatically the
165
+ scale on the x-axis. Data in log scale should be used with the
166
+ keyword 'log', while data in linear scale should be used with the
167
+ keyword 'linear'.
168
+ - xticks: [float] | None | bool, default True
169
+ If enabled (and different from 'Default'), sets manually ticks on
170
+ x-axis. In order to completely remove the ticks the keyword should
171
+ be used with None.
172
+ - xtickslabels: [str] | None | bool, default True
173
+ If enabled (and different from 'Default'), sets manually the ticks
174
+ labels on the x-axis. In order to completely remove the ticks the
175
+ keyword should be used with None. Note that fixed tickslabels should
176
+ always correspond to fixed ticks.
177
+ - xtitle: str, default None
178
+ Sets and places the label of the x-axis.
179
+ - yrange: [float, float], default 'Default'
180
+ Sets the range in the y-direction. If not defined or set to
181
+ 'Default' the code will compute the range while plotting the data by
182
+ taking the minimum and the maximum values of the x2-array.
183
+ - yscale: {'linear','log'}, default 'linear'
184
+ If enabled (and different from 'Default'), sets automatically the
185
+ scale on the y-axis. Data in log scale should be used with the
186
+ keyword 'log', while data in linear scale should be used with the
187
+ keyword 'linear'.
188
+ - yticks: [float] | None | bool, default True
189
+ If enabled (and different from 'Default'), sets manually ticks on
190
+ y-axis. In order to completely remove the ticks the keyword should
191
+ be used with None.
192
+ - ytickslabels: [float] | None | bool, default True
193
+ If enabled (and different from 'Default'), sets manually the ticks
194
+ labels on the y-axis. In order to completely remove the ticks the
195
+ keyword should be used with None. Note that fixed tickslabels should
196
+ always correspond to fixed ticks.
197
+ - ytitle: str, default None
198
+ Sets and places the label of the y-axis.
199
+
200
+ ----
201
+
202
+ Examples
203
+ --------
204
+ - Example #1: create a simple 2d plot with title and colorbar on the
205
+ right
206
+
207
+ >>> import pyPLUTO as pp
208
+ >>> I = pp.Image()
209
+ >>> I.display(var, title="title", cpos="right")
210
+
211
+ - Example #2: create a 2d plot with title on the axes, bottom colorbar
212
+ and custom shading
213
+
214
+ >>> import pyPLUTO as pp
215
+ >>> I = pp.Image()
216
+ >>> I.display(x1, x2, var, xtitle = 'x', ytitle = 'y',
217
+ cpos = 'bottom', shading = 'gouraud', cpad = 0.3)
218
+
219
+ - Example #3: create a 2d plot con custom range on axes and logarithmic
220
+ scale colorbar
221
+
222
+ >>> import pyPLUTO as pp
223
+ >>> I = pp.Image()
224
+ >>> I.display(var, xrange = [2,3], yrange = [2,4], cbar = 'right',
225
+ cscale = 'log')
226
+
227
+ - Example #4: create a 2d plot with a custom symmetric logarithmic
228
+ colorbar with custom ticks.
229
+
230
+ >>> import pyPLUTO as pp
231
+ >>> I = pp.Image()
232
+ >>> I.display(var, cpos = 'right', cmap = 'RdBu_r',
233
+ cscale = 'symlog', tresh = 0.001, vmin = -1, vmax = 1)
234
+
235
+ """
236
+ kwargs.pop("check", check)
237
+
238
+ # Set or create figure and axes
239
+ ax, nax = self.ImageToolsManager.assign_ax(
240
+ kwargs.pop("ax", None), **kwargs
241
+ )
242
+
243
+ if self.fig is None:
244
+ raise ValueError(
245
+ "No figure is present. Please create a figure first."
246
+ )
247
+ # Keyword x1 and x2
248
+ var = np.asarray(var)
249
+ if kwargs.get("transpose", False) is True:
250
+ var = var.T
251
+ x = np.asarray(kwargs.get("x1", np.arange(len(var[:, 0]) + 1)))
252
+ y = np.asarray(kwargs.get("x2", np.arange(len(var[0, :]) + 1)))
253
+
254
+ # Keywords xrange and yrange
255
+ if not kwargs.get("xrange") and self.setax[nax] != 1:
256
+ kwargs["xrange"] = [x.min(), x.max()]
257
+ if not kwargs.get("yrange") and self.setay[nax] != 1:
258
+ kwargs["yrange"] = [y.min(), y.max()]
259
+ # Set ax parameters
260
+ self.AxisManager.set_axis(ax=ax, check=False, **kwargs)
261
+ self.ImageToolsManager.hide_text(nax, ax.texts)
262
+
263
+ # Keywords vmin and vmax
264
+ vmin = kwargs.get("vmin", np.nanmin(var))
265
+ vmax = kwargs.get("vmax", np.nanmax(var))
266
+
267
+ # Keyword for colorbar and colorscale
268
+ cpos = kwargs.get("cpos")
269
+ cscale = kwargs.get("cscale", "norm")
270
+ tresh = kwargs.get("tresh", max(np.abs(vmin), vmax) * 0.01)
271
+ lint = kwargs.get("lint")
272
+ self.vlims[nax] = [vmin, vmax, tresh]
273
+
274
+ # Set the colorbar scale (put in function)
275
+ norm = self.ImageToolsManager.set_cscale(
276
+ cscale, vmin, vmax, tresh, lint
277
+ )
278
+
279
+ # Select shading
280
+ shade = kwargs.get("shading", "auto")
281
+ alpha = kwargs.get("alpha", 1.0)
282
+
283
+ cmap = self.ImageToolsManager.find_cmap(kwargs.get("cmap", "plasma"))
284
+
285
+ # Display the image
286
+ pcm = ax.pcolormesh(
287
+ x,
288
+ y,
289
+ var.T,
290
+ shading=shade,
291
+ cmap=cmap,
292
+ norm=norm,
293
+ linewidth=0,
294
+ rasterized=True,
295
+ alpha=alpha,
296
+ )
297
+
298
+ # Place the colorbar (use colorbar function)
299
+ if cpos is not None:
300
+ self.ColorbarManager.colorbar(pcm, check=False, **kwargs)
301
+
302
+ # If tight_layout is enabled, is re-inforced
303
+ if self.tight:
304
+ self.fig.tight_layout()
305
+
306
+ return pcm
@@ -0,0 +1,395 @@
1
+ """Figure Manager Module."""
2
+
3
+ import shutil
4
+ import warnings
5
+ from typing import Unpack
6
+
7
+ import matplotlib as mpl
8
+ import matplotlib.pyplot as plt
9
+ from matplotlib.figure import Figure
10
+
11
+ from pyPLUTO.imagemixin import ImageMixin
12
+ from pyPLUTO.imagestate import ImageState
13
+ from pyPLUTO.utils.annotator import AllKwargs
14
+ from pyPLUTO.utils.inspector import track_kwargs
15
+
16
+
17
+ class FigureManager(ImageMixin):
18
+ """Manages the figure and sets the style, size, and LaTeX settings."""
19
+
20
+ @track_kwargs
21
+ def __init__(
22
+ self,
23
+ state: ImageState,
24
+ **kwargs: Unpack[AllKwargs],
25
+ ) -> None:
26
+ """Initialize the FigureManager class.
27
+
28
+ It creates a new figure and sets the LaTeX conditions, as well as the
29
+ matplotlib style. Every Image is associated to a figure object and only
30
+ one in order to avoid confusion between images and figures. If you
31
+ want to create multiple figures, you have to create multiple
32
+ Image objects.
33
+
34
+ Returns
35
+ -------
36
+ - None
37
+
38
+ Parameters
39
+ ----------
40
+ - state: ImageState
41
+ The state of the image, which contains the figure and other
42
+ properties.
43
+ - kwargs: dict[str, Any]
44
+ Additional keyword arguments to customize the figure, such as
45
+ `figsize`, `fontsize`, `nwin`, `suptitle`, etc.
46
+
47
+ """
48
+ # needed because the __init__ is longer than simply self.state = state
49
+ self.state = state
50
+
51
+ # Extract specific kwargs for colorlines, with defaults if not provided
52
+ close = kwargs.pop("close", True)
53
+ fontweight = kwargs.pop("fontweight", "normal")
54
+ numcolors = kwargs.pop("numcolors", 10)
55
+ replace = kwargs.pop("replace", False)
56
+ suptitle = kwargs.pop("suptitle", None)
57
+ suptitlesize = kwargs.pop("suptitlesize", "large")
58
+ withblack = kwargs.pop("withblack", False)
59
+ withwhite = kwargs.pop("withwhite", False)
60
+
61
+ self.fig = kwargs.get("fig", self.fig)
62
+ self.figsize = kwargs.get("figsize", self.figsize)
63
+ self.fontsize = kwargs.get("fontsize", self.fontsize)
64
+ self.LaTeX = kwargs.get("LaTeX", self.LaTeX)
65
+ self.nwin = kwargs.get("nwin", self.nwin)
66
+ self.style = kwargs.get("style", self.style)
67
+ self.tight = kwargs.get("tight", self.tight)
68
+
69
+ self.check_previous_fig(close)
70
+ if "figsize" in kwargs:
71
+ self.set_size = True
72
+
73
+ self.setup_style()
74
+ self.color = self.choose_colorlines(numcolors, withblack, withwhite)
75
+ self.assign_LaTeX(fontweight)
76
+ self.create_figure(replace, suptitle, suptitlesize)
77
+
78
+ def setup_style(self) -> None:
79
+ """Set the matplotlib style."""
80
+ try:
81
+ plt.style.use(self.style)
82
+ except OSError:
83
+ warn = f"Warning: Style '{self.style}' not found. \
84
+ Switching to 'default'"
85
+ warnings.warn(warn, UserWarning, stacklevel=2)
86
+ self.style = "default"
87
+
88
+ def choose_colorlines(
89
+ self, numcolors: int, withblack: bool, withwhite: bool
90
+ ) -> list[str]:
91
+ """Choose the colors for the lines.
92
+
93
+ The colors are taken from a list of colors that are suitable for all
94
+ types of color vision deficiencies.
95
+
96
+ Returns
97
+ -------
98
+ - colors: list[str]
99
+ The list of colors for the lines.
100
+
101
+ Parameters
102
+ ----------
103
+ - numcolors: int, default 10
104
+ The number of colors.
105
+ - withblack: bool, default False
106
+ If True, the black color is used as first color.
107
+ - withwhite: bool default False
108
+ If True, the white color is used as first color.
109
+
110
+ ----
111
+
112
+ Examples
113
+ --------
114
+ - Example #1: withblack = True
115
+
116
+ >>> _choose_colorlines(6, True)
117
+
118
+ - Example #2: 12 colors, withwhite = True
119
+
120
+ >>> _choose_colorlines(12, False, True)
121
+
122
+ """
123
+ # New colors dictionary (black and white included)
124
+ self.dictcol = {
125
+ 0: "#ffffff",
126
+ 1: "#e8ecfb",
127
+ 2: "#d9cce3",
128
+ 3: "#d1bbd7",
129
+ 4: "#caaccb",
130
+ 5: "#ae76a3",
131
+ 6: "#aa6f9e",
132
+ 7: "#994f88",
133
+ 8: "#882e72",
134
+ 9: "#0104fe",
135
+ 10: "#1e3888",
136
+ 11: "#437dbf",
137
+ 12: "#5289c7",
138
+ 13: "#6195cf",
139
+ 14: "#7bafde",
140
+ 15: "#4eb265",
141
+ 16: "#90c987",
142
+ 17: "#cae0ab",
143
+ 18: "#f7f056",
144
+ 19: "#f7cb45",
145
+ 20: "#f6c141",
146
+ 21: "#f4a736",
147
+ 22: "#f1932d",
148
+ 23: "#ee8026",
149
+ 24: "#e8601c",
150
+ 25: "#e65518",
151
+ 26: "#dc050c",
152
+ 27: "#a5170e",
153
+ 28: "#72190e",
154
+ 29: "#42150a",
155
+ 30: "#777777",
156
+ 31: "#000000",
157
+ 32: "#0104fe",
158
+ }
159
+
160
+ # Colors are ordered to avoid color vision deficiencies
161
+ lstc = [
162
+ 9,
163
+ 26,
164
+ 15,
165
+ 23,
166
+ 14,
167
+ 17,
168
+ 6,
169
+ 25,
170
+ 28,
171
+ 18,
172
+ 11,
173
+ 2,
174
+ 8,
175
+ 16,
176
+ 10,
177
+ 21,
178
+ 7,
179
+ 27,
180
+ 4,
181
+ 13,
182
+ 19,
183
+ 29,
184
+ 1,
185
+ 30,
186
+ ]
187
+
188
+ # Black and white addition
189
+ lstc = [0, *lstc] if withwhite else [31, *lstc] if withblack else lstc
190
+
191
+ # End of function, return the colors
192
+ return [self.dictcol[lstc[i]] for i in range(numcolors)]
193
+
194
+ def assign_LaTeX(self, fontweight: str) -> None:
195
+ """Set the LaTeX conditions.
196
+
197
+ The option 'pgf' requires XeLaTeX and should be used only to get
198
+ vectorial figures with minimal file size.
199
+
200
+ Returns
201
+ -------
202
+ - None
203
+
204
+ Parameters
205
+ ----------
206
+ - LaTeX (not optional): bool | str
207
+ The LaTeX option. Is True is selected, the default LaTeX font is
208
+ used. If 'pgf' is selected, the pgf backend is used to save pdf
209
+ figures with minimal file size. If XeLaTeX is not installed and the
210
+ 'pgf' option is selected, the LaTeX option True is used as backup
211
+ strategy.
212
+
213
+ ----
214
+
215
+ Examples
216
+ --------
217
+ - Example #1: LaTeX option True
218
+
219
+ >>> _assign_LaTeX(True)
220
+
221
+ - Example #2: LaTeX option 'pgf'
222
+
223
+ >>> _assign_LaTeX("pgf")
224
+
225
+ """
226
+ # LaTeX option 'pgf' (requires XeLaTeX)
227
+ if self.LaTeX == "pgf" and not shutil.which("latex"):
228
+ warn = "LaTeX not installed, switching to LaTeX = True"
229
+ warnings.warn(warn, UserWarning, stacklevel=2)
230
+ self.LaTeX = True
231
+
232
+ if self.LaTeX == "pgf":
233
+ # Set the pgf backend
234
+ try:
235
+ plt.switch_backend("pgf")
236
+
237
+ # Preamble (LaTeX commands and packages)
238
+ pgf_preamble = r"""
239
+ \usepackage{amsmath}
240
+ \usepackage{amssymb}
241
+ \usepackage{mathptmx}
242
+ \usepackage{siunitx}
243
+ \usepackage[T1]{fontenc}
244
+ \newcommand{\DS}{\displaystyle}
245
+ """
246
+
247
+ # Update the rcParams
248
+ mpl.rcParams.update(
249
+ {
250
+ "pgf.preamble": pgf_preamble,
251
+ "font.family": "serif",
252
+ "font.weight": fontweight,
253
+ "text.usetex": True,
254
+ }
255
+ )
256
+
257
+ # If errors occur, the LaTeX option True is used and a warning
258
+ # message is displayed
259
+ except ImportError:
260
+ warn = "The pgf backend is not available, reverting to True\n"
261
+ warnings.warn(warn, UserWarning, stacklevel=2)
262
+ self.LaTeX = True
263
+
264
+ # LaTeX option True: default LaTeX font
265
+ if self.LaTeX is True:
266
+ try:
267
+ mpl.rcParams["mathtext.fontset"] = "stix"
268
+ mpl.rcParams["font.family"] = "STIXGeneral"
269
+ except ImportError:
270
+ warn = "The LaTeX = True option is not available."
271
+ warnings.warn(warn, UserWarning, stacklevel=2)
272
+
273
+ # End of the function
274
+
275
+ def check_previous_fig(self, close: bool) -> None:
276
+ """Check if there is an existing figure.
277
+
278
+ If it exists, the code will check if it is closed or not.
279
+
280
+ Returns
281
+ -------
282
+ - None
283
+
284
+ Parameters
285
+ ----------
286
+ - close: bool, default True
287
+ If True, the existing figure with the same window number is closed.
288
+
289
+ ----
290
+
291
+ Examples
292
+ --------
293
+ - Example #1: Check if there is an existing figure
294
+
295
+ >>> _check_previous_fig(True)
296
+
297
+ """
298
+ if isinstance(self.fig, Figure):
299
+ self.figsize = [
300
+ self.fig.get_figwidth(),
301
+ self.fig.get_figheight(),
302
+ ]
303
+ self.fontsize = plt.rcParams["font.size"]
304
+ try:
305
+ fignum = self.fig.number
306
+ if isinstance(fignum, int):
307
+ self.state.nwin = fignum
308
+ except AttributeError:
309
+ warnings.warn(
310
+ "The figure is not associated to a window number",
311
+ UserWarning,
312
+ stacklevel=2,
313
+ )
314
+ self.nwin = 1
315
+ self.tight = self.fig.get_tight_layout()
316
+
317
+ # Close the existing figure if it exists (and 'close' is enabled).
318
+ # `clf()` releases artists/axes payloads immediately, which prevents
319
+ # stale Image instances (still holding axes/text refs) from retaining
320
+ # heavy plot data in memory.
321
+ if plt.fignum_exists(self.nwin) and close is True:
322
+ existing_fig = plt.figure(self.nwin)
323
+ existing_fig.clf()
324
+ plt.close(existing_fig)
325
+
326
+ def create_figure(
327
+ self, replace: bool, suptitle: str | None, suptitlesize: int | str
328
+ ) -> None:
329
+ """Create the figure associated to an Image instance.
330
+
331
+ It is called by default when the Image class is instantiated.
332
+
333
+ Returns
334
+ -------
335
+ - None
336
+
337
+ Parameters
338
+ ----------
339
+ - close: bool, default True
340
+ If True, the existing figure with the same window number is closed.
341
+ - fig (not optional): Figure | None, default None
342
+ The figure instance. If not None, the figure is used (only if we
343
+ need to associate an Image to an existing figure).
344
+ - figsize: list[float], default [8,5]
345
+ The figure size.
346
+ - fontsize: int, default 17
347
+ The font size.
348
+ - nwin: int, default 1
349
+ The window number.
350
+ - suptitle: str | None, default None
351
+ The super title of the figure.
352
+ - suptitlesize: int | str, default 'large'
353
+ The figure title size.
354
+ - tight: bool, default True
355
+ If True, the tight layout is used.
356
+
357
+ ----
358
+
359
+ Examples
360
+ --------
361
+ - Example #1: Create a new figure
362
+
363
+ >>> _create_figure()
364
+
365
+ - Example #2: Associate an Image to an existing figure
366
+
367
+ >>> _create_figure(fig=fig)
368
+
369
+ - Example #3: Create a new figure with different size and a figure title
370
+
371
+ >>> _create_figure(suptitle="Super Title", figsize=[10, 5])
372
+
373
+ - Example #4: Create a new figure with a specific window number
374
+
375
+ >>> _create_figure(nwin=2)
376
+
377
+ """
378
+ # Create a new figure instance with the provided window number
379
+ if self.fig is None or replace is True:
380
+ self.fig = plt.figure(
381
+ self.nwin,
382
+ figsize=(self.figsize[0], self.figsize[1]),
383
+ )
384
+ plt.rcParams.update({"font.size": self.fontsize})
385
+
386
+ if self.fig is None:
387
+ raise ValueError("The figure could not be created.")
388
+
389
+ # Suptitle
390
+ if suptitle is not None:
391
+ self.fig.suptitle(suptitle, fontsize=suptitlesize)
392
+
393
+ # Tight layout
394
+ if self.tight is True:
395
+ self.fig.tight_layout()