import numpy as np
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x)
# Line with style
plt.plot(x, y, color='#2196F3', linewidth=2,
linestyle='--', marker='o', markersize=4,
label='sin(x)')
# Scatter — variable size & color
rng = np.random.default_rng(42)
colors = rng.random(100)
sizes = rng.uniform(10, 200, 100)
plt.scatter(rng.normal(0, 1, 100),
rng.normal(0, 1, 100),
c=colors, s=sizes, alpha=0.6, cmap='viridis')
plt.colorbar(label='Value')
categories = ['A', 'B', 'C', 'D']
values = [23, 45, 56, 78]
errors = [3, 5, 2, 7]
# Bar with error bars
plt.bar(categories, values, yerr=errors,
capsize=5, color=['#4CAF50','#2196F3','#FF9800','#F44336'],
edgecolor='white', linewidth=1.5)
# Stacked bar
plt.bar(cats, v1, label='Group 1', color='steelblue')
plt.bar(cats, v2, bottom=v1, label='Group 2', color='coral')
# Histogram
data = rng.standard_normal(5000)
plt.hist(data, bins=50, density=True, alpha=0.7,
color='teal', edgecolor='white')
plt.hist(data, bins=50, density=True, alpha=0.4,
color='orange', edgecolor='white',
histtype='stepfilled', cumulative=True)
# Pie chart
labels = ['Python', 'R', 'Julia', 'Scala']
sizes = [40, 30, 20, 10]
explode = (0.05, 0, 0, 0)
plt.pie(sizes, labels=labels, autopct='%1.1f%%',
explode=explode, shadow=True, startangle=140,
wedgeprops=dict(edgecolor='white', linewidth=2))
# Box plot
plt.boxplot([rng.normal(m, s, 200)
for m, s in [(0,1),(2,1.5),(4,0.5)]],
labels=['Group A','Group B','Group C'],
patch_artist=True, notch=True,
boxprops=dict(facecolor='lightblue', alpha=0.7))
# Violin plot
plt.violinplot([g1, g2, g3], showmeans=True,
showmedians=True)
x = np.linspace(-3, 3, 200)
y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
# Contour lines
plt.contour(X, Y, Z, levels=15, cmap='RdBu')
# Filled contour
plt.contourf(X, Y, Z, levels=15, cmap='RdBu')
plt.colorbar(label='f(x, y)')
💡For overlapping histograms, use histtype='stepfilled' with transparency so both distributions remain visible.
# Color formats
plt.plot(x, y, color='#FF5722') # hex
plt.plot(x, y, color='dodgerblue') # named
plt.plot(x, y, color=(0.2, 0.6, 0.8)) # RGB tuple 0-1
plt.plot(x, y, color='C3') # property cycle
# Colormaps
cmap = plt.cm.get_cmap('viridis', 10) # discrete: 10 colors
colors = cmap(np.linspace(0, 1, 5))
# Linestyles
for ls in ['-', '--', '-.', ':', (0, (5, 1)), (0, (3, 1, 1, 1))]:
plt.plot(x, y, linestyle=ls, linewidth=2)
ax.set_xlabel('Time (s)', fontsize=12, color='gray')
ax.set_ylabel('Value', fontsize=12, labelpad=10)
ax.set_title('My Plot', fontsize=16, fontweight='bold', loc='left')
# Ticks & limits
ax.set_xlim(0, 100)
ax.set_ylim(-1, 1)
ax.set_xticks([0, 25, 50, 75, 100])
ax.set_xticklabels(['Start', 'Q1', 'Mid', 'Q3', 'End'],
rotation=45, ha='right')
ax.tick_params(axis='both', which='major', labelsize=10)
# Log / symlog scale
ax.set_xscale('log')
ax.set_yscale('symlog', linthresh=0.01)
# Legend placement
ax.legend(loc='upper right', frameon=True, shadow=True,
fancybox=True, framealpha=0.9, fontsize=9)
ax.legend(loc='lower center', ncol=3, bbox_to_anchor=(0.5, -0.15))
# Grid
ax.grid(True, which='major', linestyle='-', linewidth=0.5, alpha=0.3)
ax.grid(True, which='minor', linestyle=':', linewidth=0.3, alpha=0.2)
ax.minorticks_on()
# Spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_color('gray')
# Built-in styles
plt.style.use('ggplot') # R-style
plt.style.use('seaborn-v0_8') # seaborn-inspired
plt.style.use('dark_background')
plt.style.use('fivethirtyeight')
# Context manager — temporary style
with plt.style.context('bmh'):
plt.plot(x, y)
plt.show()
# Custom rcParams
plt.rcParams.update({
'font.size': 12,
'axes.titlesize': 14,
'figure.facecolor': '#1a1a2e',
'axes.facecolor': '#16213e',
'text.color': 'white',
'axes.labelcolor': '#aaa',
'xtick.color': '#aaa',
'ytick.color': '#aaa',
})
| Colormap | Type | Best For |
|---|
| viridis | Sequential | General purpose, perceptually uniform |
| plasma | Sequential | Alternative to viridis |
| inferno | Sequential | Dark backgrounds |
| coolwarm | Diverging | Positive / negative values |
| RdBu | Diverging | Correlation matrices |
| Set2 | Qualitative | Categorical data (≤8 classes) |
| tab10 | Qualitative | Categorical data (≤10 classes) |
| twilight | Cyclic | Angles / phase data |
ax.annotate('Peak value',
xy=(3, 0.95), # arrow tip
xytext=(5, 0.7), # text position
arrowprops=dict(
arrowstyle='->', # '->', '-|>', '<->', 'fancy'
color='red',
connectionstyle='arc3,rad=0.3',
lw=1.5,
),
fontsize=11, fontweight='bold',
bbox=dict(boxstyle='round,pad=0.3',
facecolor='lightyellow', alpha=0.9))
# Text on axes
ax.text(0.5, 0.5, 'Centered',
transform=ax.transAxes, # relative coords 0-1
ha='center', va='center',
fontsize=20, alpha=0.3,
fontweight='bold', color='gray')
# Title & subtitle
ax.set_title('Main Title\nSubtitle line',
fontsize=16, linespacing=1.5)
# Figure-level text
fig.text(0.5, 0.01, 'Data source: WHO 2024',
ha='center', fontsize=9, color='gray')
# Arrows
ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle='->', color='black', lw=2))
# Spanning highlights
ax.axvspan(xmin=2, xmax=4, alpha=0.1, color='red', label='Anomaly')
ax.axhspan(ymin=0.8, ymax=1.0, alpha=0.1, color='green')
ax.axvline(x=5, color='gray', linestyle='--', linewidth=0.8)
ax.axhline(y=0, color='gray', linewidth=0.8)
# Mathtext (no LaTeX install needed)
ax.set_xlabel(r'$\sigma = \frac{1}{\sqrt{2\pi}}$')
ax.set_title(r'$\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}$')
# Full LaTeX (requires LaTeX installation)
plt.rcParams.update({'text.usetex': True})
ax.set_xlabel(r'$\sigma = \frac{1}{\sqrt{2\pi}}$')
⚠️Use transform=ax.transAxes to position text in axes-relative coordinates (0 to 1) so annotations don't shift when data changes.
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# Surface plot
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
ax.plot_surface(X, Y, Z, cmap='plasma',
alpha=0.8, edgecolor='none',
antialiased=True, rstride=2, cstride=2)
ax.set_zlabel('Z')
ax.view_init(elev=30, azim=45)
# 3D scatter
ax.scatter(xs, ys, zs, c=zs, cmap='viridis',
s=40, alpha=0.7, edgecolors='k', linewidth=0.5)
# Wireframe
ax.plot_wireframe(X, Y, Z, color='steelblue',
linewidth=0.5, alpha=0.5,
rstride=5, cstride=5)
# 3D line
ax.plot(xs, ys, zs, color='red', linewidth=2, label='trajectory')
ax.legend()
# 3D contour (projection on floor)
ax.contour(X, Y, Z, zdir='z', offset=-1, cmap='coolwarm')
# 2D contour projection
ax.contourf(X, Y, Z, zdir='x', offset=-5,
cmap='coolwarm', alpha=0.5)
# Set pane colors (dark theme)
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
ax.xaxis.pane.set_edgecolor('gray')
ax.grid(True, alpha=0.3)
| Method | Purpose | Example |
|---|
| ax.view_init() | Set camera angle | elev=30, azim=45 |
| fig.colorbar() | Color bar for surface | mappable=surf, shrink=0.5 |
| ax.set_xlim3d() | 3D axis limits | (-5, 5) |
| ax.dist | Camera distance | ax.dist = 8 |
| ax.set_box_aspect() | Equal aspect ratio | (1, 1, 0.3) |
💡For publication-quality 3D plots, rotate to find the best angle first interactively, then hard-code view_init(elev, azim) in your script.
# Basic save
fig.savefig('plot.png', dpi=300, bbox_inches='tight')
# Vector formats — publication quality
fig.savefig('plot.pdf') # PDF
fig.savefig('plot.svg') # SVG
fig.savefig('plot.eps') # EPS
# High-res raster
fig.savefig('plot.tiff', dpi=600,
bbox_inches='tight',
facecolor=fig.get_facecolor(),
transparent=False)
fig.savefig(
'output.png',
dpi=300, # resolution (dots per inch)
bbox_inches='tight', # trim whitespace
pad_inches=0.1, # padding around plot
facecolor='white', # figure background
transparent=False, # transparent background
metadata={'Author': 'You', 'Date': '2024'},
)
| Format | Type | Best For | Notes |
|---|
| PNG | Raster | Web, presentations | Lossless, universal |
| PDF | Vector | Papers, LaTeX | Scalable, small size |
| SVG | Vector | Web, editing | Editable in Inkscape/Illustrator |
| EPS | Vector | Legacy journals | Encapsulated PostScript |
| TIFF | Raster | Print, high-res | Uncompressed, large files |
| JPG | Raster | Quick sharing | Lossy compression, avoid for plots |
🚫Always set bbox_inches='tight' to prevent labels from being clipped. For LaTeX documents, PDF is preferred — matplotlib's PDF output uses consistent fonts and sharp lines at any scale.