入门
安装与第一个图形
pip install matplotlib 安装完整的 matplotlib 发行版(包含 pyplot 接口)。约定用 import matplotlib.pyplot as plt,几乎所有教程和示例都使用此别名。plt.show() 会阻塞直到关闭窗口;在 Jupyter 中 %matplotlib inline 将图形内嵌到输出单元格,%matplotlib widget 则启用交互式图形。
# install
pip install matplotlib
import matplotlib.pyplot as plt
import numpy as np
# a simple line plot
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title("Sine Wave")
plt.xlabel("x")
plt.ylabel("sin(x)")
plt.show()pyplot 状态式接口
pyplot 是一个状态机接口:它跟踪'当前图形'和'当前坐标轴',plt.plot() 等函数会作用于当前坐标轴,没有则自动创建一个。这种风格适合快速原型和交互式使用,但在程序化代码中面向对象的风格(fig, ax = plt.subplots())更清晰、更可控,尤其是在处理多个子图时。
import matplotlib.pyplot as plt
# pyplot tracks the "current" figure and axes
plt.figure() # create a new figure
plt.plot([1, 2, 3], [4, 5, 2])
plt.title("State-based") # applies to the current axes
plt.xlim(0, 4)
plt.ylim(0, 6)
plt.show()
# plt.gcf() -> current figure, plt.gca() -> current axes
print(plt.gca())Figure 与 Axes(面向对象接口)
Figure 是顶层容器,容纳一个或多个 Axes、颜色条、图例、文本等。Axes 是带有坐标轴的实际绘图区域。面向对象风格(用 ax.plot() 而非 plt.plot())显式控制哪个坐标轴,这是库代码和复杂图形的推荐风格。一个 Figure 可包含多个用 add_subplot 或 subplots 添加的 Axes。
import matplotlib.pyplot as plt
import numpy as np
# object-oriented interface: explicit Figure and Axes objects
fig, ax = plt.subplots() # fig is the canvas, ax is a single Axes
x = np.linspace(0, 5, 50)
ax.plot(x, x**2, label="x^2")
ax.plot(x, x**3, label="x^3")
ax.set_title("OO Interface")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
plt.show()常用导入与约定
np.linspace 创建均匀间隔的采样,非常适合折线图。约定:plt 是 pyplot 的标准别名,np 是 numpy 的别名。这两个别名在整个生态系统中是通用的——保持使用它们可让你的代码可读且对其他人友好。arr.shape 检查数组的维度;大多数绘图函数接受 1-D 数组并按顺序配对 (x, y) 值。
# the universal alias
import matplotlib.pyplot as plt
import numpy as np
# for the OO interface you often see
from matplotlib.figure import Figure
from matplotlib.axes import Axes
# set a global style once
plt.rcParams["figure.dpi"] = 100
plt.rcParams["font.size"] = 11
# inline backend in Jupyter (not needed in scripts)
# %matplotlib inline后端与 plt.show()
matplotlib 通过'后端'将图形渲染到屏幕或文件。交互式后端(Qt5Agg、TkAgg、MacOSX)打开 GUI 窗口;内联后端(SVG、notebook)在 Jupyter 中渲染。plt.show() 触发 GUI 事件循环并显示所有打开的图形——它应该通常是脚本的最后一行。plt.savefig() 在 show() 之前调用,否则图形已被清空。
import matplotlib
# list available backends
print(matplotlib.rcsetup.all_backends)
# force a backend (do this BEFORE importing pyplot)
# matplotlib.use("Agg") # non-interactive, for saving files
# matplotlib.use("TkAgg") # interactive Tk window
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
# plt.show() blocks until the window is closed
plt.savefig("out.png") # saving works without any GUI backend折线图 (plot)
基础折线图
plt.plot(x, y) 是最基础的绘图命令——用直线段连接 (x, y) 点。如果只传入一个数组,它被视为 y 值,x 默认为 0..N-1 的整数索引。plot 返回 Line2D 对象列表,你可以用它们在之后修改属性(如 line.set_color())。ax.plot() 在面向对象接口中做同样的事。
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = x * 2
plt.plot(x, y)
plt.title("y = 2x")
plt.xlabel("x")
plt.ylabel("y")
plt.grid(True)
plt.show()多条线
多次调用 plot 会在同一坐标轴上叠加线条,matplotlib 自动循环默认颜色。label= 关键字为每条线命名,plt.legend() 显示图例。ax.plot 支持一次性传入多对 (x, y, fmt) 参数:ax.plot(x, y1, 'r-', x, y2, 'b--')——对紧凑代码很方便。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2 * np.pi, 100)
plt.plot(x, np.sin(x), label="sin")
plt.plot(x, np.cos(x), label="cos")
plt.plot(x, np.sin(x) + np.cos(x), label="sin+cos")
plt.legend()
plt.title("Trig Functions")
plt.show()线型与标记
格式字符串 fmt = '[color][marker][line]' 是从 MATLAB 继承的简写:'r-' 是红色实线,'go' 是绿色圆点(无线),'k--' 是黑色虚线。也可用关键字 linestyle='--'、marker='o'、color='red' 等单独设置,在代码中更易读。markersize 控制标记大小,markevery 只在第 N 个点画标记以避免拥挤。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 5, 20)
# format string: [color][marker][linestyle]
plt.plot(x, x, "r-") # red solid line
plt.plot(x, x*2, "go--") # green circles, dashed
plt.plot(x, x*3, "bs:") # blue squares, dotted
plt.plot(x, x*4, "k^-.") # black triangles, dash-dot
# explicit kwargs (clearer, recommended)
plt.plot(x, x*5, color="purple", marker="D",
linestyle="-.", linewidth=2, markersize=6)颜色
matplotlib 接受多种颜色格式:单字符('r','g','b','k','w','c','m','y')、名称('crimson','steelblue')、十六进制('#11557C')、RGB 元组 ((0,0,0) 到 (1,1,1))、CSS4 名称以及 xkcd 颜色调查名称('xkcd:sky blue')。CN 格式('C0' 到 'C9')引用默认颜色循环,适合与样式无关的代码。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 1, 30)
plt.plot(x, x, color="red") # named color
plt.plot(x, x+0.2, color="#FF8800") # hex RGB
plt.plot(x, x+0.4, color=(0.1, 0.8, 0.2))# RGB tuple 0-1
plt.plot(x, x+0.6, color="C0") # cycle color 0
plt.plot(x, x+0.8, color="tab:purple") # Tableau palette
# gray shorthand: a string of float in [0,1]
plt.plot(x, x+1.0, color="0.5") # mid gray
plt.show()线宽、Alpha 与 zorder
linewidth(lw)是线宽(以点为单位,默认 1.5)。alpha 设置透明度(0=完全透明,1=完全不透明)——在数据点重叠时显示密度很有用。zorder 控制绘制顺序:zorder 值高的艺术家画在低的之上,所以把它们放在网格、填充和其他线之上。默认值:图像=1,线条=2,标记=3,文本=3。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
# alpha = transparency (0 invisible, 1 opaque)
# zorder = draw order; higher draws on top
plt.fill_between(x, np.sin(x), alpha=0.3, zorder=1)
plt.plot(x, np.sin(x), linewidth=2, zorder=2)
plt.plot(x, np.cos(x), linewidth=4, alpha=0.7, zorder=3)
plt.show()阶梯图与楼梯图
对于阶梯式数据(如数字采样信号),plot 的 where='pre'/'post'/'mid' 选项控制阶梯的水平段 相对于 x 值的对齐方式。ax.step 是显式等价物。stairs 直接从预计算的 bin 边缘绘制——它是直方图风格可视化的推荐方法,比用步骤语义绘制 bar 更高效且不易出错。
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(5)
y = [1, 3, 2, 4, 3]
# step: like plot but with horizontal/vertical steps
plt.step(x, y, where="post", label="post")
plt.step(x, y + 1, where="mid", label="mid")
plt.step(x, y + 2, where="pre", label="pre")
plt.legend(title="where=")
# stairs (matplotlib 3.4+): step from explicit bin edges
plt.stairs([1, 2, 1], baseline=0)
plt.show()散点图
基础散点图
ax.scatter(x, y) 绘制圆形标记,在低密度时与 plot(x, y, 'o') 等价。但当每个点需要独立的大小时 scatter 更强:它接受与 x/y 长度相同的 s= 和 c= 数组,使你能按数据维度缩放标记大小和颜色。在密集数据下 scatter 比 plot('o') 慢——在数万点时考虑后者。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
x = rng.random(50)
y = rng.random(50)
plt.scatter(x, y)
plt.title("Basic Scatter")
plt.xlabel("x")
plt.ylabel("y")
plt.axis("equal") # equal aspect ratio
plt.show()标记大小与颜色
s= 是以点为单位的标记面积(平方点),所以 s=100 是约 10x10 点的标记;c= 设置颜色。传递数组时,cmap 决定如何将值映射到颜色;vmin/vmax 固定颜色范围(适合跨多个图形比较)。alpha=0.5 让重叠可见。注意 s 是面积——标记的视觉直径按 sqrt(s) 缩放。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(1)
n = 50
x = rng.random(n)
y = rng.random(n)
sizes = rng.random(n) * 500 # area in points^2
colors = rng.random(n) # mapped to colormap
plt.scatter(x, y, s=sizes, c=colors, cmap="viridis", alpha=0.6)
plt.colorbar(label="value")
plt.title("Bubble Chart")
plt.show()颜色映射散点图
在 c= 传入数值数组并用 cmap= 选择颜色映射时,scatter 会将每个值映射到一个颜色——非常适合展示第三个维度。fig.colorbar(sc) 添加图例条。对于离散步长(如类别),使用离散颜色映射或列出边界。viridis 和 plasma 是感知均匀的,对色盲友好且在 灰度打印中也能保留顺序信息。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 200)
y = np.sin(x)
c = x # color by x value
sc = plt.scatter(x, y, c=c, cmap="plasma", vmin=0, vmax=10)
cb = plt.colorbar(sc)
cb.set_label("x position")
plt.title("Colored by x")
plt.show()透明度与过密绘制
当散点密集时,实心标记会相互遮挡(过密绘制)。降低 alpha 到 0.3-0.5 让重叠可见——颜色越深表示密度越高。对于非常密集的数据切换到 hexbin 或 hist2d 以显示二维密度。rasterized=True 将散点光栅化为图像而非向量路径——能大幅减小密集散点图的 PDF/SVG 文件大小。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(2)
n = 5000
x = rng.normal(0, 1, n)
y = rng.normal(0, 1, n)
# dense scatter: low alpha reveals density
plt.scatter(x, y, s=5, alpha=0.05, c="navy")
plt.title("Density via alpha")
# alternative: hexbin for very large datasets
plt.figure()
plt.hexbin(x, y, gridsize=40, cmap="Blues")
plt.colorbar(label="count")
plt.show()分类散点图
matplotlib 3.x 可直接为 x 传入字符串列表,自动用整数位置和字符串刻度标签绘制。这避免了手动用列表推导式枚举类别。对于带每个类别分布的统计图,Seaborn 的 stripplot/swarmplot/violinplot 提供更丰富的统计可视化,使用类似分类 API。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(3)
groups = ["A", "B", "C"]
data = [rng.normal(0, 1, 30),
rng.normal(2, 1, 30),
rng.normal(1, 1.5, 30)]
for i, d in enumerate(data):
# add jitter on x so points do not stack on one line
jitter = rng.uniform(-0.1, 0.1, len(d))
plt.scatter(np.full(len(d), i) + jitter, d, label=groups[i])
plt.xticks(range(len(groups)), groups)
plt.legend()
plt.show()柱状图
垂直柱状图
ax.bar(x, heights) 绘制垂直柱,顶部在 heights。x 通常是类别位置(数字或字符串)。width 默认 0.8;在并排分组柱图中,通过 +/- 偏移并使用更小的 width(如 0.35)来避免重叠。返回 BarContainer,允许后续修改单个柱的属性(如为突出显示某个而着色)。
import matplotlib.pyplot as plt
categories = ["Apple", "Banana", "Cherry", "Date"]
values = [25, 40, 30, 15]
bars = plt.bar(categories, values, color="tab:blue", edgecolor="black")
# annotate each bar with its value
for bar, v in zip(bars, values):
plt.text(bar.get_x() + bar.get_width()/2, v + 1,
str(v), ha="center", va="bottom")
plt.title("Fruit Sales")
plt.ylabel("units sold")
plt.ylim(0, 50)
plt.show()水平柱状图
barh(y, widths) 绘制水平柱;在类别名称较长时优于 bar,因为标签水平显示且无需旋转。y 位置默认为 0..N-1 的整数;set_yticks 和 set_yticklabels 设置类别标签。注意 width 是这里的柱长,height 才是柱的粗细(垂直厚度)——命名容易混淆。
import matplotlib.pyplot as plt
items = ["Reading", "Coding", "Sleep", "Exercise"]
hours = [2, 6, 8, 1]
plt.barh(items, hours, color="tab:green")
plt.xlabel("hours per day")
plt.title("Daily Activities")
# invert so the first item appears at the top
plt.gca().invert_yaxis()
plt.show()分组柱状图
并排分组柱:为每个系列计算偏移位置(x +/- n*width),用更小的 width(如 0.35)调用 bar 多次。set_xticks(x) 将刻度放在分组中心;将图例句柄和标签传递给 ax.legend()。这种手动偏移是标准做法——matplotlib 没有内置的分组柱图 API,但模式很直接。
import matplotlib.pyplot as plt
import numpy as np
labels = ["Q1", "Q2", "Q3", "Q4"]
a = [20, 35, 30, 35]
b = [25, 32, 34, 20]
x = np.arange(len(labels))
w = 0.35
plt.bar(x - w/2, a, w, label="2023")
plt.bar(x + w/2, b, w, label="2024")
plt.xticks(x, labels)
plt.ylabel("revenue")
plt.legend()
plt.show()堆叠柱状图
堆叠柱:第一次正常调用 bar;后续调用传入 bottom=previous_totals 来堆叠在上面。返回的 BarContainer 可用于在每个柱段中心添加标签。edgecolor='white' 在彩色柱段间添加细白线,提高可读性。确保所有系列对齐到相同的 x 位置,且各段的 bottom 累加。
import matplotlib.pyplot as plt
import numpy as np
labels = ["A", "B", "C"]
men = [20, 35, 30]
women = [25, 32, 34]
plt.bar(labels, men, label="Men")
plt.bar(labels, women, bottom=men, label="Women")
plt.legend()
plt.title("Stacked Bars")
plt.show()带误差棒的柱状图
bar/barh 接受 yerr(或 xerr)= 标量/数组以为每个柱添加误差棒。capsize 加上水平端帽;error_kw 字典传递给误差棒 Line2D(ecolor、elinewidth、capthick)。对于不对称误差,传入 shape (2, N) 的数组,行 0 为下界、行 1 为上界。
import matplotlib.pyplot as plt
import numpy as np
labels = ["A", "B", "C"]
means = [20, 35, 30]
errors = [2, 4, 3]
plt.bar(labels, means, yerr=errors, capsize=6,
color="tab:orange", edgecolor="black",
error_kw={"ecolor": "black", "linewidth": 1.5})
plt.title("Bar with Error Bars")
plt.ylabel("mean value")
plt.show()直 方图
基础直方图
plt.hist(data, bins=N) 将数据分入 N 个等宽箱并绘制柱状图。bins 接受整数(自动等宽箱)、箱边数组或字符串策略('auto'、'fd'、'scott' 等)。density=True 将计数归一化为概率密度(总面积=1),使其可与 PDF 曲线叠加。返回 (counts, bin_edges, patches) 三元组——patches 可用于设置单个柱的属性。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
data = rng.normal(0, 1, 1000)
plt.hist(data, bins=30)
plt.title("Histogram")
plt.xlabel("value")
plt.ylabel("frequency")
plt.show()选择箱数
箱数选择很重要:太少会隐藏形状(欠平滑),太多会显示噪声(过平滑)。'auto' 策略(Freedman-Diaconis)会根据数据量和分布自适应。range=(low, high) 限制分箱范围——在数据有离群值时很有用。对于分类数据使用 bar 而非 hist;hist 是为连续数值分布设计的。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(1)
data = rng.normal(0, 1, 1000)
# auto bin selection (Freedman-Diaconis, Sturges, etc.)
plt.hist(data, bins="auto", alpha=0.5, label="auto")
plt.hist(data, bins=10, alpha=0.5, label="10 bins")
plt.hist(data, bins=np.arange(-4, 4, 0.25),
alpha=0.5, label="0.25 width")
plt.legend()
plt.show()多个直方图
多次调用 hist 会叠加直方图。设置 alpha<1(如 0.5)使重叠区域可见。histtype='stepfilled' 移除内部边缘,使叠加更易读。density=True 归一化每条曲线,所以不同大小的数据集可在同一尺度上比较。stacked=True 改为堆叠而非叠加。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(2)
a = rng.normal(0, 1, 1000)
b = rng.normal(1, 1.2, 1000)
plt.hist(a, bins=30, alpha=0.6, label="A", color="tab:blue")
plt.hist(b, bins=30, alpha=0.6, label="B", color="tab:orange")
plt.legend()
plt.show()
# stacked alternative
plt.figure()
plt.hist([a, b], bins=30, stacked=True, label=["A", "B"])
plt.legend()
plt.show()密度 / 归一化
density=True 将计数转换为概率密度(每柱高度 = 计数/(总数 * 箱宽)),所以所有柱的面积之和为 1——这使直方 图可与概率密度函数曲线(如正态分布)叠加比较。这与 density=False(原始计数)对比,后者只显示绝对频率。在比较不同大小样本的分布形状时总是使用 density=True。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(3)
data = rng.normal(0, 1, 1000)
# density=True normalizes the area to 1 (PDF)
plt.hist(data, bins=30, density=True, alpha=0.6)
# overlay the theoretical PDF
from scipy.stats import norm
xs = np.linspace(-4, 4, 200)
plt.plot(xs, norm.pdf(xs), "r-", lw=2)
plt.title("Normalized Histogram + PDF")
plt.show()二维直方图
hist2d 将 (x, y) 点分入二维网格并显示为热力图——比密集散点图更好(避免过密绘制)。cmin=1 隐藏空单元(默认显示为背景色)。bins 接受整数或 (nx, ny) 元组。返回 (counts, xedges, yedges, QuadMesh)——后者传递给 colorbar 以显示计数图例。对于非矩形分箱使用 hexbin。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(4)
x = rng.normal(0, 1, 10000)
y = x + rng.normal(0, 1, 10000)
plt.hist2d(x, y, bins=40, cmap="Blues")
plt.colorbar(label="count")
plt.title("2D Histogram")
plt.xlabel("x")
plt.ylabel("y")
plt.show()饼图
基础饼图
ax.pie(sizes) 绘制饼图,扇形面积与 sizes 成正比。labels= 在每个扇形外侧添加文字;autopct='%1.1f%%' 在扇形内显示百分比。startangle=90 让第一个扇形从顶部开始(默认 0=右侧),逆时针排列。返回 (wedges, texts, autotexts)——其中 autotexts 是百分比标签,可单独设置样式。
import matplotlib.pyplot as plt
labels = ["Rent", "Food", "Transport", "Fun"]
sizes = [1200, 600, 300, 400]
plt.pie(sizes, labels=labels, autopct="%1.1f%%", startangle=90)
plt.title("Monthly Budget")
plt.axis("equal") # circle, not ellipse
plt.show()分离与阴影
explode 接受与 sizes 长度相同的偏移列表,把对应扇形向外拉出(0=无偏移,0.1=约 10% 半径)。shadow=True 添加伪 3D 阴影效果。对于现代数据可视化,饼图通常不推荐(人眼对角度的判断不如长度准确)——但小数量类别(<6)且需直观占比展示时仍可用。
import matplotlib.pyplot as plt
labels = ["A", "B", "C", "D"]
sizes = [30, 25, 25, 20]
explode = (0, 0.1, 0, 0) # pull the 2nd wedge out
plt.pie(sizes, labels=labels, explode=explode,
shadow=True, autopct="%1.0f%%",
startangle=140)
plt.title("Exploded Pie")
plt.show()环形图
wedges, _ = ax.pie(...) 之后用 set_width(0.4) 把每个扇形的'厚度'(从外径向内)缩小,留出中心空间形成环形。然后在中心用 ax.text(0,0,...) 写汇总值(如总数)。环形图通常比传统饼图更易读,因为视觉权重在外弧长度而非角度。
import matplotlib.pyplot as plt
labels = ["A", "B", "C"]
sizes = [40, 35, 25]
wedges, texts = plt.pie(sizes, labels=labels,
wedgeprops=dict(width=0.4, edgecolor="w"))
plt.title("Donut Chart")
# add center text
plt.text(0, 0, "Total\n100", ha="center", va="center", fontsize=14)
plt.show()百分比与起始角
autopct 接受格式字符串('%1.1f%%'、'%.0f%%')或返回字符串的可调用函数,使其能显示绝对值+百分比。counterclock=False 使扇形按顺时针排列;startangle=90 让第一片从顶部开始(更符合直觉的'12 点钟方向')。pctdistance 和 labeldistance 控制百分比/标签文字距中心的相对位置(0-1)。
import matplotlib.pyplot as plt
labels = ["North", "South", "East", "West"]
sizes = [32, 24, 28, 16]
colors = ["#4C72B0", "#DD8452", "#55A868", "#C44E52"]
plt.pie(sizes, labels=labels, colors=colors,
autopct=lambda p: f"{p:.1f}%\n({p*sum(sizes)/100:.0f})",
startangle=90, counterclock=False,
pctdistance=0.75)
plt.show()嵌套饼图(同心)
在同一 ax 上调用 pie 两次,通过 radius= 和 width= 参数分离内外环——内环小半径、外环大半径。这是展示层级分类(如大类-子类)的紧凑方式。确保两个数据集的扇形对齐(相同 startangle/counterclock),或用显式 wedgeprops 控制每环的边缘宽度。
import matplotlib.pyplot as plt
# outer ring: regions, inner ring: sub-categories
outer = [40, 30, 30]
inner = [20, 20, 15, 15, 25, 5]
outer_labels = ["A", "B", "C"]
inner_labels = ["A1", "A2", "B1", "B2", "C1", "C2"]
plt.pie(outer, labels=outer_labels, radius=1.0,
wedgeprops=dict(width=0.3, edgecolor="w"))
plt.pie(inner, labels=inner_labels, radius=0.7,
wedgeprops=dict(width=0.3, edgecolor="w"))
plt.title("Nested Pie")
plt.show()子图与布局
plt.subplot
plt.subplot(nrows, ncols, index) 创建或选中一个虚拟网格中的第 index 个子图(1-based)。该 API 来自 MATLAB,适合简单的等分网格。返回 Axes 对象。对于复杂或不等大小的布局,使用 GridSpec 或 subplots/mosaic。注意 index 从 1 开始(不是 0)——这是常见的错误来源。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 5, 50)
# subplot(nrows, ncols, index) -- 1-indexed!
plt.subplot(2, 2, 1)
plt.plot(x, x)
plt.subplot(2, 2, 2)
plt.plot(x, x**2)
plt.subplot(2, 2, 3)
plt.plot(x, x**3)
plt.subplot(2, 2, 4)
plt.plot(x, np.sin(x))
plt.tight_layout()
plt.show()plt.subplots
plt.subplots(n, m) 一次性创建 Figure 和 Axes 数组——这是现代推荐方式。返回 (fig, axs),其中 axs 是 2-D 数组(当 n,m>1)、1-D 数组(当其中之一为 1)或单个 Axes(当都为 1)。squeeze=False 强制始终返回 2-D 数组,简化遍历代码。axs.flat 提供一个 1-D 迭代器。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
# one figure, 2x2 grid of Axes, shared x and y
fig, axes = plt.subplots(2, 2, figsize=(8, 6),
sharex=True, sharey=True)
axes[0, 0].plot(x, np.sin(x)); axes[0, 0].set_title("sin")
axes[0, 1].plot(x, np.cos(x)); axes[0, 1].set_title("cos")
axes[1, 0].plot(x, np.tan(x)); axes[1, 0].set_title("tan")
axes[1, 1].plot(x, -np.sin(x)); axes[1, 1].set_title("-sin")
fig.suptitle("Trig Family")
plt.tight_layout()
plt.show()GridSpec
GridSpec 让子图跨越多行/多列,实现不等大小布局。fig.add_subplot(gs[0, :]) 创建一个跨越所有列的子图;gs[1, :-1] 跨越除最后一列外的所有列。width_ratios/height_ratios 控制列/行的相对大小。plt.subplot_mosaic 是更新的便利 API,用字符矩阵描述布局(每个唯一字符=一个子图)。
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(3, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, :]) # full top row
ax2 = fig.add_subplot(gs[1, :2]) # middle, left 2 cols
ax3 = fig.add_subplot(gs[1:, 2]) # right, spans 2 rows
ax4 = fig.add_subplot(gs[2, 0:2]) # bottom-left
ax1.set_title("wide top")
ax3.set_title("tall right")
plt.tight_layout()
plt.show()共享坐标轴
sharex/sharey='all' 链接所有子图的缩放/平移——在一个上缩放会同步所有其他。'col'/'row' 仅在列/行内共享。共享时内部刻度标签会自动隐藏以减少 杂乱。在比较多个数据集时这至关重要,否则不同子图的尺度可能误导读者。sharex=True 也确保相同 xlim,使柱图等视觉上可比。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
ax1.plot(x, np.sin(x))
ax2.plot(x, np.cos(x))
# zooming on one now zooms both
ax1.set_xlim(0, 5)
# decouple later if needed
# ax2.get_shared_x_axes().remove(ax2)
fig.suptitle("Shared x-axis")
plt.show()紧凑布局与约束布局
tight_layout() 自动调整子图参数以避免标签/标题重叠——简单可靠。constrained_layout(在 subplots 中传入 constrained_layout=True 或 rcParam)是更新的替代方案,能正确处理颜色条、图例和 suptitle,且在多次 add_axes 调用后仍能更新。优先使用 constrained_layout 而非手动 subplots_adjust。
import matplotlib.pyplot as plt
# tight_layout: simple, adjusts subplot spacing
fig, axes = plt.subplots(2, 2)
for ax in axes.flat:
ax.set_xlabel("x label")
ax.set_ylabel("y label")
ax.set_title("a title")
fig.suptitle("tight_layout")
plt.tight_layout()
# leave room for suptitle
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
# constrained_layout: recomputes on every draw (more robust)
fig, axes = plt.subplots(2, 2, layout="constrained")
fig.suptitle("constrained_layout")
plt.show()图例与标注
基础图例
ax.legend() 收集所有带 label= 的艺术家并显示图例。默认位置 loc='best' 会自动找最少重叠的位置。显式 loc 字符串('upper right'、'lower left' 等)或 2-元组坐标 (x, y) 可固定位置。ncol= 让图例分多列显示,适合多个条目。frameon=False 移除边框,使图例更轻量。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 1, 30)
plt.plot(x, x, label="linear")
plt.plot(x, x**2, label="quadratic")
plt.plot(x, x**3, label="cubic")
plt.legend()
plt.show()
# legend outside the axes
plt.figure()
plt.plot(x, x, label="linear")
plt.plot(x, x**2, label="quadratic")
plt.legend(loc="upper left", bbox_to_anchor=(1, 1))
plt.tight_layout()
plt.show()图例位置与列数
loc 接受字符串('upper left' 等)或位置代码(0-10),loc='best'(0)自动 选择。bbox_to_anchor=(x, y) 配合 loc= 将图例锚定到任意点(坐标在 axes/figure 分数中)。ncol= 在水平方向上分多列显示条目。framealpha、edgecolor、facecolor 控制图例框的外观。mode='expand' 让图例水平拉伸填满 bbox。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 1, 30)
for i in range(1, 6):
plt.plot(x, x**i, label=f"x^{i}")
plt.legend(loc="upper center", ncol=3, fontsize=9,
frameon=True, framealpha=0.9,
title="Powers", title_fontsize=10)
plt.title("Custom Legend")
plt.show()标注点
ax.annotate(text, xy=(x, y)) 在数据坐标 (x, y) 处放置文本。xytext= 指定文本位置(默认在 xy 处),textcoords= 解释 xytext 的坐标系('offset points' 是常用选择,让标签偏移而不被点遮挡)。arrowprops= 字典(如 dict(arrowstyle='->'))画一条从 xytext 到 xy 的箭头。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
# mark and label the maximum
idx = np.argmax(y)
plt.annotate(f"max = {y[idx]:.2f}",
xy=(x[idx], y[idx]), # point to annotate
xytext=(x[idx]-1, 0.5), # text position
arrowprops=dict(arrowstyle="->"))
plt.show()带箭头的标注
arrowprops=dict(arrowstyle='->', ...) 是标注调用的核心。arrowstyle 接受简写字符串('->'、'-|>'、'<->')或 ArrowStyle 对象。connectionstyle='arc3,rad=0.3' 使箭头弯曲;shrinkA/shrinkB 在两端留空隙,使箭头不直接触碰文字或点。xycoords 控制目标点坐标系(默认 'data')。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
plt.plot(x, x**3 - 3*x)
plt.annotate("local min", xy=(1, -2), xytext=(2, -10),
arrowprops=dict(arrowstyle="->", color="red",
lw=2, connectionstyle="arc3,rad=0.3"))
plt.annotate("local max", xy=(-1, 2), xytext=(-3, 8),
arrowprops=dict(arrowstyle="-|>", color="blue",
connectionstyle="angle3"))
plt.show()自定义图例句柄
ax.legend(handles, labels) 接受显式艺术家列表而非自动收集——用于精确控制图例条目或为图中未出现的'代理'艺术家创建图例(如展示用 Line2D([], [], color='red', label='trend line') 表示的分类)。这也可重新排序图例或合并多个艺术家的标签。
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.patches import Patch
plt.plot([1, 2, 3], [1, 4, 9], "o-", color="tab:blue")
plt.plot([1, 2, 3], [1, 8, 27], "s--", color="tab:orange")
custom = [
Line2D([0], [0], color="tab:blue", marker="o", label="squared"),
Line2D([0], [0], color="tab:orange", marker="s", ls="--", label="cubed"),
Patch(facecolor="gray", label="reference band"),
]
plt.legend(handles=custom)
plt.show()样式、颜色与 rcParams
内置样式
plt.style.use('name') 全局应用一个样式;plt.style.context('name') 在 with 块内临时应用而不影响全局。print(plt.style.available) 列出所有样式。'seaborn-v0_8-*' 系列在 matplotlib 3.6+ 中内置(原 seaborn 样式名);'ggplot'、'bmh'、'fivethirtyeight' 模仿各自的设计美学。dark_background 适合暗色主题演示。
import matplotlib.pyplot as plt
# list all available styles
print(plt.style.available)
# use a style globally
plt.style.use("seaborn-v0_8-whitegrid")
# or as a context manager (temporary)
with plt.style.context("dark_background"):
plt.figure()
plt.plot([1, 2, 3], [1, 4, 9])
plt.title("dark")
plt.show()
plt.plot([1, 2, 3], [9, 4, 1])
plt.title("default again")
plt.show()颜色映射
Colormap 决定数值如何映射到颜色。三类:(1) 顺序(如 viridis、plasma)——单色递进,适合低到高的连续数据;(2) 发散(如 coolwarm、RdBu)——双色中间有中性点,适合围绕中心的数据;(3) 定性(如 Set1、tab10)——离散颜色,无顺序含义。viridis 是 matplotlib 默认且是感知均匀、色盲友好的。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
# sequential, diverging, qualitative
for cmap in ["viridis", "plasma", "coolwarm", "RdBu", "Set2"]:
plt.scatter(x, y, c=x, cmap=cmap, label=cmap)
plt.colorbar(label=cmap)
plt.title(cmap)
plt.show()自定义颜色循环
rcParams['axes.prop_cycle'] 决定 plot 时自动分配的颜色顺序。用 cycler.cycler(color=[...]) 替换以自定义循环。循环可包含多个属性(如 color + linestyle),使每个新系列获得独特的颜色和线型组合。这比在每个 plot 调用中重复指定 color= 更简洁。
import matplotlib.pyplot as plt
from cycler import cycler
# set the default color cycle for new axes
plt.rcParams["axes.prop_cycle"] = cycler(
color=["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00"])
for i in range(1, 6):
plt.plot([0, 1, 2], [i]*3, label=f"line {i}", lw=4)
plt.legend()
plt.title("Custom Cycle")
plt.show()rcParams
rcParams 是全局配置字典,控制所有默认值——图形大小、DPI、字体大小、线宽、颜色循环等。在脚本顶部设置一次以统一样式。plt.rc('figure', figsize=(8,6)) 或 rcParams['figure.figsize'] = [8, 6] 是等价的。用 mpl.rcParams.update({...}) 一次更新多个值。
import matplotlib.pyplot as plt
import matplotlib as mpl
# read / set individual parameters
mpl.rcParams["figure.figsize"] = (8, 4)
mpl.rcParams["figure.dpi"] = 100
mpl.rcParams["font.size"] = 12
mpl.rcParams["axes.grid"] = True
mpl.rcParams["axes.grid.which"] = "both"
mpl.rcParams["savefig.bbox"] = "tight"
# update many at once
plt.rcParams.update({
"axes.titlesize": "large",
"axes.labelsize": "medium",
"lines.linewidth": 2,
})
plt.plot([1, 2, 3])
plt.title("Configured Defaults")
plt.show()颜色格式
matplotlib 接受的颜色规范:单字符('rgbcmykw')、CSS4 名称('crimson')、十六进制('#FF5733' 或简写 '#F53')、RGB/RGBA 元组(0-1 或 0-255,需在 0-1)、灰度字符串('0.5')、CN 循环引用('C0'-'C9')、xkcd 名称('xkcd:sky blue')、tab: 名称('tab:blue')及 Tableau 颜色。统一用十六进制或命名颜色可保证跨样式一致性。
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
# all named colors
print(list(mcolors.CSS4_COLORS)[:5])
# convert between formats
print(mcolors.to_hex((0.1, 0.2, 0.5))) # #1a3380
print(mcolors.to_rgb("#ff8800")) # (1.0, 0.533, 0.0)
# make a custom colormap from a list of colors
cmap = mcolors.LinearSegmentedColormap.from_list(
"rg", ["red", "yellow", "green"])
import numpy as np
plt.imshow(np.linspace(0, 1, 256).reshape(1, -1),
cmap=cmap, aspect="auto")
plt.title("Custom Colormap")
plt.show()坐标轴设置
范围 (xlim / ylim)
set_xlim/set_ylim 强制坐标轴范围;不调用时 matplotlib 自动从数据推导。传入 None(如 set_xlim(0, None))让一端自动。set_xbound 是带优先级的替代。在子图比较时固定范围至关重要,否则不同子图可能显示不同尺度造成误导。invert_xaxis()/invert_yaxis() 反转方向(如 y 轴向下增长)。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x))
# set explicit limits
plt.xlim(2, 8)
plt.ylim(-1.5, 1.5)
# or autoscale with margin
# plt.margins(x=0.05, y=0.1)
# query current limits
print(plt.xlim()) # (2.0, 8.0)
plt.show()刻度
set_xticks(locations) 设置刻度位置;可选 set_xticklabels(labels) 用自定义文字替换数字标签。在 matplotlib 3.5+ 中两者必须分开调用。对于分类数据,set_xticks(range(N)) 配合 set_xticklabels(names) 是标准做法。rotation= 旋转标签以避免长名称重叠。MaxNLocator 自动限制刻度数量以避免拥挤。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
plt.plot(x, np.sin(x))
# set tick positions
plt.xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
# set positions AND labels
plt.xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi],
["0", "pi/2", "pi", "3pi/2", "2pi"])
# turn off ticks
# plt.xticks([])
plt.show()刻度格式化
set_xticklabels 接受任意字符串列表,完全控制刻度文字(如将 0/1 替换为 'cat'/'dog')。对于数字格式化,FuncFormatter 接受一个 (x, pos) -> str 函数,或 StrMethodFormatter 用 '{x:.2f}' 风格模板。ScalarFormatter 控制 sci_notation;PercentFormatter 把 0-1 显示为 0-100%。Formatter 作用于主刻度,set_minor_formatter 设置次刻度。
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, FormatStrFormatter, FuncFormatter
x = np.linspace(0, 5, 100)
plt.plot(x, x**2)
ax = plt.gca()
ax.xaxis.set_major_locator(MultipleLocator(1))
ax.xaxis.set_minor_locator(MultipleLocator(0.25))
ax.yaxis.set_major_formatter(FormatStrFormatter("%.0f"))
# format with a function
ax.yaxis.set_major_formatter(
FuncFormatter(lambda v, p: f"{v/1000:.1f}k"))
plt.show()对数刻度
set_xscale('log') 切换到对数刻度——数据跨数量级时(如 1 到 100000)必备。symlog 是对称版本,可处理 0 和负数(在 0 附近用线性,远离 0 用对数)。LogLocator 自动选择 10 的幂次刻度位置;LogFormatter 用科学记数法显示。注意:对数轴下 set_xlim 必须用正值,且数据不能含 0 或负数。
import matplotlib.pyplot as plt
import numpy as np
x = np.logspace(0, 4, 50) # 10^0 .. 10^4
plt.plot(x, x**2)
# log both axes
plt.xscale("log")
plt.yscale("log")
# symlog: log scale that handles negative/zero values
# plt.yscale("symlog", linthresh=1)
plt.title("Log-Log Plot")
plt.grid(True, which="both", ls="--", alpha=0.5)
plt.show()宽高比与边框
set_aspect('equal') 让 x、y 单位长度在屏幕上相等(对圆显示为圆而非椭圆)。set_aspect('equal', adjustable='box') 调整轴框,adjustable='datalim' 调整数据范围。spines 是四条边框;set_visible(False) 隐藏某条边(常隐藏 top/right 以简化美学)。移到中心:spines['left'].set_position(('data', 0))。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
theta = np.linspace(0, 2*np.pi, 100)
ax.plot(np.cos(theta), np.sin(theta))
# equal data units on x and y (a true circle)
ax.set_aspect("equal")
# hide the top and right spines
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
# move the remaining spines to the center for a cross-hair
# ax.spines["left"].set_position(("data", 0))
# ax.spines["bottom"].set_position(("data", 0))
plt.show()文本与数学表达式
坐标轴内文本
ax.text(x, y, s) 在数据坐标 (x, y) 处放置字符串 s。transform=ax.transAxes 改为坐标轴分数(0-1,左下为原点),适合与数据范围无关的标签(如右上角标注)。transform=fig.transFigure 是图形分数坐标。返回 Text 对象,可后续修改 set_text/set_position/set_color 等。
import matplotlib.pyplot as plt
plt.plot([0, 1], [0, 1])
# ax.text(x, y, s) -- x, y in data coords
plt.text(0.5, 0.5, "center of plot", ha="center", va="center",
fontsize=14, color="red", rotation=30)
# align to axes fraction instead of data coords
plt.text(0.02, 0.98, "top-left", transform=plt.gca().transAxes,
ha="left", va="top", bbox=dict(boxstyle="round", fc="yellow"))
plt.show()suptitle 与 figtext
fig.suptitle 在整个图形顶部添加一个总标题(不同于 ax.set_title 是单个坐标轴标题)。fig.text(x, y, s) 在图形分数坐标放置任意文本。在多子图图形中用 suptitle 描述整体主题,用各 ax.set_title 描述子图。tight_layout() 不会为 suptitle 留空间——用 constrained_layout 或 subplots_adjust(top=0.9)。
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2)
axes[0].plot([1, 2, 3])
axes[1].plot([3, 2, 1])
# figure-level title (above all axes)
fig.suptitle("Main Title", fontsize=16, fontweight="bold")
# arbitrary figure-coordinate text
fig.text(0.5, 0.01, "figure footer text", ha="center", fontsize=9)
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
plt.show()LaTeX 数学 (mathtext)
在 $...$ 之间的文本用 mathtext(内置 LaTeX 子集)渲染——无需安装 LaTeX。支持 \frac、\sum、\int、希腊字母、上下标、矩阵等。$$ 是显示数学(居中独立行)。对于完整 LaTeX 排版,设置 rcParams['text.usetex']=True(需要系统装 LaTeX)——慢但渲染质量更高。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 2*np.pi, 100)
plt.plot(x, np.sin(x))
# mathtext: enclose LaTeX in dollar signs
plt.title(r"$\sin(x)$ vs $x$")
plt.xlabel(r"$x$ (radians)")
plt.ylabel(r"$\sin(x)$")
# fractions, sums, greek letters
plt.text(2, 0.5, r"$\frac{a}{b} + \sum_{i=1}^{n} x_i^2$")
plt.text(2, -0.5, r"$\alpha, \beta, \gamma, \pi, \infty$")
plt.show()文本属性
每个文本对象接受丰富属性:fontsize、fontweight('bold')、fontstyle('italic')、family('serif'/'sans-serif'/'monospace')、color 以及背景框 bbox 字典。文本对象会被返回,所以可在之后修改(在动画和交互式更新中很有用)。如 t.set_fontsize(24)、t.set_color('crimson')。
import matplotlib.pyplot as plt
t = plt.text(0.5, 0.5, "Styled Text",
fontsize=18, fontweight="bold",
fontstyle="italic", family="serif",
color="darkblue",
bbox=dict(boxstyle="round,pad=0.5",
facecolor="lightyellow", edgecolor="black"))
# animate or update properties later
t.set_fontsize(24)
t.set_color("crimson")
plt.show()标注 (textcoords)
annotate 的 textcoords 控制 xytext 如何解释:'data'(默认,数据单位)、'offset points'(相对于 xy 的点偏移——适合把标签从点上挪开)、'axes fraction'(在坐标轴内 0-1)、'figure fraction'。混用坐标系让标注在缩放时仍保持可读。xycoords 控制目标点 xy 的坐标系(默认 'data')。
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
# xy in data coords, xytext in points OFFSET from xy
plt.annotate("offset text", xy=(2, 4),
xytext=(15, 15), textcoords="offset points",
arrowprops=dict(arrowstyle="->"))
# xytext in axes fraction
plt.annotate("axes corner", xy=(2, 4),
xytext=(0.8, 0.8), textcoords="axes fraction",
arrowprops=dict(arrowstyle="-|>"))
plt.show()保存图形
savefig 基础
savefig 把当前图形写入磁盘。格式从扩展名推断(.png/.jpg/.svg/.pdf/.eps)或用 format= 显式指定。向量格式(SVG、PDF、EPS)可无损缩放;PNG/JPG 是光栅,打印需要高 dpi。必须在 plt.show() 之前调用 savefig,否则图形已被关闭/清空。
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [4, 5, 2])
# save BEFORE plt.show() -- show() clears the figure
plt.savefig("plot.png")
plt.savefig("plot.pdf")
plt.show()dpi 与 bbox_inches
dpi 控制光栅分辨率(默认 100;打印用 300)。bbox_inches='tight' 裁剪周围空白以避免图例/标签被切。pad_inches 加少量边距;facecolor 设置保存的背景色。transparent=True 使背景透明(产生带 alpha 通道的 PNG)。这些是控制输出尺寸和质量的关键参数。
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
# raster formats (pixels)
plt.savefig("plot.png") # lossless, default
plt.savefig("plot.jpg", quality=95)
plt.savefig("plot.tiff", dpi=200)
# vector formats (scale without pixelation)
plt.savefig("plot.pdf") # best for publications
plt.savefig("plot.svg") # editable in Inkscape/Illustrator
# explicit format override
plt.savefig("plot.dat", format="png")透明背景
transparent=True 把图形补丁 alpha 设为 0,产生带 alpha 通道的 PNG。在非白色背景的幻灯片或网页上叠加图形时很有用。可与 axes facecolor 组合,只让绘图区有颜色而图形背景透明。fig.patch.set_alpha(0.0) 是手动等价写法。
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot([1, 2, 3], [1, 4, 9])
# dpi controls pixel density: width_px = figsize[0] * dpi
plt.savefig("low.png", dpi=72) # 432 x 288 px
plt.savefig("high.png", dpi=300) # 1800 x 1200 px
# set a global default DPI
plt.rcParams["savefig.dpi"] = 300
plt.savefig("global.png")元数据与质量
JPEG 接受 quality(0-100;越高文件越大但越清晰)。PNG 支持 optimize=True(更小文件)和 metadata 字典(Author/Title/Description/Software/CreationDate)。PDF 元数据键包括 'Title'、'Author'、'Subject'、'Keywords'。progressive=True 生成渐进式 JPEG,适合网页逐步加载。
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
plt.title("With Long Title That Might Be Cut Off")
# tight bbox trims whitespace and keeps labels inside
plt.savefig("tight.png", bbox_inches="tight", pad_inches=0.1)
# trim even more aggressively
plt.savefig("tighter.png", bbox_inches="tight", pad_inches=0)
# preview the tight bounding box
# bbox = plt.savefig("x.png", bbox_inches="tight") # returns a Bbox保存所有图形
在循环中生成大量图形时,保存后务必 close(fig) 以避免内存泄漏(图形会留在 pyplot 状态中直到关闭)。get_fignums() 返回所有当前打开图形的编号,如需遍历已有图形。也可用 fig.savefig() 而非 plt.savefig() 以明确指定哪个图形。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
ax.set_facecolor("#f0f0f0")
# transparent background (alpha channel)
plt.savefig("transparent.png", transparent=True)
# explicit figure face color
plt.savefig("colored.png", facecolor="lightblue", edgecolor="none")
# control which elements are saved
plt.savefig("full.png", facecolor=fig.get_facecolor())3D 绘图 (mplot3d)
3D 坐标轴设置
导入 mpl_toolkits.mplot3d.Axes3D 注册 '3d' 投影。然后向 add_subplot 或 plt.axes 传入 projection='3d'。生成的 Axes3D 提供 plot3D、scatter3D、plot_surface、plot_wireframe、contour3D 等方法。用 ax.set_xlabel/ylabel/zlabel 设置三轴标签。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
# add a 3D axes via projection
ax = fig.add_subplot(projection="3d")
# or from subplots
# fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("3D Axes")
plt.show()3D 折线与散点
ax.plot(x, y, z) 绘制 3D 折线;ax.scatter(x, y, z) 绘制标记(c= 把颜色映射到值,如深度)。默认视角可用 ax.view_init(elev=30, azim=45) 改变,其中 elev 是仰角(度,从 xy 平面向上),azim 是方位角(绕 z 轴旋转)。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
n = 200
x = rng.normal(0, 1, n)
y = rng.normal(0, 1, n)
z = rng.normal(0, 1, n)
c = np.sqrt(x**2 + y**2 + z**2)
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
sc = ax.scatter(x, y, z, c=c, cmap="viridis")
fig.colorbar(sc, label="distance from origin")
ax.set_title("3D Scatter")
plt.show()曲面图
plot_surface 需要 meshgrid 生成的 2-D 数组。cmap 按 Z 着色;edgecolor='none' 移除默认的黑色线框。alpha<1 使曲面半透明,可看见背面。fig.colorbar 添加颜色标尺。rstride/cstride 控制行/列步长(降采样以提升性能)。
import matplotlib.pyplot as plt
import numpy as np
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)
Z = np.sin(R)
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
surf = ax.plot_surface(X, Y, Z, cmap="coolwarm",
rstride=1, cstride=1,
linewidth=0, antialiased=True)
fig.colorbar(surf, shrink=0.5, aspect=10)
ax.set_title("3D Surface")
plt.show()线框图与 contour3D
plot_wireframe 只画网格边(比曲面更轻量)。contour3D 把等高线切片投影到 3D 空间。rstride/cstride 控制行/列步长(降采样以提升性能)。对于大型网格降采样很关键,否则线框会过于密集无法辨认。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 30)
y = np.linspace(-3, 3, 30)
X, Y = np.meshgrid(x, y)
Z = X * np.exp(-X**2 - Y**2)
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
ax.plot_wireframe(X, Y, Z, color="black", rstride=1, cstride=1)
ax.set_title("Wireframe")
# 3D contour (filled) projected at the bottom
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
ax.contourf(X, Y, Z, zdir="z", offset=-0.5, cmap="viridis")
ax.set_title("3D Contour")
plt.show()3D 柱状图
bar3d 接受柱角坐标(x, y, z=底部)加上柱尺寸(dx, dy, dz=高度)。shade=True 根据光照方向添加伪阴影。传入颜色列表可单独着色每个柱。适合在 x-y 网格上展示三维数据(如地理位置上的值)。
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
x = np.arange(3)
y = np.arange(3)
X, Y = np.meshgrid(x, y)
X, Y = X.ravel(), Y.ravel()
Z = np.zeros_like(X)
dz = np.array([1, 2, 3, 2, 3, 1, 3, 1, 2])
ax.bar3d(X, Y, Z, dx=0.6, dy=0.6, dz=dz,
shade=True, color="tab:orange")
ax.set_title("3D Bar Chart")
plt.show()等高线图
基础等高线
contour 绘制 Z 在所选 levels 处的等值线。clabel 在每条等值线上内联标注数值。levels=N 自动选 N 个等值线;levels=[v1, v2, ...] 用显式值。colors 用单一颜色覆盖颜色映射。需要 meshgrid 生成的 2-D X、Y、Z 数组。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
# line contours
cs = plt.contour(X, Y, Z, levels=15, colors="black", linewidths=0.8)
plt.clabel(cs, inline=True, fontsize=8)
plt.title("Contour Lines")
plt.colorbar(cs)
plt.show()填充等高线
contourf 用颜色填充等值线之间的区域。与 contour(线)组合可同时显示区域和等值曲线。extend='both' 让颜色条延伸到数据范围之外,用 colors.set_under/over 设置超界颜色。这是展示二维标量场(如温度、压力)的标准方法。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2
cf = plt.contourf(X, Y, Z, levels=20, cmap="viridis")
plt.colorbar(cf, label="Z")
plt.title("Filled Contour")
plt.xlabel("X")
plt.ylabel("Y")
plt.show()对数等高线层级
对于跨数量级的数据,用 np.logspace 生成 levels 并用 norm='log'(或 matplotlib.colors.LogNorm())让颜色按对数缩放。配合 xscale('log')/yscale('log') 实现对数-对数等高线图。这在频谱、能量分布等数据中很常见。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = X * np.exp(-X**2 - Y**2)
cs = plt.contour(X, Y, Z, 10, colors="black")
plt.clabel(cs, inline=True, fontsize=9, fmt="%.2f")
# label only specific levels
# plt.clabel(cs, levels=[-0.1, 0, 0.1])
plt.title("Labeled Contours")
plt.show()自定义层级等高线
向 levels 传入值列表可在特定 Z 值处绘制等值线。fmt 控制标签格式('%.1f'、'%.2g' 或函数)。颜色列表(与 levels 长度相同)自定义每条线——适合突出某个阈值(如安全限值)。这在工程图中标定关键等值线很有用。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 5, 100)
y = np.linspace(0, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
cf = plt.contourf(X, Y, Z, cmap="RdBu")
# basic colorbar
cb = plt.colorbar(cf)
cb.set_label("Z value")
cb.set_ticks([-2, -1, 0, 1, 2])
# place colorbar with specific size and padding
# cb = plt.colorbar(cf, fraction=0.046, pad=0.04)
plt.title("Colorbar Example")
plt.show()等高线标签与影线
hatches 在 contourf 区域上添加纹理图案('/'、'\\'、'+'、'-'、'x'、'o'、'.')——在黑白打印中颜色不可见时 invaluable。传入列表(每个层级带一个)或单字符串用于全部。学术论文中常用影线区分区域。
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
# scattered (x, y, z) samples
rng = np.random.default_rng(0)
pts = rng.uniform(-2, 2, (200, 2))
z = np.sin(pts[:,0]) * np.cos(pts[:,1])
# build a regular grid
grid_x, grid_y = np.mgrid[-2:2:100j, -2:2:100j]
# interpolate scattered data onto the grid
grid_z = griddata(pts, z, (grid_x, grid_y), method="cubic")
plt.contourf(grid_x, grid_y, grid_z, levels=20, cmap="plasma")
plt.scatter(pts[:,0], pts[:,1], c="white", s=5, alpha=0.5)
plt.colorbar(label="z")
plt.title("Scattered -> Grid -> Contour")
plt.show()图像显示 (imshow)
imshow 基础
imshow 把 2-D 数组显示为图像/热力图。默认原点(第 0 行)在顶部,行向下排列。cmap 设置颜色映射;interpolation='nearest' 得到清晰像素,'bilinear' 得到平滑渐变。colorbar 添加值图例条。
import matplotlib.pyplot as plt
import numpy as np
# a 2D array is shown as a heatmap (color = value)
rng = np.random.default_rng(0)
img = rng.random((10, 10))
plt.imshow(img, cmap="viridis")
plt.colorbar(label="value")
plt.title("imshow of a 2D array")
plt.show()
# a 3D array (H, W, 3 or 4) is shown as an RGB(A) image
rgb = rng.integers(0, 256, (50, 50, 3), dtype=np.uint8)
plt.imshow(rgb)
plt.axis("off")
plt.title("RGB image")
plt.show()图像原点与范围
默认 imshow 显示数组索引;extent=[left, right, bottom, top] 把像素映射到数据坐标,使刻度匹配。origin='lower' 翻转图像以匹配笛卡尔约定(第 0 行在底部)。aspect='auto' 拉伸图像填满坐标轴;'equal' 保持像素宽高比。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 200)
y = np.linspace(-3, 3, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X**2 + Y**2) / (X**2 + Y**2 + 1)
im = plt.imshow(Z, extent=[-3, 3, -3, 3], origin="lower",
cmap="RdBu", aspect="auto")
cb = plt.colorbar(im)
cb.set_label("intensity")
plt.title("imshow with extent")
plt.show()非均匀图像 (pcolormesh)
imshow 要求均匀像素。对于非均匀网格用 pcolormesh(推荐)或 pcolor,它们接受形状为 (n+1,) 或 (n, n+1)/(n+1, n) 的 x/y 边数组。shading='auto' 根据形状选 'flat' 或 'gouraud';'nearest'/'flat' 着色单元,'gouraud' 插值。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(1)
small = rng.random((5, 5))
methods = ["none", "bilinear", "bicubic", "nearest"]
fig, axes = plt.subplots(1, 4, figsize=(12, 3))
for ax, m in zip(axes, methods):
ax.imshow(small, interpolation=m, cmap="magma")
ax.set_title(m)
ax.axis("off")
plt.tight_layout()
plt.show()加载并显示图像
mpimg.imread 把 PNG/JPG 读入 numpy 数组(float 0-1 或 uint8)。RGB 图像直接 imshow(img) 即可——不要传 cmap。axis('off') 隐藏刻度和边框,得到干净的照片展示。缩略图网格可在 subplots 中循环调用 imshow。
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LogNorm, TwoSlopeNorm
rng = np.random.default_rng(2)
Z = rng.random((50, 50)) * 1000 + 1
# clamp the colormap range
plt.imshow(Z, vmin=100, vmax=500, cmap="viridis")
plt.colorbar()
plt.title("clipped range")
plt.show()
# log-scaled colors
plt.imshow(Z, norm=LogNorm(vmin=1, vmax=1001), cmap="plasma")
plt.colorbar()
plt.title("log scale")
plt.show()
# diverging norm centered on a midpoint
# norm = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=1)带颜色条刻度的图像
向 colorbar 传 ticks= 设置显式刻度位置,然后用 set_yticklabels 设置自定义文字标签。imshow 返回的可映射对象(mappable)是 colorbar 读取以确定颜色映射和值范围的对象;imshow 上的 vmin/vmax 固定尺度(适合跨多个图比较)。
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# read an image file into a numpy array
img = mpimg.imread("photo.png") # shape (H, W, 3) or (H, W, 4)
print(img.shape, img.dtype)
plt.imshow(img)
plt.axis("off")
plt.show()
# save the (possibly modified) array back to a file
# plt.imsave("out.png", img)
# drop the alpha channel if present
if img.shape[-1] == 4:
img = img[..., :3]极坐标图
极坐标轴设置
传入 projection='polar'(或用 plt.polar)创建极坐标轴,其中 x 是弧度角度、y 是半径。set_theta_zero_location('N') 把 0 放在顶部;set_theta_direction(-1) 使 theta 顺时针。set_rlim 控制半径范围。
import matplotlib.pyplot as plt
import numpy as np
# create a polar axes via projection
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
# or from subplots
# fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
theta = np.linspace(0, 2*np.pi, 100)
ax.plot(theta, np.sin(2*theta))
plt.show()极坐标散点与柱
在极坐标轴中,ax.bar 的 width 是角度宽度(弧度),bottom 是内半径——非常适合玫瑰图。ax.scatter 用循环颜色映射(如 hsv/twilight)按角度着色,使颜色在 2π 处平滑环绕。
import matplotlib.pyplot as plt
import numpy as np
theta = np.linspace(0, 2*np.pi, 200)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.plot(theta, 1 + np.cos(theta), label="cardioid")
ax.plot(theta, np.abs(np.sin(2*theta)), label="rose")
ax.set_rmax(2.0)
ax.set_rticks([0.5, 1.0, 1.5])
ax.set_thetagrids([0, 90, 180, 270])
ax.legend(loc="upper right")
plt.show()雷达图 / 蜘蛛图
雷达图是带分类角度标签的极坐标图。要闭合多边形,把第一个值/角度附加到数组末尾。set_xticks 把类别标签放在固定角度;set_ylim 控制径向尺度。常用于多维度能力对比(如产品评分)。
import matplotlib.pyplot as plt
import numpy as np
labels = ["Speed", "Power", "Range", "Comfort", "Price"]
values = [8, 7, 6, 5, 9]
N = len(labels)
# close the loop
angles = np.linspace(0, 2*np.pi, N, endpoint=False).tolist()
values += values[:1]
angles += angles[:1]
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.plot(angles, values, "o-")
ax.fill(angles, values, alpha=0.25)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels)
ax.set_title("Radar Chart")
plt.show()极坐标网格自定义
set_theta_zero_location('N'/'E'/'S'/'W') 设置 0 弧度指向;set_theta_direction(-1) 反转方向(顺时针,如罗盘)。set_rgrids 控制径向刻度位置/标签及其角度位置;set_thetagrids 设置角度刻度。
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
N = 12
theta = np.linspace(0, 2*np.pi, N, endpoint=False)
widths = 2*np.pi / N
radii = rng.uniform(1, 5, N)
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
bars = ax.bar(theta, radii, width=widths, bottom=0,
edgecolor="black")
# color bars by radius
for r, bar in zip(radii, bars):
bar.set_facecolor(plt.cm.viridis(r / radii.max()))
ax.set_title("Rose Diagram")
plt.show()极坐标等高线
当 X 是 theta(弧度)、Y 是 r 时,contourf 在极坐标轴中工作。网格必须是 2-D;meshgrid(theta, r) 是自然选择。适合可视化角度对称场(如天线辐射方向图)。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(subplot_kw={"projection": "polar"})
ax.plot(np.linspace(0, 2*np.pi, 100), np.linspace(0, 1, 100))
# rotate 0 degrees to the top, go clockwise
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
# radial limits and ticks
ax.set_rlim(0, 1.2)
ax.set_rticks([0.25, 0.5, 0.75, 1.0])
ax.set_rlabel_position(135) # move radial labels out of the way
# label directions in degrees
ax.set_thetagrids([0, 90, 180, 270], labels=["E","N","W","S"])
plt.show()双轴与次级刻度
twinx(双 y 轴)
ax.twinx() 创建共享 x 轴、在右侧有独立 y 轴的新坐标轴。把每条线的标签/刻度颜色匹配,让读者知道哪个轴属于哪条系列。twiny() 对 x 轴做同样的事(两个 x 轴,共享 y)。常用于在同一图上比较量级差异大的两个系列(如温度与销量)。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, ax1 = plt.subplots()
ax1.plot(x, np.sin(x), "b-")
ax1.set_xlabel("x")
ax1.set_ylabel("sin(x)", color="b")
ax1.tick_params(axis="y", labelcolor="b")
# a second axes sharing the same x, with an independent y
ax2 = ax1.twinx()
ax2.plot(x, x*10, "r-")
ax2.set_ylabel("10*x", color="r")
ax2.tick_params(axis="y", labelcolor="r")
plt.title("twinx: two y-scales")
plt.show()twiny(双 x 轴)
ax.twiny() 在坐标轴顶部创建第二个 x 轴(共享 y)。适合在同一数据上显示两个尺度(如秒与频率、摄氏与华氏)。在 twin 上手动 set_xticks/labels 显示次级尺度。
import matplotlib.pyplot as plt
import numpy as np
y = np.linspace(0, 10, 50)
fig, ax1 = plt.subplots()
ax1.plot(np.exp(y), y, "g-")
ax1.set_ylabel("y")
ax1.set_xlabel("exp(y)", color="g")
# second axes sharing y, independent x on top
ax2 = ax1.twiny()
ax2.plot(y**2, y, "m-")
ax2.set_xlabel("y^2", color="m")
plt.title("twiny: two x-scales")
plt.show()次级坐标轴变换
secondary_xaxis('top', functions=(f, g)) 添加一个 x 轴,其刻度由对主轴值应用 f 计算,g 作为逆函数。secondary_yaxis('right', ...) 对 y 做同样的事。适合单位转换(摄氏转华氏、米转千米等),无需手动设置两套刻度。
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 5, 100)
temp_c = 20 + 5*np.sin(t) # Celsius
humidity = 60 - 5*t # percent
fig, ax1 = plt.subplots(figsize=(8, 4))
l1, = ax1.plot(t, temp_c, "r-o", label="Temperature (C)")
ax1.set_xlabel("time (s)")
ax1.set_ylabel("Temperature (C)", color="r")
ax1.tick_params(axis="y", labelcolor="r")
ax2 = ax1.twinx()
l2, = ax2.plot(t, humidity, "b-s", label="Humidity (%)")
ax2.set_ylabel("Humidity (%)", color="b")
ax2.tick_params(axis="y", labelcolor="b")
# combine legends from both axes
lines = [l1, l2]
ax1.legend(lines, [l.get_label() for l in lines], loc="upper right")
plt.title("Temperature & Humidity")
plt.show()断轴
当数据跨越大不相同的范围时,用两个堆叠子图(sharex=True)和紧凑的 ylim 值模拟'断轴'。隐藏内部边框,用对角标记(ax.plot 配 transform)表示断裂。这避免了用对数轴扭曲数据,同时仍能紧凑显示两个尺度。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, np.sin(x), color="tab:blue")
ax2.plot(x, np.cos(x), color="tab:orange")
# remove the top spine so the two axes don't double-border
ax1.spines["top"].set_visible(False)
ax2.spines["top"].set_visible(False)
# color the spines to match their axes
ax1.spines["left"].set_color("tab:blue")
ax2.spines["right"].set_color("tab:orange")
plt.title("Clean Twin Axes")
plt.show()子图间共享坐标轴
sharex/sharey='all'(或 True)链接子图间的缩放/平移,使它们保持同步。用 'col' 或 'row' 仅在列/行内共享。内部坐标轴的刻度标签会自动隐藏以减少杂乱。在比较多个数据集时至关重要,否则不同子图可能显示误导性的不同尺度。
import matplotlib.pyplot as plt
import numpy as np
km = np.linspace(0, 100, 50)
mile = km * 0.621371
fig, ax1 = plt.subplots()
ax1.plot(km, np.sin(km/10), "tab:purple")
ax1.set_xlabel("distance")
ax1.set_ylabel("signal", color="tab:purple")
ax2 = ax1.twiny()
ax2.set_xlim(ax1.get_xlim()) # align x limits
# relabel the top ticks in miles
new_ticks = np.array([0, 25, 50, 75, 100])
ax2.set_xticks(new_ticks)
ax2.set_xticklabels([f"{m:.0f}" for m in new_ticks*0.621371])
ax2.set_xlabel("miles")
plt.show()误差棒与填充区域
基础误差棒
errorbar 绘制带垂直(及 水平,用 xerr)误差棒的点。fmt 是绘图格式字符串('o'、's-' 等)。capsize 在棒端添加小水平端帽;ecolor 设置误差棒颜色,独立于线条颜色。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 5, 10)
y = np.exp(-x)
yerr = 0.1 + 0.1*x # error grows with x
plt.errorbar(x, y, yerr=yerr, fmt="o-", color="tab:blue",
ecolor="gray", elinewidth=1.5, capsize=4,
markersize=6, label="exp(-x) +/- err")
plt.legend()
plt.title("Error Bar Plot")
plt.show()非对称误差
向 yerr(或 xerr)传入 2×N 数组指定非对称误差:第 0 行是下界,第 1 行是上界。对称误差传 1-D 数组或标量。配合 fmt='o'(无线)得到干净的误差棒散点。常用于实验数据上下界不对称的情况。
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(5)
y = np.array([2, 3, 5, 4, 6])
# separate lower and upper errors (each a 1-D array)
yerr = [[0.5, 1, 0.8, 0.6, 1.2], # lower
[1.0, 0.8, 1.5, 1.0, 0.7]] # upper
plt.errorbar(x, y, yerr=yerr, fmt="s", color="tab:green",
capsize=5)
plt.title("Asymmetric Error Bars")
plt.show()
# horizontal asymmetric errors work the same way
# xerr = [[...lower...], [...upper...]]fill_between
fill_between 在曲线和基线(默认 0)之间填充。where= 接受布尔数组,只填充部分——适合突出曲线正/负区域。interpolate=True 避免曲线交叉处的间隙。常用于强调某条件下的数据范围。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
std = 0.2
plt.plot(x, y, "b-", label="mean")
# shade +/- one standard deviation
plt.fill_between(x, y - std, y + std, color="blue", alpha=0.2,
label="+/- 1 std")
# shade only where a condition holds
plt.fill_between(x, y, 0, where=(y > 0), color="green", alpha=0.2,
label="y > 0")
plt.legend()
plt.show()fill_between 置信带
fill_between(x, y_lower, y_upper) 在两条曲线之间填充——这是围绕均值曲线绘制置信带的标准做法。配合 plot(x, y_mean) 画中心线。alpha 控制带透明度。在机器学习预测区间、统计置信区间可视化中常用。
import matplotlib.pyplot as plt
import numpy as np
years = np.arange(2010, 2021)
a = np.array([10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 27])
b = np.array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
c = np.array([ 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10])
plt.stackplot(years, a, b, c, labels=["A", "B", "C"],
colors=["#4C72B0", "#55A868", "#C44E52"], alpha=0.8)
plt.legend(loc="upper left")
plt.title("Stacked Area Chart")
plt.xlabel("year")
plt.ylabel("value")
plt.show()stackplot(堆叠面积)
stackplot 把多个 y 系列堆叠在一起,适合展示随时间变化的组成。baseline='zero'(默认)、'sym'(围绕 0 对称)、'wiggle'(最小化加权变化)、'weighted_wiggle'。传入 colors 和 labels 列表。
import matplotlib.pyplot as plt
import numpy as np
# fill a closed polygon defined by its vertices
x = [0, 1, 1, 0, 0]
y = [0, 0, 1, 1, 0]
plt.fill(x, y, color="tab:cyan", alpha=0.5)
# shade under a curve
xs = np.linspace(0, 2*np.pi, 100)
ys = np.sin(xs)
plt.fill(np.r_[xs, xs[::-1]],
np.r_[ys, np.zeros_like(ys)],
color="tab:orange", alpha=0.3)
plt.title("Filled Polygons")
plt.show()Seaborn 集成
设置主题与样式
sns.set_theme 全局配置 matplotlib:style(darkgrid/whitegrid/dark/white/ticks)、context(paper/notebook/talk/poster——缩放字体/元素)、palette(deep/muted/pastel/bright/dark/colorblind)。用 axes_style() 在 with 块内做局部覆盖。
# install seaborn
pip install seaborn
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# Seaborn is built ON matplotlib: any sns plot returns an Axes
# and accepts an ax= argument, so you can mix freely.
sns.set_theme() # apply seaborn's default style
tips = sns.load_dataset("tips")
ax = sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time")
ax.set_title("Tips dataset")
plt.show()统计图
sns.violinplot 按类别显示完整分布(KDE);split=True 把 hue 等级放在小提琴两侧。inner='quartile'/'box'/'point' 控制内部标记。boxplot 是经典五数概括;stripplot/swarmplot 叠加单个点。Seaborn 内置统计聚合让复杂可视化变得简单。
import seaborn as sns
import matplotlib.pyplot as plt
# five built-in themes: darkgrid, whitegrid, dark, white, ticks
sns.set_style("whitegrid")
sns.set_context("notebook") # paper, notebook, talk, poster
# set the color palette
sns.set_palette("Set2")
import numpy as np
for i in range(4):
plt.plot(np.arange(10), np.arange(10)+i)
plt.title("Seaborn-styled")
plt.show()
# remove the top/right spines (despine) for a clean look
# sns.despine()回归图与联合图
regplot 拟合并绘制带 95% 置信区间的线性回归;scatter_kws/line_kws 传递到底层绘图调用。jointplot 创建独立图形,中央散点/六边形/KDE 加边缘直方图——kind='scatter'/'hex'/'kde'/'reg'/'hist'/'resid'。是探索两个变量关系的利器。
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")
# scatter or line, faceted by a categorical variable
g = sns.relplot(data=tips, x="total_bill", y="tip",
hue="smoker", style="time", col="day",
kind="scatter", height=3, aspect=1.2)
g.fig.suptitle("Tips by day", y=1.03)
plt.show()FacetGrid(小倍数图)
FacetGrid 创建按分类列分割的子图网格——这是跨组比较分布的最清晰方式。map_dataframe 把 seaborn/plt 绘图函数应用到每个子集。用 col_wrap 把列换行到多行。set_axis_labels/set_titles 自定义标签和标题模板。
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")
# histogram with an overlaid KDE (density curve)
sns.histplot(data=tips, x="total_bill", bins=20, kde=True,
hue="time", stat="density", common_norm=False)
plt.title("Histogram + KDE")
plt.show()
# standalone KDE
plt.figure()
sns.kdeplot(data=tips, x="total_bill", hue="time", fill=True)
plt.show()pairplot 与 heatmap
pairplot 把每个数值列与其他列两两绘制,按分类 hue 着色——完美用于发现聚类。heatmap 绘制二维矩阵,颜色表示值;annot=True 显示数值,vmin/vmax 固定尺度,square=True 保持单元方形。correlation heatmap 是数据探索的常见起点。
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# correlation matrix
tips = sns.load_dataset("tips")
num = tips.select_dtypes("number").drop(columns=["size"])
corr = num.corr()
sns.heatmap(corr, annot=True, cmap="coolwarm", center=0,
vmin=-1, vmax=1, square=True,
linewidths=0.5, fmt=".2f")
plt.title("Correlation Heatmap")
plt.show()调色板
color_palette('name', n) 返回 RGB 元组列表;as_cmap=True 返回 matplotlib Colormap。顺序(flare、viridis)、发散(vlag、coolwarm)、定性(Set2、deep)——按数据类型选择。palplot 把调色板显示为水平条带,便于预览。
import seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset("iris")
# scatter matrix: every numeric column vs every other
g = sns.pairplot(iris, hue="species", height=2.5)
g.fig.suptitle("Iris pairplot", y=1.01)
plt.show()
# violin plot: box + kernel density on each side
plt.figure()
sns.violinplot(data=iris, x="species", y="sepal_length",
inner="quartile")
plt.show()交互式控件与动画
FuncAnimation 基础
FuncAnimation 每 interval 毫秒调用 update(frame)。update 必须返回已更改艺术家的可迭代对象(blit=True 时高效地只重绘它们)。用 ani.save('out.gif'/'out.mp4', writer='pillow'/'ffmpeg') 保存。frames 可以是 range、列表或生成器。
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import numpy as np
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
x = np.linspace(0, 10, 500)
line, = ax.plot(x, np.sin(x))
# axes for the slider
ax_freq = plt.axes([0.2, 0.1, 0.6, 0.03])
slider = Slider(ax_freq, "freq", 0.1, 5.0, valinit=1.0)
def update(val):
line.set_ydata(np.sin(slider.val * x))
fig.canvas.draw_idle()
slider.on_changed(update)
plt.show()滑块与按钮
用 plt.axes([left, bottom, width, height]) 在图形分数坐标中手动放置 Slider/Button 坐标轴。on_changed(callback) 在滑块移动时触发;调用 fig.canvas.draw_idle() 刷新。Button 用 on_clicked(callback)。总是 subplots_adjust 为控件留出空间。
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import numpy as np
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.2)
(ln,) = ax.plot(np.random.rand(10))
ax_btn = plt.axes([0.7, 0.05, 0.2, 0.075])
btn = Button(ax_btn, "Resample")
def reshuffle(event):
ln.set_ydata(np.random.rand(10))
fig.canvas.draw_idle()
btn.on_clicked(reshuffle)
plt.show()鼠标事件与拾取
mpl_connect 接入 GUI 事件循环。常见事件:'button_press_event'、'motion_notify_event'、'key_press_event'、'pick_event'。在艺术家上设 picker=5(点容差)启用拾取事件;event.ind 给出被拾取的索引。用于实现自定义交互(点击高亮、悬停信息)。
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
import numpy as np
x = np.linspace(0, 5, 200)
l1, = plt.plot(x, np.sin(x), label="sin")
l2, = plt.plot(x, np.cos(x), label="cos")
plt.subplots_adjust(right=0.8)
rax = plt.axes([0.82, 0.4, 0.15, 0.2])
check = CheckButtons(rax, ["sin", "cos"], [True, True])
def toggle(label):
if label == "sin": l1.set_visible(not l1.get_visible())
if label == "cos": l2.set_visible(not l2.get_visible())
plt.draw()
check.on_clicked(toggle)
plt.show()光标标注
mplcursors 为任何艺术家添加交互式悬停/点击标注。cursor(sc) 附加到特定艺术家;hover=True 鼠标悬停时显示工具提示。用 cursors.cursor(sc).connect('add', lambda sel: sel.annotation.set_text(...)) 自定义格式。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
def on_click(event):
if event.inaxes != ax:
return
print(f"clicked at x={event.xdata:.2f} y={event.ydata:.2f}")
def on_move(event):
if event.inaxes == ax:
ax.set_title(f"x={event.xdata:.2f}, y={event.ydata:.2f}")
fig.canvas.draw_idle()
fig.canvas.mpl_connect("button_press_event", on_click)
fig.canvas.mpl_connect("motion_notify_event", on_move)
plt.show()Notebook 交互性
%matplotlib widget(需 ipympl)在 JupyterLab 中启用内联交互式图形。配合 ipywidgets.interact 用滑块/下拉框重新运行函数——函数修改艺术家并调用 draw_idle() 刷新,而无需重建图形。是数据探索的强大组合。
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 200)
line, = ax.plot(x, np.sin(x))
def update(frame):
line.set_ydata(np.sin(x + frame / 10.0))
return line,
ani = animation.FuncAnimation(fig, update, frames=100,
interval=50, blit=True, repeat=True)
# save to a file (requires ffmpeg or pillow installed)
# ani.save("wave.mp4", writer="ffmpeg")
# ani.save("wave.gif", writer="pillow")
plt.show()相关 Matplotlib 代码片段
Copy-paste ready code for common tasks.
Line Plot
Plot lines with markers, colors, and styles.
Bar Chart
Draw vertical, horizontal, and grouped bars.
Scatter Plot
Visualize relationships with size and color encodings.
Subplots
Arrange multiple axes with subplots and GridSpec.
Labels and Legend
Annotate plots with text, arrows, and legend options.
Styles and Themes
Apply built-in styles and customize rcParams.
Save Figure
Export figures to PNG, PDF, and SVG with DPI control.
3D Plot
Render surfaces and scatter in 3D.
这篇内容对您有帮助吗?