1818from 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+
21156class 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
669669if __name__ == "__main__" :
0 commit comments