maxplotlibx 0.1__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.
- maxplotlib/__init__.py +3 -0
- maxplotlib/backends/matplotlib/utils.py +136 -0
- maxplotlib/backends/matplotlib/utils_old.py +852 -0
- maxplotlib/backends/plotly/__init__.py +0 -0
- maxplotlib/backends/plotly/utils.py +0 -0
- maxplotlib/canvas/__init__.py +0 -0
- maxplotlib/canvas/canvas.py +526 -0
- maxplotlib/colors/__init__.py +0 -0
- maxplotlib/colors/colors.py +85 -0
- maxplotlib/linestyle/__init__.py +0 -0
- maxplotlib/linestyle/linestyle.py +58 -0
- maxplotlib/objects/__init__.py +0 -0
- maxplotlib/objects/layer.py +20 -0
- maxplotlib/objects/node.py +0 -0
- maxplotlib/objects/path.py +0 -0
- maxplotlib/subfigure/__init__.py +0 -0
- maxplotlib/subfigure/line_plot.py +357 -0
- maxplotlib/subfigure/subfigure.py +3 -0
- maxplotlib/subfigure/tikz_figure.py +497 -0
- maxplotlib/tests/test_canvas.py +7 -0
- maxplotlib/tests/test_imports.py +12 -0
- maxplotlib/tests/test_plot.py +0 -0
- maxplotlibx-0.1.dist-info/METADATA +64 -0
- maxplotlibx-0.1.dist-info/RECORD +27 -0
- maxplotlibx-0.1.dist-info/WHEEL +5 -0
- maxplotlibx-0.1.dist-info/licenses/LICENSE +21 -0
- maxplotlibx-0.1.dist-info/top_level.txt +1 -0
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import plotly.graph_objects as go
|
|
4
|
+
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
|
5
|
+
|
|
6
|
+
import maxplotlib.subfigure.tikz_figure as tf
|
|
7
|
+
from maxplotlib.objects.layer import Tikzlayer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Node:
|
|
11
|
+
def __init__(self, x, y, label="", content="", layer=0, **kwargs):
|
|
12
|
+
self.x = x
|
|
13
|
+
self.y = y
|
|
14
|
+
self.label = label
|
|
15
|
+
self.content = content
|
|
16
|
+
self.layer = layer
|
|
17
|
+
self.options = kwargs
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Path:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
nodes,
|
|
24
|
+
path_actions=[],
|
|
25
|
+
cycle=False,
|
|
26
|
+
label="",
|
|
27
|
+
layer=0,
|
|
28
|
+
**kwargs,
|
|
29
|
+
):
|
|
30
|
+
self.nodes = nodes
|
|
31
|
+
self.path_actions = path_actions
|
|
32
|
+
self.cycle = cycle
|
|
33
|
+
self.layer = layer
|
|
34
|
+
self.label = label
|
|
35
|
+
self.options = kwargs
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LinePlot:
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
title: str | None = None,
|
|
42
|
+
grid: bool = False,
|
|
43
|
+
legend: bool = False,
|
|
44
|
+
xmin: float | int | None = None,
|
|
45
|
+
xmax: float | int | None = None,
|
|
46
|
+
ymin: float | int | None = None,
|
|
47
|
+
ymax: float | int | None = None,
|
|
48
|
+
xlabel: str | None = None,
|
|
49
|
+
ylabel: str | None = None,
|
|
50
|
+
xscale: float | int = 1.0,
|
|
51
|
+
yscale: float | int = 1.0,
|
|
52
|
+
xshift: float | int = 0.0,
|
|
53
|
+
yshift: float | int = 0.0,
|
|
54
|
+
):
|
|
55
|
+
"""
|
|
56
|
+
Initialize the LinePlot class for a subplot.
|
|
57
|
+
|
|
58
|
+
Parameters:
|
|
59
|
+
title (str): Title of the plot.
|
|
60
|
+
caption (str): Caption for the plot.
|
|
61
|
+
description (str): Description of the plot.
|
|
62
|
+
label (str): Label for the plot.
|
|
63
|
+
grid (bool): Whether to display grid lines (default is False).
|
|
64
|
+
legend (bool): Whether to display legend (default is False).
|
|
65
|
+
xmin, xmax, ymin, ymax (float): Axis limits.
|
|
66
|
+
xlabel, ylabel (str): Axis labels.
|
|
67
|
+
xscale, yscale (float): Scaling factors for axes.
|
|
68
|
+
xshift, yshift (float): Shifts for axes.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
self._title = title
|
|
72
|
+
self._grid = grid
|
|
73
|
+
self._legend = legend
|
|
74
|
+
self._xmin = xmin
|
|
75
|
+
self._xmax = xmax
|
|
76
|
+
self._ymin = ymin
|
|
77
|
+
self._ymax = ymax
|
|
78
|
+
self._xlabel = xlabel
|
|
79
|
+
self._ylabel = ylabel
|
|
80
|
+
self._xscale = xscale
|
|
81
|
+
self._yscale = yscale
|
|
82
|
+
self._xshift = xshift
|
|
83
|
+
self._yshift = yshift
|
|
84
|
+
|
|
85
|
+
# List to store line data, each entry contains x and y data, label, and plot kwargs
|
|
86
|
+
self.line_data = []
|
|
87
|
+
self.layered_line_data = {}
|
|
88
|
+
|
|
89
|
+
# Initialize lists to hold Node and Path objects
|
|
90
|
+
self.nodes = []
|
|
91
|
+
self.paths = []
|
|
92
|
+
|
|
93
|
+
# Counter for unnamed nodes
|
|
94
|
+
self._node_counter = 0
|
|
95
|
+
|
|
96
|
+
def add_caption(self, caption):
|
|
97
|
+
self._caption = caption
|
|
98
|
+
|
|
99
|
+
def _add(self, obj, layer):
|
|
100
|
+
self.line_data.append(obj)
|
|
101
|
+
if layer in self.layered_line_data:
|
|
102
|
+
self.layered_line_data[layer].append(obj)
|
|
103
|
+
else:
|
|
104
|
+
self.layered_line_data[layer] = [obj]
|
|
105
|
+
|
|
106
|
+
def add_line(
|
|
107
|
+
self,
|
|
108
|
+
x_data,
|
|
109
|
+
y_data,
|
|
110
|
+
layer=0,
|
|
111
|
+
plot_type="plot",
|
|
112
|
+
**kwargs,
|
|
113
|
+
):
|
|
114
|
+
"""
|
|
115
|
+
Add a line to the plot.
|
|
116
|
+
|
|
117
|
+
Parameters:
|
|
118
|
+
label (str): Label for the line.
|
|
119
|
+
x_data (list): X-axis data.
|
|
120
|
+
y_data (list): Y-axis data.
|
|
121
|
+
**kwargs: Additional keyword arguments for the plot (e.g., color, linestyle).
|
|
122
|
+
"""
|
|
123
|
+
ld = {
|
|
124
|
+
"x": np.array(x_data),
|
|
125
|
+
"y": np.array(y_data),
|
|
126
|
+
"layer": layer,
|
|
127
|
+
"plot_type": plot_type,
|
|
128
|
+
"kwargs": kwargs,
|
|
129
|
+
}
|
|
130
|
+
self._add(ld, layer)
|
|
131
|
+
|
|
132
|
+
def add_imshow(self, data, layer=0, plot_type="imshow", **kwargs):
|
|
133
|
+
ld = {
|
|
134
|
+
"data": np.array(data),
|
|
135
|
+
"layer": layer,
|
|
136
|
+
"plot_type": plot_type,
|
|
137
|
+
"kwargs": kwargs,
|
|
138
|
+
}
|
|
139
|
+
self._add(ld, layer)
|
|
140
|
+
|
|
141
|
+
def add_patch(self, patch, layer=0, plot_type="patch", **kwargs):
|
|
142
|
+
ld = {
|
|
143
|
+
"patch": patch,
|
|
144
|
+
"layer": layer,
|
|
145
|
+
"plot_type": plot_type,
|
|
146
|
+
"kwargs": kwargs,
|
|
147
|
+
}
|
|
148
|
+
self._add(ld, layer)
|
|
149
|
+
|
|
150
|
+
def add_colorbar(self, label="", layer=0, plot_type="colorbar", **kwargs):
|
|
151
|
+
cb = {
|
|
152
|
+
"label": label,
|
|
153
|
+
"layer": layer,
|
|
154
|
+
"plot_type": plot_type,
|
|
155
|
+
"kwargs": kwargs,
|
|
156
|
+
}
|
|
157
|
+
self._add(cb, layer)
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def layers(self):
|
|
161
|
+
layers = []
|
|
162
|
+
for layer_name, layer_lines in self.layered_line_data.items():
|
|
163
|
+
layers.append(layer_name)
|
|
164
|
+
return layers
|
|
165
|
+
|
|
166
|
+
def plot_matplotlib(self, ax, layers=None):
|
|
167
|
+
"""
|
|
168
|
+
Plot all lines on the provided axis.
|
|
169
|
+
|
|
170
|
+
Parameters:
|
|
171
|
+
ax (matplotlib.axes.Axes): Axis on which to plot the lines.
|
|
172
|
+
"""
|
|
173
|
+
for layer_name, layer_lines in self.layered_line_data.items():
|
|
174
|
+
if layers and layer_name not in layers:
|
|
175
|
+
continue
|
|
176
|
+
for line in layer_lines:
|
|
177
|
+
if line["plot_type"] == "plot":
|
|
178
|
+
ax.plot(
|
|
179
|
+
(line["x"] + self._xshift) * self._xscale,
|
|
180
|
+
(line["y"] + self._yshift) * self._yscale,
|
|
181
|
+
**line["kwargs"],
|
|
182
|
+
)
|
|
183
|
+
elif line["plot_type"] == "scatter":
|
|
184
|
+
ax.scatter(
|
|
185
|
+
(line["x"] + self._xshift) * self._xscale,
|
|
186
|
+
(line["y"] + self._yshift) * self._yscale,
|
|
187
|
+
**line["kwargs"],
|
|
188
|
+
)
|
|
189
|
+
elif line["plot_type"] == "imshow":
|
|
190
|
+
im = ax.imshow(
|
|
191
|
+
line["data"],
|
|
192
|
+
**line["kwargs"],
|
|
193
|
+
)
|
|
194
|
+
elif line["plot_type"] == "patch":
|
|
195
|
+
ax.add_patch(
|
|
196
|
+
line["patch"],
|
|
197
|
+
**line["kwargs"],
|
|
198
|
+
)
|
|
199
|
+
elif line["plot_type"] == "colorbar":
|
|
200
|
+
divider = make_axes_locatable(ax)
|
|
201
|
+
cax = divider.append_axes("right", size="5%", pad=0.05)
|
|
202
|
+
plt.colorbar(im, cax=cax, label="Potential (V)")
|
|
203
|
+
if self._title:
|
|
204
|
+
ax.set_title(self._title)
|
|
205
|
+
if self._xlabel:
|
|
206
|
+
ax.set_xlabel(self._xlabel)
|
|
207
|
+
if self._ylabel:
|
|
208
|
+
ax.set_ylabel(self._ylabel)
|
|
209
|
+
if self._legend and len(self.line_data) > 0:
|
|
210
|
+
ax.legend()
|
|
211
|
+
if self._grid:
|
|
212
|
+
ax.grid()
|
|
213
|
+
if self.xmin:
|
|
214
|
+
ax.axis(xmin=self.xmin)
|
|
215
|
+
if self.xmax:
|
|
216
|
+
ax.axis(xmax=self.xmax)
|
|
217
|
+
if self.ymin:
|
|
218
|
+
ax.axis(ymin=self.ymin)
|
|
219
|
+
if self.ymax:
|
|
220
|
+
ax.axis(ymax=self.ymax)
|
|
221
|
+
|
|
222
|
+
def plot_plotly(self):
|
|
223
|
+
"""
|
|
224
|
+
Plot all lines using Plotly and return a list of traces for each line.
|
|
225
|
+
"""
|
|
226
|
+
# Mapping Matplotlib linestyles to Plotly dash styles
|
|
227
|
+
linestyle_map = {
|
|
228
|
+
"solid": "solid",
|
|
229
|
+
"dashed": "dash",
|
|
230
|
+
"dotted": "dot",
|
|
231
|
+
"dashdot": "dashdot",
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
traces = []
|
|
235
|
+
for line in self.line_data:
|
|
236
|
+
trace = go.Scatter(
|
|
237
|
+
x=(line["x"] + self._xshift) * self._xscale,
|
|
238
|
+
y=(line["y"] + self._yshift) * self._yscale,
|
|
239
|
+
mode="lines+markers" if "marker" in line["kwargs"] else "lines",
|
|
240
|
+
name=line["kwargs"].get("label", ""),
|
|
241
|
+
line=dict(
|
|
242
|
+
color=line["kwargs"].get("color", None),
|
|
243
|
+
dash=linestyle_map.get(
|
|
244
|
+
line["kwargs"].get("linestyle", "solid"),
|
|
245
|
+
"solid",
|
|
246
|
+
),
|
|
247
|
+
),
|
|
248
|
+
)
|
|
249
|
+
traces.append(trace)
|
|
250
|
+
|
|
251
|
+
return traces
|
|
252
|
+
|
|
253
|
+
def add_node(self, x, y, label=None, content="", layer=0, **kwargs):
|
|
254
|
+
"""
|
|
255
|
+
Add a node to the TikZ figure.
|
|
256
|
+
|
|
257
|
+
Parameters:
|
|
258
|
+
- x (float): X-coordinate of the node.
|
|
259
|
+
- y (float): Y-coordinate of the node.
|
|
260
|
+
- label (str, optional): Label of the node. If None, a default label will be assigned.
|
|
261
|
+
- **kwargs: Additional TikZ node options (e.g., shape, color).
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
- node (Node): The Node object that was added.
|
|
265
|
+
"""
|
|
266
|
+
if label is None:
|
|
267
|
+
label = f"node{self._node_counter}"
|
|
268
|
+
node = Node(x=x, y=y, label=label, layer=layer, content=content, **kwargs)
|
|
269
|
+
self.nodes.append(node)
|
|
270
|
+
if layer in self.layers:
|
|
271
|
+
self.layers[layer].add(node)
|
|
272
|
+
else:
|
|
273
|
+
# print(f"{self.layers = } {layer = }")
|
|
274
|
+
self.layers[layer] = Tikzlayer(layer)
|
|
275
|
+
self.layers[layer].add(node)
|
|
276
|
+
self._node_counter += 1
|
|
277
|
+
return node
|
|
278
|
+
|
|
279
|
+
def add_path(self, nodes, layer=0, **kwargs):
|
|
280
|
+
"""
|
|
281
|
+
Add a line or path connecting multiple nodes.
|
|
282
|
+
|
|
283
|
+
Parameters:
|
|
284
|
+
- nodes (list of str): List of node names to connect.
|
|
285
|
+
- **kwargs: Additional TikZ path options (e.g., style, color).
|
|
286
|
+
|
|
287
|
+
Examples:
|
|
288
|
+
- add_path(['A', 'B', 'C'], color='blue')
|
|
289
|
+
Connects nodes A -> B -> C with a blue line.
|
|
290
|
+
"""
|
|
291
|
+
if not isinstance(nodes, list):
|
|
292
|
+
raise ValueError("nodes parameter must be a list of node names.")
|
|
293
|
+
|
|
294
|
+
nodes = [
|
|
295
|
+
(
|
|
296
|
+
node
|
|
297
|
+
if isinstance(node, Node)
|
|
298
|
+
else (
|
|
299
|
+
self.get_node(node)
|
|
300
|
+
if isinstance(node, str)
|
|
301
|
+
else ValueError(f"Invalid node type: {type(node)}")
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
for node in nodes
|
|
305
|
+
]
|
|
306
|
+
path = Path(nodes, **kwargs)
|
|
307
|
+
self.paths.append(path)
|
|
308
|
+
if layer in self.layers:
|
|
309
|
+
self.layers[layer].add(path)
|
|
310
|
+
else:
|
|
311
|
+
self.layers[layer] = Tikzlayer(layer)
|
|
312
|
+
self.layers[layer].add(path)
|
|
313
|
+
return path
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def xmin(self):
|
|
317
|
+
return self._xmin
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def xmax(self):
|
|
321
|
+
return self._xmax
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def ymin(self):
|
|
325
|
+
return self._ymin
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def ymax(self):
|
|
329
|
+
return self._ymax
|
|
330
|
+
|
|
331
|
+
# Getter and Setter for grid
|
|
332
|
+
@property
|
|
333
|
+
def grid(self):
|
|
334
|
+
return self._grid
|
|
335
|
+
|
|
336
|
+
@grid.setter
|
|
337
|
+
def grid(self, value):
|
|
338
|
+
self._grid = value
|
|
339
|
+
|
|
340
|
+
# Getter and Setter for legend
|
|
341
|
+
@property
|
|
342
|
+
def legend(self):
|
|
343
|
+
return self._legend
|
|
344
|
+
|
|
345
|
+
@legend.setter
|
|
346
|
+
def legend(self, value):
|
|
347
|
+
self._legend = value
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
if __name__ == "__main__":
|
|
351
|
+
plotter = LinePlot()
|
|
352
|
+
plotter.add_line("Line 1", [0, 1, 2, 3], [0, 1, 4, 9])
|
|
353
|
+
plotter.add_line("Line 2", [0, 1, 2, 3], [0, 2, 3, 6])
|
|
354
|
+
latex_code = plotter.generate_latex_plot()
|
|
355
|
+
with open("figures/latex_code.tex", "w") as f:
|
|
356
|
+
f.write(latex_code)
|
|
357
|
+
print(latex_code)
|