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.
@@ -0,0 +1,497 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+ import tempfile
5
+
6
+ import matplotlib.patches as patches
7
+ import numpy as np
8
+ from matplotlib.image import imread
9
+
10
+ from maxplotlib.colors.colors import Color
11
+ from maxplotlib.linestyle.linestyle import Linestyle
12
+
13
+
14
+ class Tikzlayer:
15
+ def __init__(self, label):
16
+ self.label = label
17
+ self.items = []
18
+
19
+ def add(self, item):
20
+ self.items.append(item)
21
+
22
+ def get_reqs(self):
23
+ reqs = set()
24
+ for item in self.items:
25
+ if isinstance(item, Path):
26
+ for node in item.nodes:
27
+ if not node.layer == self.label:
28
+ reqs.add(node.layer)
29
+ return reqs
30
+
31
+ def generate_tikz(self):
32
+ tikz_script = f"\n% Layer {self.label}\n"
33
+ tikz_script += f"\\begin{{pgfonlayer}}{{{self.label}}}\n"
34
+ for item in self.items:
35
+ tikz_script += item.to_tikz()
36
+ tikz_script += f"\\end{{pgfonlayer}}{{{self.label}}}\n"
37
+ return tikz_script
38
+
39
+
40
+ class TikzWrapper:
41
+ def __init__(self, raw_tikz, label="", content="", layer=0, **kwargs):
42
+ self.raw_tikz = raw_tikz
43
+ self.label = label
44
+ self.content = content
45
+ self.layer = layer
46
+ self.options = kwargs
47
+
48
+ def to_tikz(self):
49
+ return self.raw_tikz
50
+
51
+
52
+ class Node:
53
+ def __init__(self, x, y, label="", content="", layer=0, **kwargs):
54
+ """
55
+ Represents a TikZ node.
56
+
57
+ Parameters:
58
+ - x (float): X-coordinate of the node.
59
+ - y (float): Y-coordinate of the node.
60
+ - name (str, optional): Name of the node. If None, a default name will be assigned.
61
+ - **kwargs: Additional TikZ node options (e.g., shape, color).
62
+ """
63
+ self.x = x
64
+ self.y = y
65
+ self.label = label
66
+ self.content = content
67
+ self.layer = layer
68
+ self.options = kwargs
69
+
70
+ def to_tikz(self):
71
+ """
72
+ Generate the TikZ code for this node.
73
+
74
+ Returns:
75
+ - tikz_str (str): TikZ code string for the node.
76
+ """
77
+ options = ", ".join(
78
+ f"{k.replace('_', ' ')}={v}" for k, v in self.options.items()
79
+ )
80
+ if options:
81
+ options = f"[{options}]"
82
+ return f"\\node{options} ({self.label}) at ({self.x}, {self.y}) {{{self.content}}};\n"
83
+
84
+
85
+ class Path:
86
+ def __init__(
87
+ self,
88
+ nodes,
89
+ path_actions=[],
90
+ cycle=False,
91
+ label="",
92
+ layer=0,
93
+ **kwargs,
94
+ ):
95
+ """
96
+ Represents a path (line) connecting multiple nodes.
97
+
98
+ Parameters:
99
+ - nodes (list of str): List of node names to connect.
100
+ - **kwargs: Additional TikZ path options (e.g., style, color).
101
+ """
102
+ self.nodes = nodes
103
+ self.path_actions = path_actions
104
+ self.cycle = cycle
105
+ self.layer = layer
106
+ self.label = label
107
+ self.options = kwargs
108
+
109
+ def to_tikz(self):
110
+ """
111
+ Generate the TikZ code for this path.
112
+
113
+ Returns:
114
+ - tikz_str (str): TikZ code string for the path.
115
+ """
116
+ options = ", ".join(
117
+ f"{k.replace('_', ' ')}={v}" for k, v in self.options.items()
118
+ )
119
+ if len(self.path_actions) > 0:
120
+ options = ", ".join(self.path_actions) + ", " + options
121
+ if options:
122
+ options = f"[{options}]"
123
+ path_str = " to ".join(f"({node.label}.center)" for node in self.nodes)
124
+ if self.cycle:
125
+ path_str += " -- cycle"
126
+ return f"\\draw{options} {path_str};\n"
127
+
128
+
129
+ class TikzFigure:
130
+ def __init__(self, **kwargs):
131
+ """
132
+ Initialize the TikzFigure class for creating TikZ figures.
133
+
134
+ Parameters:
135
+ **kwargs: Arbitrary keyword arguments.
136
+ - figsize (tuple): Figure size (default is (10, 6)).
137
+ - caption (str): Caption for the figure.
138
+ - description (str): Description of the figure.
139
+ - label (str): Label for the figure.
140
+ - grid (bool): Whether to display grid lines (default is False).
141
+ TODO: Add all options
142
+ """
143
+ # Set default values
144
+ self._figsize = kwargs.get("figsize", (10, 6))
145
+ self._caption = kwargs.get("caption", None)
146
+ self._description = kwargs.get("description", None)
147
+ self._label = kwargs.get("label", None)
148
+ self._grid = kwargs.get("grid", False)
149
+
150
+ # Initialize lists to hold Node and Path objects
151
+ self.nodes = []
152
+ self.paths = []
153
+ self.layers = {}
154
+
155
+ # Counter for unnamed nodes
156
+ self._node_counter = 0
157
+
158
+ def add_node(self, x, y, label=None, content="", layer=0, **kwargs):
159
+ """
160
+ Add a node to the TikZ figure.
161
+
162
+ Parameters:
163
+ - x (float): X-coordinate of the node.
164
+ - y (float): Y-coordinate of the node.
165
+ - label (str, optional): Label of the node. If None, a default label will be assigned.
166
+ - **kwargs: Additional TikZ node options (e.g., shape, color).
167
+
168
+ Returns:
169
+ - node (Node): The Node object that was added.
170
+ """
171
+ if label is None:
172
+ label = f"node{self._node_counter}"
173
+ node = Node(x=x, y=y, label=label, layer=layer, content=content, **kwargs)
174
+ self.nodes.append(node)
175
+ if layer in self.layers:
176
+ self.layers[layer].add(node)
177
+ else:
178
+ self.layers[layer] = Tikzlayer(layer)
179
+ self.layers[layer].add(node)
180
+ self._node_counter += 1
181
+ return node
182
+
183
+ def add_path(self, nodes, layer=0, **kwargs):
184
+ """
185
+ Add a line or path connecting multiple nodes.
186
+
187
+ Parameters:
188
+ - nodes (list of str): List of node names to connect.
189
+ - **kwargs: Additional TikZ path options (e.g., style, color).
190
+
191
+ Examples:
192
+ - add_path(['A', 'B', 'C'], color='blue')
193
+ Connects nodes A -> B -> C with a blue line.
194
+ """
195
+ if not isinstance(nodes, list):
196
+ raise ValueError("nodes parameter must be a list of node names.")
197
+
198
+ nodes = [
199
+ (
200
+ node
201
+ if isinstance(node, Node)
202
+ else (
203
+ self.get_node(node)
204
+ if isinstance(node, str)
205
+ else ValueError(f"Invalid node type: {type(node)}")
206
+ )
207
+ )
208
+ for node in nodes
209
+ ]
210
+ path = Path(nodes, **kwargs)
211
+ self.paths.append(path)
212
+ if layer in self.layers:
213
+ self.layers[layer].add(path)
214
+ else:
215
+ self.layers[layer] = Tikzlayer(layer)
216
+ self.layers[layer].add(path)
217
+ return path
218
+
219
+ def add_raw(self, raw_tikz, layer=0, **kwargs):
220
+ tikz = TikzWrapper(raw_tikz)
221
+ if layer in self.layers:
222
+ self.layers[layer].add(tikz)
223
+ else:
224
+ self.layers[layer] = Tikzlayer(layer)
225
+ self.layers[layer].add(tikz)
226
+ return tikz
227
+
228
+ def get_node(self, node_label):
229
+ for node in self.nodes:
230
+ if node.label == node_label:
231
+ return node
232
+
233
+ def get_layer(self, item):
234
+ for layer, layer_items in self.layers.items():
235
+ if item in [layer_item.label for layer_item in layer_items]:
236
+ return layer
237
+ print(f"Item {item} not found in any layer!")
238
+
239
+ def add_tabs(self, tikz_script):
240
+ tikz_script_new = ""
241
+ tab_str = " "
242
+ num_tabs = 0
243
+ for line in tikz_script.split("\n"):
244
+ if "\\end" in line:
245
+ num_tabs = max(num_tabs - 1, 0)
246
+ tikz_script_new += f"{tab_str*num_tabs}{line}\n"
247
+ if "\\begin" in line:
248
+ num_tabs += 1
249
+ return tikz_script_new
250
+
251
+ def generate_tikz(self):
252
+ """
253
+ Generate the TikZ script for the figure.
254
+
255
+ Returns:
256
+ - tikz_script (str): The TikZ script as a string.
257
+ """
258
+ tikz_script = "\\begin{tikzpicture}\n"
259
+ tikz_script += "% Define the layers library\n"
260
+ layers = sorted([str(layer) for layer in self.layers.keys()])
261
+ for layer in layers:
262
+ tikz_script += f"\\pgfdeclarelayer{{{layer}}}\n"
263
+ tikz_script += f"\\pgfsetlayers{{{','.join(layers)}}}\n"
264
+
265
+ # Add grid if enabled
266
+ # TODO: Create a Grid class
267
+ if self._grid:
268
+ tikz_script += (
269
+ " \\draw[step=1cm, gray, very thin] (-10,-10) grid (10,10);\n"
270
+ )
271
+ ordered_layers = []
272
+ buffered_layers = set()
273
+
274
+ for key, layer in self.layers.items():
275
+ # layer_order, buffered_layers = update_layer_order(layer, layer_order, buffered_layers)
276
+ reqs = layer.get_reqs()
277
+ if all([r == layer.label for r in reqs]):
278
+ ordered_layers.append(layer)
279
+ elif all([r in [l.label for l in ordered_layers] for r in reqs]):
280
+ ordered_layers.append(layer)
281
+ else:
282
+ buffered_layers.add(layer)
283
+
284
+ for buffered_layer in buffered_layers:
285
+ buff_reqs = buffered_layer.get_reqs()
286
+ if all([r in [l.label for l in ordered_layers] for r in buff_reqs]):
287
+ print("Move layer from buffer")
288
+ ordered_layers.append(key)
289
+ buffered_layers.remove(key)
290
+ assert (
291
+ len(buffered_layers) == 0
292
+ ), f"Layer order is impossible for layer {[layer.label for layer in buffered_layers]}"
293
+ for layer in ordered_layers:
294
+ tikz_script += layer.generate_tikz()
295
+
296
+ tikz_script += "\\end{tikzpicture}"
297
+
298
+ # Wrap in figure environment if necessary
299
+ if self._caption or self._description or self._label:
300
+ figure_env = "\\begin{figure}\n" + tikz_script + "\n"
301
+ if self._caption:
302
+ figure_env += f" \\caption{{{self._caption}}}\n"
303
+ if self._label:
304
+ figure_env += f" \\label{{{self._label}}}\n"
305
+ figure_env += "\\end{figure}"
306
+ tikz_script = figure_env
307
+ tikz_script = self.add_tabs(tikz_script)
308
+ return tikz_script
309
+
310
+ def savefig(self, filepath):
311
+ tikz_code = self.generate_tikz()
312
+ with open(filepath, "w") as f:
313
+ f.write(tikz_code)
314
+
315
+ def generate_standalone(self):
316
+ tikz_code = self.generate_tikz()
317
+
318
+ # Create a minimal LaTeX document
319
+ latex_document = (
320
+ "\\documentclass[border=10pt]{standalone}\n"
321
+ "\\usepackage{tikz}\n"
322
+ "\\begin{document}\n"
323
+ f"{tikz_code}\n"
324
+ "\\end{document}"
325
+ )
326
+ return latex_document
327
+
328
+ def compile_pdf(self, filename="output.pdf"):
329
+ """
330
+ Compile the TikZ script into a PDF using pdflatex.
331
+
332
+ Parameters:
333
+ - filename (str): The name of the output PDF file (default is 'output.pdf').
334
+
335
+ Notes:
336
+ - Requires 'pdflatex' to be installed and accessible from the command line.
337
+ """
338
+ latex_document = self.generate_standalone()
339
+
340
+ # Use a temporary directory to store the LaTeX files
341
+ with tempfile.TemporaryDirectory() as tempdir:
342
+ tex_file = os.path.join(tempdir, "figure.tex")
343
+ with open(tex_file, "w") as f:
344
+ f.write(latex_document)
345
+
346
+ # Run pdflatex
347
+ try:
348
+ subprocess.run(
349
+ ["pdflatex", "-interaction=nonstopmode", tex_file],
350
+ cwd=tempdir,
351
+ check=True,
352
+ stdout=subprocess.PIPE,
353
+ stderr=subprocess.PIPE,
354
+ )
355
+ except subprocess.CalledProcessError as e:
356
+ print("An error occurred while compiling the LaTeX document:")
357
+ print(e.stderr.decode())
358
+ return
359
+
360
+ # Move the output PDF to the desired location
361
+ pdf_output = os.path.join(tempdir, "figure.pdf")
362
+ if os.path.exists(pdf_output):
363
+ os.rename(pdf_output, filename)
364
+ print(f"PDF successfully compiled and saved as '{filename}'.")
365
+ else:
366
+ print("PDF compilation failed. Please check the LaTeX log for details.")
367
+
368
+ def plot_matplotlib(self, ax, layers=None):
369
+ """
370
+ Plot all nodes and paths on the provided axis using Matplotlib.
371
+
372
+ Parameters:
373
+ - ax (matplotlib.axes.Axes): Axis on which to plot the figure.
374
+ """
375
+
376
+ # Plot paths first so they appear behind nodes
377
+ for path in self.paths:
378
+ x_coords = [node.x for node in path.nodes]
379
+ y_coords = [node.y for node in path.nodes]
380
+
381
+ # Parse path color
382
+ path_color_spec = path.options.get("color", "black")
383
+ try:
384
+ color = Color(path_color_spec).to_rgb()
385
+ except ValueError as e:
386
+ print(e)
387
+ color = "black"
388
+
389
+ # Parse line width
390
+ line_width_spec = path.options.get("line_width", 1)
391
+ if isinstance(line_width_spec, str):
392
+ match = re.match(r"([\d.]+)(pt)?", line_width_spec)
393
+ if match:
394
+ line_width = float(match.group(1))
395
+ else:
396
+ print(
397
+ f"Invalid line width specification: '{line_width_spec}', defaulting to 1",
398
+ )
399
+ line_width = 1
400
+ else:
401
+ line_width = float(line_width_spec)
402
+
403
+ # Parse line style using Linestyle class
404
+ style_spec = path.options.get("style", "solid")
405
+ linestyle = Linestyle(style_spec).to_matplotlib()
406
+
407
+ ax.plot(
408
+ x_coords,
409
+ y_coords,
410
+ color=color,
411
+ linewidth=line_width,
412
+ linestyle=linestyle,
413
+ zorder=1, # Lower z-order to place behind nodes
414
+ )
415
+
416
+ # Plot nodes after paths so they appear on top
417
+ for node in self.nodes:
418
+ # Determine shape and size
419
+ shape = node.options.get("shape", "circle")
420
+ fill_color_spec = node.options.get("fill", "white")
421
+ edge_color_spec = node.options.get("draw", "black")
422
+ linewidth = float(node.options.get("line_width", 1))
423
+ size = float(node.options.get("size", 1))
424
+
425
+ # Parse colors using the Color class
426
+ try:
427
+ facecolor = Color(fill_color_spec).to_rgb()
428
+ except ValueError as e:
429
+ print(e)
430
+ facecolor = "white"
431
+
432
+ try:
433
+ edgecolor = Color(edge_color_spec).to_rgb()
434
+ except ValueError as e:
435
+ print(e)
436
+ edgecolor = "black"
437
+
438
+ # Plot shapes
439
+ if shape == "circle":
440
+ radius = size / 2
441
+ circle = patches.Circle(
442
+ (node.x, node.y),
443
+ radius,
444
+ facecolor=facecolor,
445
+ edgecolor=edgecolor,
446
+ linewidth=linewidth,
447
+ zorder=2, # Higher z-order to place on top of paths
448
+ )
449
+ ax.add_patch(circle)
450
+ elif shape == "rectangle":
451
+ width = height = size
452
+ rect = patches.Rectangle(
453
+ (node.x - width / 2, node.y - height / 2),
454
+ width,
455
+ height,
456
+ facecolor=facecolor,
457
+ edgecolor=edgecolor,
458
+ linewidth=linewidth,
459
+ zorder=2, # Higher z-order
460
+ )
461
+ ax.add_patch(rect)
462
+ else:
463
+ # Default to circle if shape is unknown
464
+ radius = size / 2
465
+ circle = patches.Circle(
466
+ (node.x, node.y),
467
+ radius,
468
+ facecolor=facecolor,
469
+ edgecolor=edgecolor,
470
+ linewidth=linewidth,
471
+ zorder=2,
472
+ )
473
+ ax.add_patch(circle)
474
+
475
+ # Add text inside the shape
476
+ if node.content:
477
+ ax.text(
478
+ node.x,
479
+ node.y,
480
+ node.content,
481
+ fontsize=10,
482
+ ha="center",
483
+ va="center",
484
+ wrap=True,
485
+ zorder=3, # Even higher z-order for text
486
+ )
487
+
488
+ # Remove axes, ticks, and legend
489
+ ax.axis("off")
490
+
491
+ # Adjust plot limits
492
+ all_x = [node.x for node in self.nodes]
493
+ all_y = [node.y for node in self.nodes]
494
+ padding = 1 # Adjust padding as needed
495
+ ax.set_xlim(min(all_x) - padding, max(all_x) + padding)
496
+ ax.set_ylim(min(all_y) - padding, max(all_y) + padding)
497
+ ax.set_aspect("equal", adjustable="datalim")
@@ -0,0 +1,7 @@
1
+ def test():
2
+ import maxplotlib.canvas.canvas
3
+ import maxplotlib.subfigure.line_plot
4
+
5
+
6
+ if __name__ == "__main__":
7
+ test()
@@ -0,0 +1,12 @@
1
+ import pytest
2
+
3
+
4
+ @pytest.mark.parametrize("x", [0])
5
+ def import_modules(x):
6
+ import matplotlib
7
+
8
+ import maxplotlib
9
+
10
+
11
+ if __name__ == "__main__":
12
+ import_modules(x=1)
File without changes
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: maxplotlibx
3
+ Version: 0.1
4
+ Summary: A reproducible plotting module with various backends and export options.
5
+ Author: Max
6
+ Project-URL: Source, https://github.com/max-models/maxplotlib
7
+ Keywords: matplotlib
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: pint
14
+ Requires-Dist: plotly
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest; extra == "test"
17
+ Requires-Dist: coverage; extra == "test"
18
+ Provides-Extra: docs
19
+ Requires-Dist: myst-parser; extra == "docs"
20
+ Requires-Dist: sphinx; extra == "docs"
21
+ Requires-Dist: sphinx-rtd-theme; extra == "docs"
22
+ Requires-Dist: nbsphinx; extra == "docs"
23
+ Requires-Dist: ipykernel; extra == "docs"
24
+ Requires-Dist: nbconvert; extra == "docs"
25
+ Provides-Extra: dev
26
+ Requires-Dist: maxplotlibx[docs,test]; extra == "dev"
27
+ Requires-Dist: ruff; extra == "dev"
28
+ Requires-Dist: black; extra == "dev"
29
+ Requires-Dist: isort; extra == "dev"
30
+ Requires-Dist: jupyterlab; extra == "dev"
31
+ Requires-Dist: nbstripout; extra == "dev"
32
+ Requires-Dist: pre-commit; extra == "dev"
33
+ Requires-Dist: pyproject-fmt; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # maxplotlib
37
+
38
+ This is a wrapper for matplotlib so I can produce figures with consistent formatting. It also has some pretty nice additions such as using layers and exporting to tikz.
39
+
40
+ Related packages: [maxtikzlib](https://github.com/max-models/maxtikzlib) and [maxtexlib](https://github.com/max-models/maxtexlib).
41
+
42
+ ## Install
43
+
44
+ Create and activate python environment
45
+
46
+ ```
47
+ python -m venv env
48
+ source env/bin/activate
49
+ pip install --upgrade pip
50
+ ```
51
+
52
+ Install the code and requirements with pip
53
+
54
+ ```
55
+ pip install -e .
56
+ ```
57
+
58
+ Additional dependencies for developers can be installed with
59
+
60
+ ```
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ Some examples can be found in `tutorials/`
@@ -0,0 +1,27 @@
1
+ maxplotlib/__init__.py,sha256=M4hqMJNeTsfZU99H6vI_rr8ua-ZM49GyEMHUV_Vq2JQ,66
2
+ maxplotlib/backends/matplotlib/utils.py,sha256=fmKhWiBeWALGuHUBxTEMl0GVpRF7TObfpZWjsaL7ZOM,3585
3
+ maxplotlib/backends/matplotlib/utils_old.py,sha256=VpkRRt3bhUtPd03SxWa7mPRWwSiOu9j5SA3GFlJ1DDc,29391
4
+ maxplotlib/backends/plotly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ maxplotlib/backends/plotly/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ maxplotlib/canvas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ maxplotlib/canvas/canvas.py,sha256=7HXQlcsWcNJzOy9T7A3PDkjYVPh3ciHKV7R8pHzTO9s,17352
8
+ maxplotlib/colors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ maxplotlib/colors/colors.py,sha256=_1V2Mumh_aM0Y7iOzQOEItrCh2nzmFKapzy1OGZ-_Q0,2599
10
+ maxplotlib/linestyle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ maxplotlib/linestyle/linestyle.py,sha256=xGakDaroYVb9HWQoL5RtwPAno5SUH70r85ozXiA2U3c,2021
12
+ maxplotlib/objects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ maxplotlib/objects/layer.py,sha256=BGZTtTzu20FkZyGwhnBql827HV1I7SLkKw08bDdIqeQ,556
14
+ maxplotlib/objects/node.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ maxplotlib/objects/path.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ maxplotlib/subfigure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ maxplotlib/subfigure/line_plot.py,sha256=QzJL2Cx5XMAfONMWUaEV8MyTJcjnz_ovHyDAaNKydkU,10826
18
+ maxplotlib/subfigure/subfigure.py,sha256=MMIAT8haC-zuCLucXagWchHqBYQdqWLc_MJv5G1OAP0,80
19
+ maxplotlib/subfigure/tikz_figure.py,sha256=xzil9gBOsT6JMPcskS07yiYSwahMvGHVs41vtkZCU7U,16822
20
+ maxplotlib/tests/test_canvas.py,sha256=-wbfUUnfXF4AGe2UPZl0_QuDDYKEdV9378UZo1MWC84,130
21
+ maxplotlib/tests/test_imports.py,sha256=icFvgf2VVlO5e5FkU-IFYk6CPnXQWGM3_nJyEkpC2_Y,172
22
+ maxplotlib/tests/test_plot.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ maxplotlibx-0.1.dist-info/licenses/LICENSE,sha256=yQ4Pipqp0gP6uNf8Hb6bj4HpyUuJvg41pkIrx3vUoxY,1060
24
+ maxplotlibx-0.1.dist-info/METADATA,sha256=3MjFktiWokVySS9MEFpxC4gURJ2uAUsempgSra_Hwl8,1838
25
+ maxplotlibx-0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
+ maxplotlibx-0.1.dist-info/top_level.txt,sha256=F_tiI1wDrGUZQgHR8EKZ-ajO0SSTSTp-NmYbGm1A_kA,11
27
+ maxplotlibx-0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Max
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ maxplotlib