/ Visualization - Intro to matplotlib
Visualization - Intro to matplotlib¶
Matplotlib is the most widely used Python library for creating static, animated, and interactive visualizations. It provides a MATLAB-like plotting interface through pyplot and gives fine-grained control over every element of a figure.
What you'll learn in this notebook:
- Installing and importing Matplotlib
- The anatomy of a Matplotlib figure
- Common 2D plots: line, scatter, bar, histogram, pie, heatmap, contour
- Common 3D plots: surface, wireframe, scatter, bar, contour
- Customizing plots: titles, labels, legends, colormaps, and styles
Installation¶
If Matplotlib is not already installed, run the cell below.
# Uncomment to install
!pip install matplotlib -q
Imports¶
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 – registers 3D projection
import numpy as np
print(f"Matplotlib version: {matplotlib.__version__}")
# Use a clean built-in style
plt.style.use('seaborn-v0_8-whitegrid')
Matplotlib version: 3.10.6
Anatomy of a Matplotlib Figure¶
A Matplotlib Figure is the top-level container. Inside it live one or more Axes objects — each Axes is an individual plot with its own coordinate system, title, labels, and artists (lines, patches, text, etc.).
Figure
└── Axes
├── Title
├── XAxis (label, tick marks, tick labels)
├── YAxis (label, tick marks, tick labels)
└── Artists (Line2D, PathPatch, Text, …)
fig, ax = plt.subplots(figsize=(6, 4))
ax.set_title('Anatomy of a Figure', fontsize=14, fontweight='bold')
ax.set_xlabel('X Axis Label')
ax.set_ylabel('Y Axis Label')
ax.annotate('This is an Axes object', xy=(0.5, 0.5), xycoords='axes fraction',
ha='center', va='center', fontsize=12,
bbox=dict(boxstyle='round,pad=0.3', facecolor='wheat', alpha=0.7))
plt.tight_layout()
plt.show()
2D Plots¶
Line Plot¶
Line plots are ideal for showing continuous data and trends over an ordered dimension (e.g., time).
x = np.linspace(0, 2 * np.pi, 300)
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, np.sin(x), label='sin(x)', linewidth=2)
ax.plot(x, np.cos(x), label='cos(x)', linewidth=2, linestyle='--')
ax.plot(x, np.sin(x) * np.cos(x), label='sin(x)·cos(x)', linewidth=2, linestyle=':')
ax.set_title('Line Plot – Trigonometric Functions')
ax.set_xlabel('x (radians)')
ax.set_ylabel('Amplitude')
ax.legend()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(
lambda val, pos: f'{val/np.pi:.1g}π' if val != 0 else '0'))
plt.tight_layout()
plt.show()
Scatter Plot¶
Scatter plots reveal relationships between two continuous variables and are great for spotting clusters or outliers.
rng = np.random.default_rng(42)
n = 200
x = rng.normal(0, 1, n)
y = 0.8 * x + rng.normal(0, 0.6, n)
color_vals = np.sqrt(x**2 + y**2)
fig, ax = plt.subplots(figsize=(6, 5))
sc = ax.scatter(x, y, c=color_vals, cmap='viridis', alpha=0.8, edgecolors='none', s=40)
fig.colorbar(sc, ax=ax, label='Distance from origin')
ax.set_title('Scatter Plot – Correlated Variables')
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.tight_layout()
plt.show()
Bar Chart¶
Bar charts compare discrete categories. Use barh for horizontal bars when category labels are long.
languages = ['Python', 'JavaScript', 'TypeScript', 'Java', 'C++', 'Rust', 'Go']
scores = [30.3, 22.1, 9.4, 8.8, 7.5, 4.6, 3.7]
colors = plt.cm.tab10(np.linspace(0, 0.7, len(languages)))
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(languages, scores, color=colors, edgecolor='white', linewidth=0.8)
ax.bar_label(bars, fmt='%.1f%%', padding=3, fontsize=9)
ax.set_title('Bar Chart – Programming Language Popularity (2025, fictional data)')
ax.set_ylabel('Share (%)')
ax.set_ylim(0, 36)
plt.tight_layout()
plt.show()
Histogram¶
Histograms show the distribution of a single continuous variable by grouping values into bins.
rng = np.random.default_rng(0)
data_a = rng.normal(loc=60, scale=10, size=800)
data_b = rng.normal(loc=75, scale=8, size=600)
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(data_a, bins=40, alpha=0.6, label='Group A', color='steelblue', edgecolor='white')
ax.hist(data_b, bins=40, alpha=0.6, label='Group B', color='tomato', edgecolor='white')
ax.set_title('Histogram – Overlapping Distributions')
ax.set_xlabel('Value')
ax.set_ylabel('Count')
ax.legend()
plt.tight_layout()
plt.show()
Pie Chart¶
Pie charts show part-to-whole relationships. Use sparingly — bar charts are usually easier to read for comparisons.
labels = ['Python', 'JavaScript', 'TypeScript', 'Java', 'Other']
sizes = [30.3, 22.1, 9.4, 8.8, 29.4]
explode = (0.05, 0, 0, 0, 0)
fig, ax = plt.subplots(figsize=(6, 6))
wedges, texts, autotexts = ax.pie(
sizes, explode=explode, labels=labels,
autopct='%1.1f%%', startangle=140,
colors=plt.cm.Pastel1.colors)
for t in autotexts:
t.set_fontsize(9)
ax.set_title('Pie Chart – Language Popularity')
plt.tight_layout()
plt.show()
Heatmap (imshow)¶
Heatmaps encode a matrix of values as color. Common uses include correlation matrices, confusion matrices, and spatial data.
rng = np.random.default_rng(7)
# Simulate a correlation-like symmetric matrix
raw = rng.standard_normal((8, 8))
data = np.corrcoef(raw)
features = [f'F{i}' for i in range(1, 9)]
fig, ax = plt.subplots(figsize=(6, 5))
im = ax.imshow(data, cmap='coolwarm', vmin=-1, vmax=1)
fig.colorbar(im, ax=ax, label='Correlation')
ax.set_xticks(range(len(features))); ax.set_xticklabels(features)
ax.set_yticks(range(len(features))); ax.set_yticklabels(features)
ax.set_title('Heatmap – Correlation Matrix')
for i in range(len(features)):
for j in range(len(features)):
ax.text(j, i, f'{data[i,j]:.2f}', ha='center', va='center',
fontsize=7, color='black')
plt.tight_layout()
plt.show()
Contour Plot¶
Contour (and filled-contour) plots display isolines of a scalar field defined over a 2D grid — similar to topographic maps.
x = np.linspace(-3, 3, 200)
y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
# Filled contour
cf = axes[0].contourf(X, Y, Z, levels=20, cmap='RdYlBu')
fig.colorbar(cf, ax=axes[0])
axes[0].set_title('Filled Contour (contourf)')
axes[0].set_xlabel('x'); axes[0].set_ylabel('y')
# Line contour
cs = axes[1].contour(X, Y, Z, levels=20, cmap='RdYlBu')
axes[1].clabel(cs, inline=True, fontsize=7)
axes[1].set_title('Line Contour (contour)')
axes[1].set_xlabel('x'); axes[1].set_ylabel('y')
plt.tight_layout()
plt.show()
3D Surface Plot¶
Surface plots render a function z = f(x, y) as a shaded mesh — useful for visualising optimization landscapes and physical fields.
x = np.linspace(-5, 5, 80)
y = np.linspace(-5, 5, 80)
X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2) + 1e-9
Z = np.sin(R) / R
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='viridis', linewidth=0, antialiased=True, alpha=0.9)
fig.colorbar(surf, ax=ax, shrink=0.5, aspect=10, label='z')
ax.set_title('3D Surface – sinc function')
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_zlabel('z')
plt.tight_layout()
plt.show()
3D Wireframe Plot¶
Wireframe plots draw only the grid lines of the surface, making the underlying structure more transparent.
x = np.linspace(-4, 4, 40)
y = np.linspace(-4, 4, 40)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y)
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X, Y, Z, rstride=2, cstride=2, color='teal', linewidth=0.7, alpha=0.7)
ax.set_title('3D Wireframe – cos(x)·sin(y)')
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_zlabel('z')
plt.tight_layout()
plt.show()
3D Scatter Plot¶
3D scatter plots extend the 2D scatter concept to three dimensions — handy for exploring clusters in high-dimensional data (after dimensionality reduction).
rng = np.random.default_rng(123)
n_per_cluster = 80
centers = [(1,1,1), (-1,-1,1), (1,-1,-1), (-1,1,-1)]
colors_c = ['tomato', 'steelblue', 'seagreen', 'goldenrod']
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
for (cx, cy, cz), col in zip(centers, colors_c):
xs = rng.normal(cx, 0.3, n_per_cluster)
ys = rng.normal(cy, 0.3, n_per_cluster)
zs = rng.normal(cz, 0.3, n_per_cluster)
ax.scatter(xs, ys, zs, c=col, s=20, alpha=0.7,
label=f'Cluster ({cx},{cy},{cz})')
ax.set_title('3D Scatter – Four Clusters')
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_zlabel('z')
ax.legend(fontsize=8, loc='upper left')
plt.tight_layout()
plt.show()
3D Bar Chart¶
3D bars (bar3d) add a depth dimension to a traditional bar chart — useful for small matrices of categorical data.
months = ['Jan', 'Feb', 'Mar', 'Apr']
products = ['A', 'B', 'C']
sales = np.array([[120, 85, 95, 110],
[60, 90, 75, 80],
[40, 55, 70, 65]])
fig = plt.figure(figsize=(9, 6))
ax = fig.add_subplot(111, projection='3d')
colors_b = ['steelblue', 'tomato', 'seagreen']
dx = dy = 0.6
for pi, (prod, col) in enumerate(zip(products, colors_b)):
for mi in range(len(months)):
ax.bar3d(mi - dx/2, pi - dy/2, 0,
dx, dy, sales[pi, mi],
color=col, alpha=0.8, edgecolor='white', linewidth=0.5)
ax.set_xticks(range(len(months))); ax.set_xticklabels(months)
ax.set_yticks(range(len(products))); ax.set_yticklabels(products)
ax.set_xlabel('Month'); ax.set_ylabel('Product'); ax.set_zlabel('Sales')
ax.set_title('3D Bar Chart – Monthly Sales by Product')
plt.tight_layout()
plt.show()
/var/folders/nx/gq421vkn2h1cxq_cljnl3r1m0000gn/T/ipykernel_59093/1736813720.py:22: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all Axes decorations. plt.tight_layout()
3D Contour Plot¶
You can project a contour plot onto a 3D surface or onto the floor/walls of a 3D axis using contour with zdir and offset parameters.
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2) / 2)
fig = plt.figure(figsize=(9, 7))
ax = fig.add_subplot(111, projection='3d')
# Surface
surf = ax.plot_surface(X, Y, Z, cmap='plasma', alpha=0.75, linewidth=0)
# Floor projection
ax.contourf(X, Y, Z, levels=15, zdir='z', offset=-0.05, cmap='plasma', alpha=0.4)
# Side projections
ax.contourf(X, Y, Z, levels=10, zdir='x', offset=-3.5, cmap='plasma', alpha=0.3)
ax.contourf(X, Y, Z, levels=10, zdir='y', offset= 3.5, cmap='plasma', alpha=0.3)
ax.set_xlim(-3.5, 3); ax.set_ylim(-3, 3.5); ax.set_zlim(-0.05, 1.05)
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_zlabel('z')
ax.set_title('3D Surface with Contour Projections')
fig.colorbar(surf, ax=ax, shrink=0.4, aspect=10)
plt.tight_layout()
plt.show()
Summary¶
| Plot type | Function | Best for |
|---|---|---|
| Line | ax.plot |
Trends, continuous data |
| Scatter | ax.scatter |
Relationships, clusters |
| Bar | ax.bar / ax.barh |
Category comparisons |
| Histogram | ax.hist |
Distributions |
| Pie | ax.pie |
Part-to-whole |
| Heatmap | ax.imshow |
Matrices, correlations |
| Contour | ax.contour / contourf |
Scalar fields, isolines |
| 3D Surface | ax.plot_surface |
z = f(x,y) landscapes |
| 3D Wireframe | ax.plot_wireframe |
Transparent surfaces |
| 3D Scatter | ax.scatter (3D) |
Clusters in 3D |
| 3D Bar | ax.bar3d |
Small category matrices |
| 3D Contour | ax.contour / contourf (3D) |
Surface + projections |
Further reading:
© 2026 Ivan Cao-Berg Pittsburgh Supercomputing Center, Carnegie Mellon University
Licensed under the GNU General Public License v2.0 (GPL-2).
You may redistribute and/or modify this work under the terms of GPL-2.
This work is distributed WITHOUT ANY WARRANTY.
Happy computing.