Skip to content

Commit 21f5034

Browse files
committed
ssort
1 parent 3406673 commit 21f5034

3 files changed

Lines changed: 162 additions & 160 deletions

File tree

src/maxplotlib/canvas/canvas.py

Lines changed: 140 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,141 @@
1818
from maxplotlib.utils.options import Backends
1919

2020

21+
def plot_matplotlib(tikzfigure: TikzFigure, ax, layers=None):
22+
"""
23+
Plot all nodes and paths on the provided axis using Matplotlib.
24+
25+
Parameters:
26+
- ax (matplotlib.axes.Axes): Axis on which to plot the figure.
27+
"""
28+
29+
# TODO: Specify which layers to retreive nodes from with layers=layers
30+
nodes = tikzfigure.layers.get_nodes()
31+
paths = tikzfigure.layers.get_paths()
32+
33+
for path in paths:
34+
x_coords = [node.x for node in path.nodes]
35+
y_coords = [node.y for node in path.nodes]
36+
37+
# Parse path color
38+
path_color_spec = path.kwargs.get("color", "black")
39+
try:
40+
color = Color(path_color_spec).to_rgb()
41+
except ValueError as e:
42+
print(e)
43+
color = "black"
44+
45+
# Parse line width
46+
line_width_spec = path.kwargs.get("line_width", 1)
47+
if isinstance(line_width_spec, str):
48+
match = re.match(r"([\d.]+)(pt)?", line_width_spec)
49+
if match:
50+
line_width = float(match.group(1))
51+
else:
52+
print(
53+
f"Invalid line width specification: '{line_width_spec}', defaulting to 1",
54+
)
55+
line_width = 1
56+
else:
57+
line_width = float(line_width_spec)
58+
59+
# Parse line style using Linestyle class
60+
style_spec = path.kwargs.get("style", "solid")
61+
linestyle = Linestyle(style_spec).to_matplotlib()
62+
63+
ax.plot(
64+
x_coords,
65+
y_coords,
66+
color=color,
67+
linewidth=line_width,
68+
linestyle=linestyle,
69+
zorder=1, # Lower z-order to place behind nodes
70+
)
71+
72+
# Plot nodes after paths so they appear on top
73+
for node in nodes:
74+
# Determine shape and size
75+
shape = node.kwargs.get("shape", "circle")
76+
fill_color_spec = node.kwargs.get("fill", "white")
77+
edge_color_spec = node.kwargs.get("draw", "black")
78+
linewidth = float(node.kwargs.get("line_width", 1))
79+
size = float(node.kwargs.get("size", 1))
80+
81+
# Parse colors using the Color class
82+
try:
83+
facecolor = Color(fill_color_spec).to_rgb()
84+
except ValueError as e:
85+
print(e)
86+
facecolor = "white"
87+
88+
try:
89+
edgecolor = Color(edge_color_spec).to_rgb()
90+
except ValueError as e:
91+
print(e)
92+
edgecolor = "black"
93+
94+
# Plot shapes
95+
if shape == "circle":
96+
radius = size / 2
97+
circle = patches.Circle(
98+
(node.x, node.y),
99+
radius,
100+
facecolor=facecolor,
101+
edgecolor=edgecolor,
102+
linewidth=linewidth,
103+
zorder=2, # Higher z-order to place on top of paths
104+
)
105+
ax.add_patch(circle)
106+
elif shape == "rectangle":
107+
width = height = size
108+
rect = patches.Rectangle(
109+
(node.x - width / 2, node.y - height / 2),
110+
width,
111+
height,
112+
facecolor=facecolor,
113+
edgecolor=edgecolor,
114+
linewidth=linewidth,
115+
zorder=2, # Higher z-order
116+
)
117+
ax.add_patch(rect)
118+
else:
119+
# Default to circle if shape is unknown
120+
radius = size / 2
121+
circle = patches.Circle(
122+
(node.x, node.y),
123+
radius,
124+
facecolor=facecolor,
125+
edgecolor=edgecolor,
126+
linewidth=linewidth,
127+
zorder=2,
128+
)
129+
ax.add_patch(circle)
130+
131+
# Add text inside the shape
132+
if node.content:
133+
ax.text(
134+
node.x,
135+
node.y,
136+
node.content,
137+
fontsize=10,
138+
ha="center",
139+
va="center",
140+
wrap=True,
141+
zorder=3, # Even higher z-order for text
142+
)
143+
144+
# Remove axes, ticks, and legend
145+
ax.axis("off")
146+
147+
# Adjust plot limits
148+
all_x = [node.x for node in nodes]
149+
all_y = [node.y for node in nodes]
150+
padding = 1 # Adjust padding as needed
151+
ax.set_xlim(min(all_x) - padding, max(all_x) + padding)
152+
ax.set_ylim(min(all_y) - padding, max(all_y) + padding)
153+
ax.set_aspect("equal", adjustable="datalim")
154+
155+
21156
class Canvas:
22157
def __init__(
23158
self,
@@ -509,13 +644,6 @@ def label(self, value):
509644
def figsize(self, value):
510645
self._figsize = value
511646

512-
# Magic methods
513-
def __str__(self):
514-
return f"Canvas(nrows={self.nrows}, ncols={self.ncols}, figsize={self.figsize})"
515-
516-
def __repr__(self):
517-
return f"Canvas(nrows={self.nrows}, ncols={self.ncols}, caption={self.caption}, label={self.label})"
518-
519647
def __getitem__(self, key):
520648
"""Allows accessing subplots by tuple index."""
521649
row, col = key
@@ -530,140 +658,12 @@ def __setitem__(self, key, value):
530658
raise IndexError("Subplot index out of range")
531659
self._subplot_matrix[row][col] = value
532660

661+
def __repr__(self):
662+
return f"Canvas(nrows={self.nrows}, ncols={self.ncols}, caption={self.caption}, label={self.label})"
533663

534-
def plot_matplotlib(tikzfigure: TikzFigure, ax, layers=None):
535-
"""
536-
Plot all nodes and paths on the provided axis using Matplotlib.
537-
538-
Parameters:
539-
- ax (matplotlib.axes.Axes): Axis on which to plot the figure.
540-
"""
541-
542-
# TODO: Specify which layers to retreive nodes from with layers=layers
543-
nodes = tikzfigure.layers.get_nodes()
544-
paths = tikzfigure.layers.get_paths()
545-
546-
for path in paths:
547-
x_coords = [node.x for node in path.nodes]
548-
y_coords = [node.y for node in path.nodes]
549-
550-
# Parse path color
551-
path_color_spec = path.kwargs.get("color", "black")
552-
try:
553-
color = Color(path_color_spec).to_rgb()
554-
except ValueError as e:
555-
print(e)
556-
color = "black"
557-
558-
# Parse line width
559-
line_width_spec = path.kwargs.get("line_width", 1)
560-
if isinstance(line_width_spec, str):
561-
match = re.match(r"([\d.]+)(pt)?", line_width_spec)
562-
if match:
563-
line_width = float(match.group(1))
564-
else:
565-
print(
566-
f"Invalid line width specification: '{line_width_spec}', defaulting to 1",
567-
)
568-
line_width = 1
569-
else:
570-
line_width = float(line_width_spec)
571-
572-
# Parse line style using Linestyle class
573-
style_spec = path.kwargs.get("style", "solid")
574-
linestyle = Linestyle(style_spec).to_matplotlib()
575-
576-
ax.plot(
577-
x_coords,
578-
y_coords,
579-
color=color,
580-
linewidth=line_width,
581-
linestyle=linestyle,
582-
zorder=1, # Lower z-order to place behind nodes
583-
)
584-
585-
# Plot nodes after paths so they appear on top
586-
for node in nodes:
587-
# Determine shape and size
588-
shape = node.kwargs.get("shape", "circle")
589-
fill_color_spec = node.kwargs.get("fill", "white")
590-
edge_color_spec = node.kwargs.get("draw", "black")
591-
linewidth = float(node.kwargs.get("line_width", 1))
592-
size = float(node.kwargs.get("size", 1))
593-
594-
# Parse colors using the Color class
595-
try:
596-
facecolor = Color(fill_color_spec).to_rgb()
597-
except ValueError as e:
598-
print(e)
599-
facecolor = "white"
600-
601-
try:
602-
edgecolor = Color(edge_color_spec).to_rgb()
603-
except ValueError as e:
604-
print(e)
605-
edgecolor = "black"
606-
607-
# Plot shapes
608-
if shape == "circle":
609-
radius = size / 2
610-
circle = patches.Circle(
611-
(node.x, node.y),
612-
radius,
613-
facecolor=facecolor,
614-
edgecolor=edgecolor,
615-
linewidth=linewidth,
616-
zorder=2, # Higher z-order to place on top of paths
617-
)
618-
ax.add_patch(circle)
619-
elif shape == "rectangle":
620-
width = height = size
621-
rect = patches.Rectangle(
622-
(node.x - width / 2, node.y - height / 2),
623-
width,
624-
height,
625-
facecolor=facecolor,
626-
edgecolor=edgecolor,
627-
linewidth=linewidth,
628-
zorder=2, # Higher z-order
629-
)
630-
ax.add_patch(rect)
631-
else:
632-
# Default to circle if shape is unknown
633-
radius = size / 2
634-
circle = patches.Circle(
635-
(node.x, node.y),
636-
radius,
637-
facecolor=facecolor,
638-
edgecolor=edgecolor,
639-
linewidth=linewidth,
640-
zorder=2,
641-
)
642-
ax.add_patch(circle)
643-
644-
# Add text inside the shape
645-
if node.content:
646-
ax.text(
647-
node.x,
648-
node.y,
649-
node.content,
650-
fontsize=10,
651-
ha="center",
652-
va="center",
653-
wrap=True,
654-
zorder=3, # Even higher z-order for text
655-
)
656-
657-
# Remove axes, ticks, and legend
658-
ax.axis("off")
659-
660-
# Adjust plot limits
661-
all_x = [node.x for node in nodes]
662-
all_y = [node.y for node in nodes]
663-
padding = 1 # Adjust padding as needed
664-
ax.set_xlim(min(all_x) - padding, max(all_x) + padding)
665-
ax.set_ylim(min(all_y) - padding, max(all_y) + padding)
666-
ax.set_aspect("equal", adjustable="datalim")
664+
# Magic methods
665+
def __str__(self):
666+
return f"Canvas(nrows={self.nrows}, ncols={self.ncols}, figsize={self.figsize})"
667667

668668

669669
if __name__ == "__main__":

src/maxplotlib/colors/colors.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,6 @@
55

66

77
class Color:
8-
def __init__(self, color_spec):
9-
"""
10-
Initialize the Color object by parsing the color specification.
11-
12-
Parameters:
13-
- color_spec: Can be a TikZ color string (e.g., 'blue!20'), a standard color name,
14-
an RGB tuple, a hex code, etc.
15-
"""
16-
self.color_spec = color_spec
17-
self.rgb = self._parse_color(color_spec)
188

199
def _parse_color(self, color_spec):
2010
"""
@@ -53,6 +43,17 @@ def _parse_color(self, color_spec):
5343
except ValueError:
5444
raise ValueError(f"Invalid color specification: '{color_spec}'")
5545

46+
def __init__(self, color_spec):
47+
"""
48+
Initialize the Color object by parsing the color specification.
49+
50+
Parameters:
51+
- color_spec: Can be a TikZ color string (e.g., 'blue!20'), a standard color name,
52+
an RGB tuple, a hex code, etc.
53+
"""
54+
self.color_spec = color_spec
55+
self.rgb = self._parse_color(color_spec)
56+
5657
def to_rgb(self):
5758
"""
5859
Return the color as an RGB tuple.

src/maxplotlib/linestyle/linestyle.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,6 @@
22

33

44
class Linestyle:
5-
def __init__(self, style_spec):
6-
"""
7-
Initialize the Linestyle object by parsing the style specification.
8-
9-
Parameters:
10-
- style_spec: Can be a TikZ-style line style string (e.g., 'dashed', 'dotted', 'solid', 'dashdot'),
11-
or a custom dash pattern.
12-
"""
13-
self.style_spec = style_spec
14-
self.matplotlib_style = self._parse_style(style_spec)
155

166
def _parse_style(self, style_spec):
177
"""
@@ -48,6 +38,17 @@ def _parse_style(self, style_spec):
4838
print(f"Unknown line style: '{style_spec}', defaulting to 'solid'")
4939
return "solid"
5040

41+
def __init__(self, style_spec):
42+
"""
43+
Initialize the Linestyle object by parsing the style specification.
44+
45+
Parameters:
46+
- style_spec: Can be a TikZ-style line style string (e.g., 'dashed', 'dotted', 'solid', 'dashdot'),
47+
or a custom dash pattern.
48+
"""
49+
self.style_spec = style_spec
50+
self.matplotlib_style = self._parse_style(style_spec)
51+
5152
def to_matplotlib(self):
5253
"""
5354
Return the line style in Matplotlib format.

0 commit comments

Comments
 (0)