0
# Geometric Shapes
1
2
Drawing primitive shapes and complex geometric objects. Matplotlib provides extensive patch classes for creating rectangles, circles, polygons, arrows, and custom geometric shapes with full styling control.
3
4
## Capabilities
5
6
### Basic Shapes
7
8
Fundamental geometric shapes for annotations and custom graphics.
9
10
```python { .api }
11
import matplotlib.patches as mpatches
12
13
class Rectangle:
14
def __init__(self, xy, width, height, *, angle=0.0, **kwargs):
15
"""Rectangle patch with bottom-left corner at xy."""
16
17
def get_x(self) -> float:
18
"""Return the left coordinate of the rectangle."""
19
20
def get_y(self) -> float:
21
"""Return the bottom coordinate of the rectangle."""
22
23
def get_width(self) -> float:
24
"""Return the width of the rectangle."""
25
26
def get_height(self) -> float:
27
"""Return the height of the rectangle."""
28
29
def set_x(self, x) -> None:
30
"""Set the left coordinate of the rectangle."""
31
32
def set_y(self, y) -> None:
33
"""Set the bottom coordinate of the rectangle."""
34
35
def set_width(self, w) -> None:
36
"""Set the width of the rectangle."""
37
38
def set_height(self, h) -> None:
39
"""Set the height of the rectangle."""
40
41
class Circle:
42
def __init__(self, xy, radius, **kwargs):
43
"""Circle patch centered at xy."""
44
45
def get_radius(self) -> float:
46
"""Return the radius of the circle."""
47
48
def set_radius(self, radius) -> None:
49
"""Set the radius of the circle."""
50
51
class Ellipse:
52
def __init__(self, xy, width, height, *, angle=0, **kwargs):
53
"""Ellipse patch centered at xy."""
54
55
def get_width(self) -> float:
56
"""Return the width of the ellipse."""
57
58
def get_height(self) -> float:
59
"""Return the height of the ellipse."""
60
61
class Polygon:
62
def __init__(self, xy, *, closed=True, **kwargs):
63
"""General polygon patch from sequence of xy coordinates."""
64
65
def get_xy(self) -> np.ndarray:
66
"""Get the vertices of the polygon."""
67
68
def set_xy(self, xy) -> None:
69
"""Set the vertices of the polygon."""
70
71
class RegularPolygon:
72
def __init__(self, xy, numVertices, radius=5, *, orientation=0, **kwargs):
73
"""Regular polygon with numVertices sides."""
74
75
def get_numVertices(self) -> int:
76
"""Return the number of vertices."""
77
78
def get_radius(self) -> float:
79
"""Return the radius of the polygon."""
80
81
def get_orientation(self) -> float:
82
"""Return the orientation of the polygon."""
83
```
84
85
### Specialized Shapes
86
87
More complex geometric shapes for specific use cases.
88
89
```python { .api }
90
class Wedge:
91
def __init__(self, center, r, theta1, theta2, *, width=None, **kwargs):
92
"""Wedge-shaped patch from center with angular range."""
93
94
def get_center(self) -> tuple:
95
"""Return the center of the wedge."""
96
97
def get_radius(self) -> float:
98
"""Return the radius of the wedge."""
99
100
def get_theta1(self) -> float:
101
"""Return the start angle of the wedge."""
102
103
def get_theta2(self) -> float:
104
"""Return the end angle of the wedge."""
105
106
class Arc:
107
def __init__(self, xy, width, height, *, angle=0, theta1=0, theta2=360, **kwargs):
108
"""Elliptical arc patch."""
109
110
def get_theta1(self) -> float:
111
"""Return the start angle of the arc."""
112
113
def get_theta2(self) -> float:
114
"""Return the end angle of the arc."""
115
116
class PathPatch:
117
def __init__(self, path, **kwargs):
118
"""Patch from a matplotlib Path object."""
119
120
def get_path(self) -> Path:
121
"""Return the path of the patch."""
122
123
def set_path(self, path) -> None:
124
"""Set the path of the patch."""
125
```
126
127
### Arrow Shapes
128
129
Arrows and directional indicators with customizable styling.
130
131
```python { .api }
132
class Arrow:
133
def __init__(self, x, y, dx, dy, *, width=1.0, **kwargs):
134
"""Simple arrow patch from (x,y) with displacement (dx,dy)."""
135
136
def get_x(self) -> float:
137
"""Return the x coordinate of the arrow base."""
138
139
def get_y(self) -> float:
140
"""Return the y coordinate of the arrow base."""
141
142
class FancyArrow:
143
def __init__(self, x, y, dx, dy, *, width=0.001, length_includes_head=False,
144
head_width=None, head_length=None, shape='full', overhang=0,
145
head_starts_at_zero=False, **kwargs):
146
"""Fancy arrow with customizable head and tail."""
147
148
def get_dxy(self) -> tuple:
149
"""Return the displacement (dx, dy) of the arrow."""
150
151
class FancyArrowPatch:
152
def __init__(self, posA=None, posB=None, *, path=None, arrowstyle='->',
153
connectionstyle='arc3', patchA=None, patchB=None,
154
shrinkA=2, shrinkB=2, mutation_scale=20, mutation_aspect=1,
155
**kwargs):
156
"""Fancy arrow patch connecting two points with custom styling."""
157
158
def set_positions(self, posA, posB) -> None:
159
"""Set the start and end positions of the arrow."""
160
161
def set_arrowstyle(self, arrowstyle=None, **kwargs) -> None:
162
"""Set the arrow style."""
163
164
def set_connectionstyle(self, connectionstyle, **kwargs) -> None:
165
"""Set the connection style."""
166
```
167
168
### Advanced Patches
169
170
Complex patch types for specialized graphics.
171
172
```python { .api }
173
class FancyBboxPatch:
174
def __init__(self, xy, width, height, *, boxstyle='round', **kwargs):
175
"""Fancy bounding box with various border styles."""
176
177
def set_boxstyle(self, boxstyle=None, **kwargs) -> None:
178
"""Set the box style."""
179
180
def get_boxstyle(self) -> BoxStyle:
181
"""Return the box style."""
182
183
class ConnectionPatch:
184
def __init__(self, xyA, xyB, coordsA, coordsB=None, *,
185
axesA=None, axesB=None, arrowstyle='-', shrinkA=0, shrinkB=0,
186
**kwargs):
187
"""Patch to connect two points, possibly in different coordinate systems."""
188
189
def set_xyA(self, xy) -> None:
190
"""Set the starting point A."""
191
192
def set_xyB(self, xy) -> None:
193
"""Set the ending point B."""
194
195
class Shadow:
196
def __init__(self, patch, ox, oy, *, props=None, **kwargs):
197
"""Create a shadow effect for another patch."""
198
```
199
200
### Style Classes
201
202
Style specifications for complex patches.
203
204
```python { .api }
205
class BoxStyle:
206
"""Box styling options for FancyBboxPatch."""
207
208
@staticmethod
209
def Round(pad=0.3, rounding_size=None) -> BoxStyle:
210
"""Rounded corner box style."""
211
212
@staticmethod
213
def Square(pad=0.3) -> BoxStyle:
214
"""Square corner box style."""
215
216
@staticmethod
217
def Sawtooth(pad=0.3, tooth_size=None) -> BoxStyle:
218
"""Sawtooth edge box style."""
219
220
@staticmethod
221
def Circle(pad=0.3) -> BoxStyle:
222
"""Circular box style."""
223
224
class ArrowStyle:
225
"""Arrow styling options for FancyArrowPatch."""
226
227
@staticmethod
228
def Simple(head_length=0.5, head_width=0.5, tail_width=0.2) -> ArrowStyle:
229
"""Simple arrow style."""
230
231
@staticmethod
232
def Fancy(head_length=0.4, head_width=0.4, tail_width=0.4) -> ArrowStyle:
233
"""Fancy arrow style."""
234
235
@staticmethod
236
def Wedge(tail_width=0.3, shrink_factor=0.5) -> ArrowStyle:
237
"""Wedge arrow style."""
238
239
class ConnectionStyle:
240
"""Connection styling options for connecting patches."""
241
242
@staticmethod
243
def Arc3(rad=0.0) -> ConnectionStyle:
244
"""Arc connection with specified radius."""
245
246
@staticmethod
247
def Angle3(angleA=90, angleB=0) -> ConnectionStyle:
248
"""Angle connection with specified angles."""
249
250
@staticmethod
251
def Bar(armA=0.0, armB=0.0, fraction=0.3, angle=None) -> ConnectionStyle:
252
"""Bar connection style."""
253
```
254
255
## Usage Examples
256
257
### Basic Shapes
258
259
```python
260
import matplotlib.pyplot as plt
261
import matplotlib.patches as mpatches
262
import numpy as np
263
264
fig, ax = plt.subplots(figsize=(12, 8))
265
266
# Rectangle
267
rect = mpatches.Rectangle((0.1, 0.1), 0.3, 0.2,
268
facecolor='lightblue', edgecolor='blue', linewidth=2)
269
ax.add_patch(rect)
270
271
# Circle
272
circle = mpatches.Circle((0.6, 0.2), 0.1,
273
facecolor='lightcoral', edgecolor='red', linewidth=2)
274
ax.add_patch(circle)
275
276
# Ellipse
277
ellipse = mpatches.Ellipse((0.2, 0.6), 0.2, 0.1, angle=45,
278
facecolor='lightgreen', edgecolor='green', linewidth=2)
279
ax.add_patch(ellipse)
280
281
# Polygon (triangle)
282
triangle = mpatches.Polygon([(0.5, 0.5), (0.7, 0.5), (0.6, 0.7)],
283
facecolor='yellow', edgecolor='orange', linewidth=2)
284
ax.add_patch(triangle)
285
286
# Regular polygon (hexagon)
287
hexagon = mpatches.RegularPolygon((0.8, 0.7), 6, radius=0.08,
288
facecolor='plum', edgecolor='purple', linewidth=2)
289
ax.add_patch(hexagon)
290
291
ax.set_xlim(0, 1)
292
ax.set_ylim(0, 1)
293
ax.set_aspect('equal')
294
ax.set_title('Basic Shapes')
295
ax.grid(True, alpha=0.3)
296
plt.show()
297
```
298
299
### Arrows and Directional Graphics
300
301
```python
302
import matplotlib.pyplot as plt
303
import matplotlib.patches as mpatches
304
305
fig, ax = plt.subplots(figsize=(12, 8))
306
307
# Simple arrow
308
arrow1 = mpatches.Arrow(0.1, 0.1, 0.2, 0.1, width=0.05, color='red')
309
ax.add_patch(arrow1)
310
311
# Fancy arrow
312
arrow2 = mpatches.FancyArrow(0.1, 0.3, 0.3, 0.0, width=0.02, head_width=0.05,
313
head_length=0.03, fc='blue', ec='darkblue')
314
ax.add_patch(arrow2)
315
316
# Fancy arrow patch with custom styling
317
arrow3 = mpatches.FancyArrowPatch((0.1, 0.5), (0.4, 0.7),
318
arrowstyle='->', mutation_scale=20,
319
color='green', linewidth=2)
320
ax.add_patch(arrow3)
321
322
# Curved arrow
323
arrow4 = mpatches.FancyArrowPatch((0.6, 0.2), (0.8, 0.6),
324
connectionstyle='arc3,rad=0.3',
325
arrowstyle='-|>', mutation_scale=20,
326
color='purple', linewidth=2)
327
ax.add_patch(arrow4)
328
329
# Bidirectional arrow
330
arrow5 = mpatches.FancyArrowPatch((0.5, 0.8), (0.9, 0.8),
331
arrowstyle='<->', mutation_scale=20,
332
color='orange', linewidth=2)
333
ax.add_patch(arrow5)
334
335
ax.set_xlim(0, 1)
336
ax.set_ylim(0, 1)
337
ax.set_aspect('equal')
338
ax.set_title('Arrow Examples')
339
ax.grid(True, alpha=0.3)
340
plt.show()
341
```
342
343
### Advanced Patch Styling
344
345
```python
346
import matplotlib.pyplot as plt
347
import matplotlib.patches as mpatches
348
349
fig, ax = plt.subplots(figsize=(12, 8))
350
351
# Fancy bounding boxes with different styles
352
styles = ['round', 'square', 'sawtooth', 'circle']
353
colors = ['lightblue', 'lightcoral', 'lightgreen', 'lightyellow']
354
355
for i, (style, color) in enumerate(zip(styles, colors)):
356
x = 0.1 + (i % 2) * 0.4
357
y = 0.6 - (i // 2) * 0.3
358
359
bbox = mpatches.FancyBboxPatch((x, y), 0.25, 0.15,
360
boxstyle=f"{style},pad=0.02",
361
facecolor=color, edgecolor='black',
362
linewidth=1.5)
363
ax.add_patch(bbox)
364
365
# Add text label
366
ax.text(x + 0.125, y + 0.075, style.capitalize(),
367
ha='center', va='center', fontsize=12, weight='bold')
368
369
# Wedge (pie slice)
370
wedge = mpatches.Wedge((0.8, 0.3), 0.15, 30, 120,
371
facecolor='gold', edgecolor='orange', linewidth=2)
372
ax.add_patch(wedge)
373
374
# Arc
375
arc = mpatches.Arc((0.8, 0.3), 0.3, 0.3, angle=0, theta1=150, theta2=390,
376
edgecolor='red', linewidth=3)
377
ax.add_patch(arc)
378
379
ax.set_xlim(0, 1)
380
ax.set_ylim(0, 1)
381
ax.set_aspect('equal')
382
ax.set_title('Advanced Patch Styling')
383
ax.grid(True, alpha=0.3)
384
plt.show()
385
```
386
387
### Interactive Shape Creation
388
389
```python
390
import matplotlib.pyplot as plt
391
import matplotlib.patches as mpatches
392
import numpy as np
393
394
def create_flowchart():
395
"""Create a simple flowchart using patches."""
396
fig, ax = plt.subplots(figsize=(12, 10))
397
398
# Define positions and sizes
399
boxes = [
400
{'xy': (0.2, 0.8), 'size': (0.15, 0.08), 'text': 'Start', 'style': 'round'},
401
{'xy': (0.2, 0.6), 'size': (0.15, 0.08), 'text': 'Process', 'style': 'square'},
402
{'xy': (0.2, 0.4), 'size': (0.15, 0.08), 'text': 'Decision', 'style': 'round'},
403
{'xy': (0.5, 0.4), 'size': (0.15, 0.08), 'text': 'Yes Branch', 'style': 'square'},
404
{'xy': (0.2, 0.2), 'size': (0.15, 0.08), 'text': 'No Branch', 'style': 'square'},
405
{'xy': (0.5, 0.2), 'size': (0.15, 0.08), 'text': 'End', 'style': 'round'}
406
]
407
408
# Create boxes
409
for box in boxes:
410
patch = mpatches.FancyBboxPatch(
411
box['xy'], box['size'][0], box['size'][1],
412
boxstyle=f"{box['style']},pad=0.01",
413
facecolor='lightblue', edgecolor='navy', linewidth=2
414
)
415
ax.add_patch(patch)
416
417
# Add text
418
center_x = box['xy'][0] + box['size'][0]/2
419
center_y = box['xy'][1] + box['size'][1]/2
420
ax.text(center_x, center_y, box['text'],
421
ha='center', va='center', fontsize=10, weight='bold')
422
423
# Add connecting arrows
424
arrows = [
425
((0.275, 0.8), (0.275, 0.68)), # Start to Process
426
((0.275, 0.6), (0.275, 0.48)), # Process to Decision
427
((0.35, 0.44), (0.5, 0.44)), # Decision to Yes
428
((0.275, 0.4), (0.275, 0.28)), # Decision to No
429
((0.575, 0.4), (0.575, 0.28)) # Yes to End
430
]
431
432
for start, end in arrows:
433
arrow = mpatches.FancyArrowPatch(start, end,
434
arrowstyle='->', mutation_scale=15,
435
color='darkblue', linewidth=2)
436
ax.add_patch(arrow)
437
438
# Add labels for decision branches
439
ax.text(0.42, 0.46, 'Yes', ha='center', va='center', fontsize=9,
440
bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0.8))
441
ax.text(0.3, 0.32, 'No', ha='center', va='center', fontsize=9,
442
bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0.8))
443
444
ax.set_xlim(0, 0.8)
445
ax.set_ylim(0, 1)
446
ax.set_aspect('equal')
447
ax.set_title('Flowchart Example using Patches')
448
ax.axis('off')
449
plt.show()
450
451
create_flowchart()
452
```
453
454
### Custom Shape Creation
455
456
```python
457
import matplotlib.pyplot as plt
458
import matplotlib.patches as mpatches
459
from matplotlib.path import Path
460
import numpy as np
461
462
# Create custom star shape using Path
463
def create_star(center, radius, n_points=5):
464
"""Create a star shape path."""
465
angles = np.linspace(0, 2*np.pi, n_points*2, endpoint=False)
466
radii = np.array([radius, radius*0.4] * n_points)
467
468
x = center[0] + radii * np.cos(angles)
469
y = center[1] + radii * np.sin(angles)
470
471
vertices = list(zip(x, y))
472
codes = [Path.MOVETO] + [Path.LINETO] * (len(vertices)-2) + [Path.CLOSEPOLY]
473
474
return Path(vertices, codes)
475
476
fig, ax = plt.subplots(figsize=(10, 8))
477
478
# Create multiple custom stars
479
centers = [(0.2, 0.3), (0.5, 0.7), (0.8, 0.4)]
480
radii = [0.08, 0.12, 0.06]
481
colors = ['gold', 'orange', 'yellow']
482
483
for center, radius, color in zip(centers, radii, colors):
484
star_path = create_star(center, radius)
485
star_patch = mpatches.PathPatch(star_path, facecolor=color,
486
edgecolor='darkorange', linewidth=2)
487
ax.add_patch(star_patch)
488
489
# Add some decorative circles
490
for i in range(8):
491
angle = i * np.pi / 4
492
x = 0.5 + 0.3 * np.cos(angle)
493
y = 0.5 + 0.3 * np.sin(angle)
494
circle = mpatches.Circle((x, y), 0.02, facecolor='lightblue',
495
edgecolor='blue', alpha=0.7)
496
ax.add_patch(circle)
497
498
ax.set_xlim(0, 1)
499
ax.set_ylim(0, 1)
500
ax.set_aspect('equal')
501
ax.set_title('Custom Shapes with Paths')
502
ax.set_facecolor('lightgray')
503
ax.grid(True, alpha=0.3)
504
plt.show()
505
```