This page is for anyone who wants practical matplotlib.pyplot usage in Python: install and import, your first line chart, common plot types, styling, figures and subplots, and saving files. For figure sizing and subplots(), see pyplot figure with matplotlib; for vertical reference lines, see plt.vlines; for statistical scatter plots, Seaborn scatterplot wraps the same backend.
Tested on: Python 3.13.3; Matplotlib 3.8.3; kernel 6.14.0-37-generic; Ubuntu 25.04.
What is Matplotlib in Python?
Matplotlib is Python’s standard plotting library for static charts: line plots, scatter, bars, histograms, pie charts, images, and more. Plotting functions accept any sequence of numbers; NumPy arrays behave like lists here and are the usual choice in real analysis. Matplotlib turns data plus styling into a Figure you can display or write to PNG, PDF, SVG, and other formats.
What is pyplot and plt in Python?
The submodule matplotlib.pyplot exposes a MATLAB-like API: functions such as plot, scatter, and title operate on the “current” figure and axes. The community convention is:
import matplotlib.pyplot as pltHere plt is only an alias; it keeps notebooks and scripts short. Behind the scenes, pyplot tracks a default “current” Figure and Axes, so the order of calls matters. For larger programs, many teams prefer fig, ax = plt.subplots() and call methods on ax so each plot’s state is explicit and you avoid accidental reuse of the same axes.
Install and import Matplotlib
Install Matplotlib using pip
From a virtual environment or system Python:
pip install matplotlibOn this machine, pip show matplotlib reports something like the following (versions and paths will match your install):
Name: matplotlib
Version: 3.8.3
Summary: Python plotting package
Home-page: https://matplotlib.org
Requires: contourpy, cycler, fonttools, kiwisolver, numpy, packaging, pillow, pyparsing, python-dateutilIf you install packages from version control or private indexes, the same workflow applies as in install Python package from GitHub: activate your environment, then pip install.
With Anaconda, you can use conda install matplotlib instead; see install conda on Ubuntu for context on Conda environments.
Import pyplot as plt
Headless servers and CI jobs often have no display. Set a non-interactive backend before importing pyplot if you only save files:
import matplotlib
matplotlib.use("Agg") # no GUI; safe for servers
import matplotlib.pyplot as pltFor local scripts with a screen, you can omit matplotlib.use and call plt.show() to open a window.
Create your first Matplotlib plot
Simple line plot example
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
plt.plot(x, y)
plt.savefig("first-line.png")Running this in the current directory writes first-line.png with a curve through your (x, y) points.
Add title and axis labels
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
plt.plot(x, y)
plt.title("Squares")
plt.xlabel("x")
plt.ylabel("x squared")
plt.savefig("first-line-labeled.png")Show the plot using plt.show()
plt.show() displays the current figure and blocks until you close the window on interactive backends (for example TkAgg on the desktop). In Jupyter Notebook, the classic %matplotlib inline magic still appears in older material; current practice is often the inline backend by default or ipympl for interaction. If you use Agg and only call savefig, you do not need show(), and nothing pops up on a headless server—which is usually what you want for batch jobs.
Matplotlib plot examples
The snippets below use Agg and savefig so you can run them without a display; adjust filenames as you like. Each block is a minimal script—run it once, open the image it writes, and add plt.close() after savefig when you generate many figures in a loop so memory stays bounded.
Line plot
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
plt.plot(x, y, marker="o")
plt.title("Line plot")
plt.savefig("line.png")Scatter plot
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
plt.scatter(x, y, color="C0")
plt.title("Scatter plot")
plt.savefig("scatter.png")Bar chart
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
labels = ["A", "B", "C"]
values = [4, 7, 1]
plt.bar(labels, values)
plt.title("Bar chart")
plt.savefig("bar.png")Histogram
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
values = [1, 2, 2, 3, 3, 3, 4, 4, 5]
plt.hist(values, bins=5, edgecolor="black")
plt.title("Histogram")
plt.savefig("hist.png")Pie chart
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
labels = ["Apple", "Banana", "Cherry"]
sizes = [15, 30, 45]
plt.pie(sizes, labels=labels, autopct="%1.1f%%")
plt.title("Pie chart")
plt.savefig("pie.png")Make beautiful plots in Matplotlib
Small layout and style choices add up: readable figure size, grid, color and marker choices, legends, tight margins, and built-in style sheets.
Use figure size
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.figure(figsize=(9, 4))
plt.plot([0, 1, 2], [0, 1, 4], marker="s")
plt.title("Wide figure")
plt.savefig("wide.png")figsize is in inches; pair with dpi in savefig when you care about pixel dimensions.
Add grid lines
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot([0, 1, 2, 3], [0, 1, 4, 9])
plt.grid(True, linestyle=":", alpha=0.7)
plt.savefig("grid.png")Use colors and markers
plot accepts color, marker, and linestyle; see optional arguments in Python for the general idea—here they map to Matplotlib keyword parameters.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot(
[0, 1, 2, 3],
[0, 1, 4, 9],
color="tab:green",
marker="o",
linestyle="--",
linewidth=2,
markersize=8,
)
plt.savefig("styled-line.png")Add legend
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3]
plt.plot(x, [0, 1, 4, 9], label="n^2")
plt.plot(x, [0, 1, 2, 3], label="n")
plt.legend()
plt.savefig("legend.png")Use tight layout
plt.tight_layout() adjusts padding so titles and axis labels are less likely to overlap panel edges—especially useful before savefig.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot([0, 1, 2], [0, 1, 4])
plt.title("Title that needs room")
plt.xlabel("x axis")
plt.ylabel("y axis")
plt.tight_layout()
plt.savefig("tight.png")Use Matplotlib styles
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.style.use("ggplot")
plt.plot([0, 1, 2], [1, 3, 2])
plt.savefig("style-ggplot.png")
plt.close()
plt.style.use("default")Try print(plt.style.available) for names on your install. Switch back to "default" when you want the stock look in the same session.
Figure and Axes in Matplotlib
Figure vs Axes
A Figure is the top-level container: overall size in inches, optional suptitle, and one or more plotting regions. An Axes (singular name, plural often written “axes”) is one of those regions: it owns the x/y (or polar) spines, tick locators, labels, and the line or patch artists you draw. fig.savefig(...) saves the whole figure; ax.set_title(...) only affects one panel. One figure can hold many axes—for example a row of charts that share a theme or color cycle.
When to use plt.subplots()
Call fig, ax = plt.subplots() (or plt.subplots(nrows, ncols)) when you want a clear handle to pass around, multiple subplots in one layout, or code that mirrors the Matplotlib object-oriented API. Use bare plt.plot for quick one-off charts.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(5, 3))
ax.plot([0, 1, 2], [0, 1, 4])
ax.set_title("OO style")
fig.savefig("oo-line.png")Create multiple plots with subplots
Create two plots side by side
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot([0, 1, 2], [0, 1, 4])
ax1.set_title("Line")
ax2.scatter([0, 1, 2], [0, 1, 4])
ax2.set_title("Scatter")
fig.tight_layout()
fig.savefig("side-by-side.png")Create a 2x2 subplot layout
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [0, 1, 2, 3]
y = [0, 1, 4, 9]
fig, ax = plt.subplots(2, 2, figsize=(8, 8))
ax[0, 0].plot(x, y)
ax[0, 0].set_title("Line")
ax[0, 1].scatter(x, y)
ax[0, 1].set_title("Scatter")
ax[1, 0].bar(["a", "b", "c"], [3, 5, 2])
ax[1, 0].set_title("Bar")
ax[1, 1].hist([1, 2, 2, 3, 3, 3], bins=4, edgecolor="black")
ax[1, 1].set_title("Histogram")
fig.tight_layout()
fig.savefig("grid-2x2.png")Save Matplotlib plot as image
Save as PNG
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot([0, 1, 2], [2, 3, 1])
plt.savefig("plot.png", format="png")Save as SVG or PDF
Vector formats scale cleanly for print and slides:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot([0, 1, 2], [2, 3, 1])
plt.savefig("plot.svg")
plt.savefig("plot.pdf")Use dpi and bbox_inches
Higher dpi increases raster resolution. bbox_inches="tight" trims extra margin so labels are not cut off.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.plot([0, 1, 2], [2, 3, 1])
plt.title("Export settings")
plt.savefig("plot-hidpi.png", dpi=200, bbox_inches="tight")For web assets you sometimes want a transparent background: pass transparent=True to savefig. When a script creates many figures in a loop, call plt.close(fig) or plt.close("all") after each savefig so memory does not grow without bound.
Common mistakes with Matplotlib pyplot
- Importing
pyplotbefore callingmatplotlib.use("Agg")on headless machines—set the backend first, then importpyplot. - Calling
savefigafterplt.close()or after the figure is discarded; save while the figure still exists. - Overlapping labels in multi-panel figures; use
fig.tight_layout()orconstrained_layout=Trueinsubplots. - Mixing stateful
plt.*calls with multiple figures without tracking which figure is “current”; prefer keeping afigreference. - Expecting
plt.show()to write files; usesavefigfor persistent output. - Creating hundreds of plots in one process without
plt.close(); figures stay in memory until closed. - Re-running cells in Jupyter that call
plt.plotrepeatedly on the pyplot state machine; preferfig, ax = plt.subplots()and reuseax, or clear output between runs.
Matplotlib pyplot quick reference table
| Task | Typical call |
|---|---|
| Headless backend | matplotlib.use("Agg") before import matplotlib.pyplot as plt |
| Import | import matplotlib.pyplot as plt |
| Line | plt.plot(x, y) or ax.plot(x, y) |
| Scatter | plt.scatter(x, y) |
| Bars | plt.bar(labels, values) |
| Histogram | plt.hist(data, bins=...) |
| Pie | plt.pie(sizes, labels=..., autopct=...) |
| Labels | plt.title, plt.xlabel, plt.ylabel |
| Grid | plt.grid(True) |
| Legend | plt.legend() after labeling series |
| Layout | plt.tight_layout() or fig.tight_layout() |
| Subplots | fig, ax = plt.subplots(rows, cols) |
| Save | plt.savefig("out.png", dpi=150, bbox_inches="tight") |
| Show (interactive) | plt.show() |
| Free memory | plt.close(fig) or plt.close("all") |
| Style | plt.style.use("ggplot") |
Summary
You can cover most day-to-day work with import matplotlib.pyplot as plt, a small amount of data as lists or arrays, and calls such as plot, scatter, bar, hist, and pie. Titles, labels, grids, legends, figure size, style sheets, and tight_layout make charts easier to read. When scripts grow, plt.subplots returns explicit Figure and Axes objects that stay maintainable. Finish with savefig (and dpi / bbox_inches as needed), set the Agg backend on servers without a display, and close figures when you generate many of them in one run.

