Matplotlib Pyplot
Learn how matplotlib.pyplot works: the stateful interface, key functions, figure and axes concepts, saving plots, and when to use the OO API instead.
matplotlib.pyplot is a collection of functions that make Matplotlib behave like MATLAB's plotting system. Each function creates or modifies some element of a figure — adding axes, drawing a line, setting a title — and pyplot keeps track of the "current" figure and axes automatically so you do not have to pass objects around. This page explains how that stateful model works, walks through the most important pyplot functions, and shows when to switch to the explicit object-oriented API instead.
What Is matplotlib.pyplot?
Matplotlib has two main interfaces:
| Interface | How you access it | Best for |
|---|---|---|
| pyplot (stateful) | import matplotlib.pyplot as plt | Quick scripts, interactive notebooks |
| Object-oriented | fig, ax = plt.subplots() | Complex multi-panel figures, libraries, reusable code |
Both interfaces live in the same library. pyplot is a convenience layer — every plt.something() call ultimately manipulates the same Figure and Axes objects that the OO interface exposes directly. Understanding this relationship lets you mix both styles confidently.
The standard alias is plt:
import matplotlib.pyplot as pltHow the Stateful Interface Works
pyplot keeps an internal reference to the current figure and the current axes. When you call plt.plot(), Matplotlib:
- Checks whether a figure already exists; if not, creates one.
- Checks whether that figure has axes; if not, adds a single
Axesto fill the figure. - Draws the data onto those axes.
import matplotlib.pyplot as plt
# No figure exists yet — pyplot creates one automatically
plt.plot([1, 2, 3], [4, 6, 5])
plt.title("My first plot")
plt.show()The figure and axes were created implicitly. This is convenient for one-off plots but can cause surprises when you run multiple plots in the same script. Use plt.figure() and plt.clf() (clear figure) or plt.close() to control state explicitly.
Core pyplot Functions
plt.plot() — Draw Lines and Markers
plt.plot(x, y) is the workhorse. It draws lines, markers, or both.
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
revenue = [12000, 15000, 13500, 17000, 19500, 22000]
plt.plot(months, revenue, color="steelblue", linewidth=2, marker="o", markersize=6)
plt.xlabel("Month")
plt.ylabel("Revenue ($)")
plt.title("Monthly Revenue")
plt.grid(True, linestyle="--", alpha=0.5)
plt.show()Key plt.plot() parameters:
| Parameter | Example values | Effect |
|---|---|---|
color | "red", "#2196F3", (0.1, 0.6, 0.8) | Line and marker color |
linewidth / lw | 1, 2.5 | Thickness of the line |
linestyle / ls | "-", "--", ":", "-." | Solid, dashed, dotted, dash-dot |
marker | "o", "s", "^", "x" | Circle, square, triangle, cross |
markersize / ms | 4, 8 | Marker size in points |
label | "Series A" | Text used by plt.legend() |
plt.xlabel(), plt.ylabel(), plt.title()
Label the axes and add a title. All three accept a fontsize argument:
import matplotlib.pyplot as plt
plt.plot([0, 1, 2], [0, 1, 4])
plt.xlabel("x", fontsize=12)
plt.ylabel("x²", fontsize=12)
plt.title("Quadratic Growth", fontsize=14, fontweight="bold")
plt.show()plt.legend()
When you pass label= to a plot call, plt.legend() turns those labels into a box on the chart:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
plt.plot(x, [v**1 for v in x], label="Linear")
plt.plot(x, [v**2 for v in x], label="Quadratic")
plt.plot(x, [v**3 for v in x], label="Cubic")
plt.xlabel("x")
plt.ylabel("y")
plt.title("Growth Rates")
plt.legend()
plt.show()Control legend placement with the loc parameter: "upper left", "lower right", "best" (default), and so on.
plt.grid()
plt.grid(True) adds grid lines. Use axis="x" or axis="y" to restrict to one axis, and pass linestyle / alpha to style the lines:
plt.grid(True, axis="y", linestyle="--", alpha=0.7)plt.xlim() and plt.ylim()
Set the visible range on each axis:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4, 5], [2, 4, 1, 5, 3])
plt.xlim(0, 6) # show a bit of padding on each side
plt.ylim(0, 7)
plt.show()plt.xticks() and plt.yticks()
Control which tick marks appear and what labels they carry:
import matplotlib.pyplot as plt
plt.plot([0, 1, 2, 3, 4], [10, 20, 15, 25, 30])
plt.xticks([0, 1, 2, 3, 4], ["Mon", "Tue", "Wed", "Thu", "Fri"])
plt.yticks([10, 20, 30], ["Low", "Mid", "High"])
plt.show()plt.figure()
Create a new figure explicitly. This is important in scripts that produce multiple separate plots:
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4)) # width, height in inches
plt.plot([1, 2, 3], [3, 1, 4])
plt.title("Figure with custom size")
plt.show()figsize controls the output size. A wider figure (e.g. (12, 4)) suits time-series data; a square figure suits scatter plots.
plt.savefig()
Save the current figure to a file instead of (or in addition to) displaying it:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
plt.title("Saved Plot")
plt.savefig("output.png", dpi=150, bbox_inches="tight")
plt.show()Supported formats include png, pdf, svg, and jpg. bbox_inches="tight" trims extra whitespace around the figure. Call savefig() before show() — show() clears the figure's state in some backends.
plt.close() and plt.clf()
In a loop that produces many figures, always close figures you are done with to free memory:
plt.close() # close the current figure
plt.close("all") # close every open figure
plt.clf() # clear the current figure without closing its windowSubplots via pyplot
plt.subplots() is the bridge between the pyplot and OO interfaces. It creates a Figure and one or more Axes objects, then returns both:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(10, 4)) # 1 row, 2 columns
# Left panel
axes[0].plot([1, 2, 3], [1, 4, 9], color="steelblue")
axes[0].set_title("Quadratic")
axes[0].set_xlabel("x")
axes[0].set_ylabel("x²")
# Right panel
axes[1].plot([1, 2, 3], [1, 8, 27], color="tomato")
axes[1].set_title("Cubic")
axes[1].set_xlabel("x")
axes[1].set_ylabel("x³")
fig.suptitle("Growth Curves", fontsize=14)
plt.tight_layout()
plt.show()plt.tight_layout() automatically adjusts spacing between panels to prevent titles and labels from overlapping.
pyplot vs. the Object-Oriented API
Once you move beyond a single axes, the stateful API becomes harder to reason about. Use the OO API (via fig, ax = plt.subplots()) when:
- You have more than one subplot.
- You are writing a function that creates and returns a plot.
- You need fine-grained control over tick formatters, secondary axes, or inset axes.
| Task | pyplot style | OO style |
|---|---|---|
| Set title | plt.title("...") | ax.set_title("...") |
| Set x-label | plt.xlabel("...") | ax.set_xlabel("...") |
| Set x limits | plt.xlim(0, 10) | ax.set_xlim(0, 10) |
| Draw a line | plt.plot(x, y) | ax.plot(x, y) |
The pattern is simple: most plt.something() functions have an ax.set_something() equivalent on the Axes object.
A Complete Example
The following script combines the most common pyplot functions into one self-contained, runnable example:
import matplotlib.pyplot as plt
# Data
years = [2019, 2020, 2021, 2022, 2023]
product_a = [45, 38, 52, 61, 70]
product_b = [30, 42, 39, 55, 65]
# Figure
plt.figure(figsize=(9, 5))
# Two series
plt.plot(years, product_a, marker="o", color="steelblue",
linewidth=2, label="Product A")
plt.plot(years, product_b, marker="s", color="tomato",
linewidth=2, label="Product B")
# Labels and decoration
plt.xlabel("Year", fontsize=12)
plt.ylabel("Units Sold (thousands)", fontsize=12)
plt.title("Annual Sales Comparison", fontsize=14)
plt.legend()
plt.grid(True, linestyle="--", alpha=0.5)
plt.xticks(years)
# Save and display
plt.savefig("sales_comparison.png", dpi=150, bbox_inches="tight")
plt.show()This example shows both series on the same axes, a legend, grid, custom x-tick labels, and saves the result to a PNG file.
Common Pitfalls
Forgetting plt.show() — in a plain Python script (not Jupyter), the plot window never opens without it. In Jupyter, %matplotlib inline makes this automatic.
Calling plt.savefig() after plt.show() — show() finalizes and resets the figure. Save first, then show:
plt.savefig("chart.png") # correct order
plt.show()Multiple figures accumulating — in a loop, each plt.figure() call creates a new figure that stays in memory until you call plt.close(). Close figures you no longer need.
Mixing pyplot and OO styles inconsistently — it is fine to use both, but be deliberate: get the Axes object and work with it directly rather than relying on pyplot's implicit "current axes" when you have more than one axes.
Next Steps
- Matplotlib Line Plots — line styles, multiple series, and filled areas in depth.
- Matplotlib Markers — all built-in marker shapes and how to style them.
- Matplotlib Labels — titles, axis labels, annotations, and text placement.
- Matplotlib Grid — grid line styles, minor ticks, and background styling.
- Matplotlib Bars — vertical, horizontal, stacked, and grouped bar charts.
- Matplotlib Scatter — scatter plots with color maps and size encoding.
- Matplotlib Histograms — bin control, density curves, and overlapping distributions.
- Matplotlib Subplot — multi-panel layouts with
subplots()andGridSpec.