• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Data Viz with Python and R

Learn to Make Plots in Python and R

  • Home
  • Seaborn
  • Matplotlib
  • ggplot2
  • Altair
  • About
    • Privacy Policy
  • Visualizing Activation Functions in Neural Networks
  • Confusion Matrix Calculator
  • Visualizing Dropout Rate in Neural Network
  • Visualizing Loss Functions in Neural Networks
  • Show Search
Hide Search

Matplotlib Draw Rectangle: Add, Fill, Annotate & Highlight Regions (Step-by-Step)

datavizpyr · January 30, 2021 ·

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()

Matplotlib rectangle outline on scatter plot
Outline rectangle highlighting a region of interest

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()

Matplotlib rectangle with transparent fill
Transparent rectangle keeps data legible while guiding attention

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()
    

Rectangle with text annotation in Matplotlib
Explain the rectangle’s purpose with a clear, concise text label

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()
    

Multiple rectangles on the same Matplotlib plot
Use color + alpha to differentiate multiple highlighted rectangles

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()
    

Rectangle drawn behind the scatter points using zorder
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()
    

Rectangles added to specific subplots in Matplotlib
Add rectangles per axes when comparing panels side-by-side in Matplotlib

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()
    

Axis-relative rectangle using transAxes in Matplotlib
Axis-relative rectangles keep the same proportion regardless of data limits


🔗 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 with mpl_connect() and detect clicks within a rectangle’s bounds for interactive plots.
  • Can I round the corners of a rectangle?
    Yes, use FancyBboxPatch with boxstyle="round" for rounded rectangles instead of Rectangle.
  • How do I rotate a rectangle in Matplotlib?
    The Rectangle() class has an angle argument (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 the hatch argument (e.g., '/', 'x', 'o') to add textures for print-friendly visuals.
  • What if my data uses datetime axes?
    Rectangles still work — just pass datetime objects for x-limits. Matplotlib converts them internally to numeric coordinates.


Related posts:

Connect paired data points in a scatter plot with arrowheads and labelsConnect Paired Data Points in a Scatter Plot in Python (Step-by-Step Guide) Change matplotlib style scatterplot to fivethirtyeightHow to View All Matplotlib Plot Styles and Change Default ThumbnailHow to Make Violin plots with Matplotlib Grouped barplot with Matoplotlib in PythonHow to make Grouped barplots with Matplotlib in Python

Filed Under: Matplotlib, Python Tagged With: add rectangle with matplotlib

Primary Sidebar

Python & R Viz Hubs

  • Seaborn Guide & Cookbook
  • ggplot2 Guide & Cookbook
  • Matplotlib Guide & Cookbook
  • Confusion Matrix Calculator
  • Visualizing Activation Functions
  • Visualizing Dropout
  • Visualizing Loss Functions

Buy Me a Coffee

Copyright © 2026 · Daily Dish Pro on Genesis Framework · WordPress · Log in

Go to mobile version