Last updated on August 26, 2025
Need to highlight regions, create annotations, or add geometric shapes to your plots? This guide shows exactly how to draw rectangles in Matplotlib using patches.Rectangle—from crisp outlines to transparent overlays, labels, multiple boxes, subplots, and more. Copy-paste the code and adapt it to your data.
Rectangles are ideal for highlighting clusters, marking thresholds/time windows, or building custom legends. We’ll use a real dataset and progressively add features so you can apply them immediately.
Setup & Data (Palmer Penguins)
We’ll use the Palmer Penguins dataset (loaded from a public URL) to build a scatter plot. Then we’ll add rectangles on top of it. You can substitute your own DataFrame—everything else stays the same.
import matplotlib.pyplot as plt import pandas as pd import matplotlib.patches as mpatches # Load data (tab-separated) penguins_data = "https://raw.githubusercontent.com/datavizpyr/data/master/palmer_penguin_species.tsv" df = pd.read_csv(penguins_data, sep="\t") # Quick check print(df.head(3))
How to Draw a Rectangle on a Matplotlib Plot (Step-by-Step)
To make a rectangle, we need needs four numbers: the bottom-left corner (x, y) and the width and height. We first create the plot, then construct a Rectangle, and finally add it to the current axes with add_patch(). This version draws an outline only (no fill), perfect for precise boundaries.
# Base scatter plot with scatter()
plt.figure(figsize=(7.5,6))
plt.scatter(x=df.culmen_length_mm,
y=df.culmen_depth_mm,
alpha=0.8)
plt.xlabel("Culmen Length (mm)",
fontweight='bold',
fontsize=13)
plt.ylabel("Culmen Depth (mm)",
fontweight='bold',
fontsize=13)
plt.title("Matplotlib Rectangle: Outline Only",
fontsize=15)
# Define rectangle geometry: (left, bottom, width, height)
left, bottom, width, height = (31, 15, 14, 7)
# Create rectangle patch (no fill)
rect = mpatches.Rectangle((left, bottom),
width, height,
fill=False,
edgecolor="purple",
linewidth=2)
# Add to axes
ax = plt.gca()
ax.add_patch(rect)
plt.tight_layout()
plt.savefig("matplotlib_rectangle_outline.png", dpi=300)
plt.show()

How to Fill a Rectangle with Transparent Color in Matplotlib
To highlight an area without obscuring data points, add a fill with facecolor and dial in transparency using alpha. This creates a soft overlay—great for emphasis in scatterplots or time windows in line charts.
plt.figure(figsize=(7.5,6))
plt.scatter(df.culmen_length_mm,
df.culmen_depth_mm,
alpha=0.8)
plt.xlabel("Culmen Length (mm)",
fontweight='bold',
fontsize=13)
plt.ylabel("Culmen Depth (mm)",
fontweight='bold',
fontsize=13)
plt.title("Matplotlib Rectangle: Transparent Fill Overlay",
fontsize=15)
left, bottom, width, height = (31, 15, 14, 7)
rect = mpatches.Rectangle((left, bottom), width, height,
facecolor="crimson", alpha=0.18, # translucent fill
edgecolor="crimson", linewidth=1.8)
plt.gca().add_patch(rect)
plt.tight_layout()
plt.savefig("matplotlib_rectangle_transparent_fill.png", dpi=300)
plt.show()

How to Add Text Annotation Inside the Rectangle
Annotations explain why a region matters. Use plt.text() (or ax.text()) to label the rectangle succinctly. Pick a contrasting color, and consider a bold weight for clarity in presentations.
plt.figure(figsize=(7.5,6))
plt.scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.8)
plt.xlabel("Culmen Length (mm)", fontweight='bold', fontsize=13)
plt.ylabel("Culmen Depth (mm)", fontweight='bold', fontsize=13)
plt.title("Matplotlib Rectangle with Text Annotation", fontsize=15)
left, bottom, width, height = (31, 15, 14, 7)
rect = mpatches.Rectangle((left, bottom), width, height,
facecolor="gold", alpha=0.18,
edgecolor="goldenrod", linewidth=1.8)
ax = plt.gca()
ax.add_patch(rect)
# Add text label near the top-left of the rectangle
ax.text(left + 0.3, bottom + height - 0.4, "Target Range",
fontsize=13, color="goldenrod", weight="bold")
plt.tight_layout()
plt.savefig("matplotlib_rectangle_with_text.png", dpi=300)
plt.show()

How to Draw Multiple Rectangles on the Same Plot
You can add as many rectangles as needed—just create multiple Rectangle patches and add_patch() each one. Mix colors and transparency to communicate different categories or confidence bands.
plt.figure(figsize=(7.5,6))
plt.scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.8)
plt.xlabel("Culmen Length (mm)", fontweight='bold', fontsize=13)
plt.ylabel("Culmen Depth (mm)", fontweight='bold', fontsize=13)
plt.title("Matplotlib: Multiple Rectangles", fontsize=15)
ax = plt.gca()
# Rectangle 1
r1 = mpatches.Rectangle((31, 15), 14, 7,
facecolor="red", alpha=0.15,
edgecolor="red", linewidth=1.6)
ax.add_patch(r1)
# Rectangle 2
r2 = mpatches.Rectangle((48, 17.5), 7, 4,
facecolor="seagreen", alpha=0.18,
edgecolor="seagreen", linewidth=1.6)
ax.add_patch(r2)
plt.tight_layout()
plt.savefig("matplotlib_multiple_rectangles.png", dpi=300)
plt.show()

Control Stacking Order: Draw Rectangles Behind/Above Data
By default, patches can overlap points. Control the draw order with zorder: lower values render first (behind), higher values render last (on top). For subtle highlights, place rectangles behind the data.
plt.figure(figsize=(7.5,6))
# Higher zorder for points so they sit on top
plt.scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.9, zorder=3)
plt.xlabel("Culmen Length (mm)", fontweight='bold', fontsize=13)
plt.ylabel("Culmen Depth (mm)", fontweight='bold', fontsize=13)
plt.title("Rectangle Behind Points (zorder)", fontsize=15)
rect = mpatches.Rectangle((31, 15), 14, 7,
facecolor="royalblue", alpha=0.15,
edgecolor="royalblue", linewidth=1.5)
plt.gca().add_patch(rect)
# Put rectangle behind markers
rect.set_zorder(1)
plt.tight_layout()
plt.savefig("matplotlib_rectangle_zorder.png", dpi=300)
plt.show()

zorder lets you tuck the rectangle behind your data.
Subplots: Add Rectangles to Specific Axes
In multi-panel figures, create rectangles per axes. You’ll call ax.add_patch() for each subplot where you want a rectangle. This is handy when comparing ranges across categories or time periods.
fig, axes = plt.subplots(1, 2, figsize=(11,5), sharey=True)
# Left subplot
axes[0].scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.8)
axes[0].set_title("Left Panel")
axes[0].set_xlabel("Culmen Length (mm)")
axes[0].set_ylabel("Culmen Depth (mm)")
axes[0].add_patch(mpatches.Rectangle((31,15), 14, 7,
facecolor="tomato", alpha=0.16,
edgecolor="tomato", linewidth=1.4))
# Right subplot
axes[1].scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.8, color="gray")
axes[1].set_title("Right Panel")
axes[1].set_xlabel("Culmen Length (mm)")
axes[1].add_patch(mpatches.Rectangle((46,16), 8, 5,
facecolor="steelblue", alpha=0.18,
edgecolor="steelblue", linewidth=1.4))
fig.suptitle("Matplotlib Rectangles in Subplots", y=1.02, fontsize=15)
fig.tight_layout()
plt.savefig("matplotlib_rectangles_subplots.png", dpi=300, bbox_inches="tight")
plt.show()

Bonus: Axis-Relative Rectangles (Always Cover the Same Fraction)
Sometimes you want a rectangle that covers a fixed fraction of the axes (e.g., a banner box at the top), regardless of data limits. Use the axes coordinate system via transform=ax.transAxes where (0,0) is bottom-left and (1,1) is top-right of the axes frame.
plt.figure(figsize=(7.5,6))
ax = plt.gca()
ax.scatter(df.culmen_length_mm, df.culmen_depth_mm, alpha=0.85)
ax.set_title("Axis-Relative Rectangle (transAxes)", fontsize=15)
ax.set_xlabel("Culmen Length (mm)")
ax.set_ylabel("Culmen Depth (mm)")
# Rectangle spans full width of axes, top 12% area
banner = mpatches.Rectangle((0, 0.88), 1.0, 0.12,
transform=ax.transAxes, # axes coords
facecolor="black", alpha=0.10,
edgecolor="black", linewidth=0.8)
ax.add_patch(banner)
ax.text(0.02, 0.94, "Note: Special Highlight", transform=ax.transAxes,
va="center", ha="left", fontsize=12, color="black", weight="bold")
plt.tight_layout()
plt.savefig("matplotlib_rectangle_axis_relative.png", dpi=300)
plt.show()

🔗 Keep learning: How to make a heatmap with Matplotlib (step-by-step)
FAQs: Matplotlib Rectangle on Plot
-
How do I add a clickable rectangle in Matplotlib?
You can connect event handlers withmpl_connect()and detect clicks within a rectangle’s bounds for interactive plots. -
Can I round the corners of a rectangle?
Yes, useFancyBboxPatchwithboxstyle="round"for rounded rectangles instead ofRectangle. -
How do I rotate a rectangle in Matplotlib?
TheRectangle()class has anangleargument (in degrees) to tilt rectangles around their lower-left corner. -
Can I use rectangles in interactive dashboards?
Absolutely. Rectangles integrate with tools like Matplotlib widgets, Plotly, or Panel for dynamic highlighting. -
How do I create rectangles with hatching or patterns?
Use thehatchargument (e.g.,'/','x','o') to add textures for print-friendly visuals. -
What if my data uses datetime axes?
Rectangles still work — just passdatetimeobjects for x-limits. Matplotlib converts them internally to numeric coordinates.



