Matplotlib 3.6.0 的新功能 (2022年9月15日)#
要查看自上次修订以来的所有问题和拉取请求列表,请参阅 GitHub 统计数据为 3.9.2 版本(2024年8月12日)。
图形和轴的创建 / 管理#
subplots, subplot_mosaic 接受 height_ratios 和 width_ratios 参数#
在 subplots 和 subplot_mosaic 中,列和行的相对宽度和高度可以通过向方法传递 height_ratios 和 width_ratios 关键字参数来控制:
fig = plt.figure()
axs = fig.subplots(3, 1, sharex=True, height_ratios=[3, 1, 1])
(Source code, 2x.png, png)
之前,这需要通过 gridspec_kw 参数传递比率:
fig = plt.figure()
axs = fig.subplots(3, 1, sharex=True,
gridspec_kw=dict(height_ratios=[3, 1, 1]))
约束布局不再被视为实验性功能#
约束布局引擎和API不再被视为实验性的。在没有弃用期的情况下,不再允许对行为和API进行任意更改。
新的 layout_engine 模块#
Matplotlib 附带了 tight_layout 和 constrained_layout 布局引擎。提供了一个新的 layout_engine 模块,允许下游库编写自己的布局引擎,并且 Figure 对象现在可以将 LayoutEngine 子类作为 layout 参数的参数。
固定纵横比 Axes 的压缩布局#
现在可以通过 fig, axs = plt.subplots(2, 3, layout='compressed') 将具有固定纵横比的 Axes 进行简单排列并打包在一起。
使用 layout='tight' 或 'constrained',具有固定纵横比的 Axes 可能会在彼此之间留下较大的间隙:
(Source code, 2x.png, png)
使用 layout='compressed' 布局可以减少 Axes 之间的空间,并将额外空间添加到外部边距中:
(Source code, 2x.png, png)
详情请参见 固定纵横比轴的网格:“压缩”布局。
布局引擎现在可以被移除#
现在可以通过调用 Figure.set_layout_engine 并传入 'none' 来移除 Figure 上的布局引擎。这在计算布局后可能很有用,以便减少计算量,例如,用于后续的动画循环。
可以随后设置不同的布局引擎,只要它与之前的布局引擎兼容。
Axes.inset_axes 灵活性#
matplotlib.axes.Axes.inset_axes 现在接受 projection、polar 和 axes_class 关键字参数,因此可以返回 matplotlib.axes.Axes 的子类。
fig, ax = plt.subplots()
ax.plot([0, 2], [1, 2])
polar_ax = ax.inset_axes([0.75, 0.25, 0.2, 0.2], projection='polar')
polar_ax.plot([0, 2], [1, 2])
(Source code, 2x.png, png)
WebP 现在是一个支持的输出格式#
现在可以通过使用 .webp 文件扩展名,或者传递 format='webp' 给 savefig 来将图像保存为 WebP 格式。这依赖于 Pillow 对 WebP 的支持。
垃圾回收不再在关闭图形时运行#
Matplotlib 有许多循环引用(在 Figure 和 Manager 之间,在 Axes 和 Figure 之间,Axes 和 Artist 之间,Figure 和 Canvas 之间等),因此当用户放弃对 Figure 的最后一个引用(并从 pyplot 的状态中清除它)时,这些对象不会立即被删除。
为了解决这个问题,我们很早(自2004年之前)就在关闭代码中加入了 `gc.collect`(仅针对最低的两个代),以便及时清理我们留下的痕迹。然而,这既没有达到我们想要的效果(因为我们的对象实际上大部分都会存活),而且由于清除了第一代,使得我们的内存使用变得无界。
在创建图形和销毁图形之间存在非常紧密的循环的情况下(例如 plt.figure(); plt.close()),第一次生成永远不会增长到足够大,以至于Python会考虑在更高的代上运行收集。这将导致内存使用量无限制地增加,因为长期存在的对象永远不会被重新考虑以查找引用循环,因此永远不会被删除。
现在,当一个图形关闭时,我们不再进行任何垃圾收集,而是依赖Python自动决定定期运行垃圾收集。如果你有严格的内存要求,你可以自己调用 gc.collect,但这可能会在紧密的计算循环中影响性能。
绘图方法#
条纹线(实验性)#
新的 gapcolor 参数用于 plot ,可以创建条纹线。
x = np.linspace(1., 3., 10)
y = x**3
fig, ax = plt.subplots()
ax.plot(x, y, linestyle='--', color='orange', gapcolor='blue',
linewidth=3, label='a striped line')
ax.legend()
(Source code, 2x.png, png)
在 bxp 和 boxplot 中的箱线图中自定义帽宽#
新的 capwidths 参数用于 bxp 和 boxplot,允许控制箱线图中帽子的宽度。
x = np.linspace(-7, 7, 140)
x = np.hstack([-25, x, 25])
capwidths = [0.01, 0.2]
fig, ax = plt.subplots()
ax.boxplot([x, x], notch=True, capwidths=capwidths)
ax.set_title(f'{capwidths=}')
(Source code, 2x.png, png)
在条形图中更容易标记条形#
bar 和 barh 的 label 参数现在可以传递一个标签列表给条形图。该列表的长度必须与 x 相同,并标记各个条形。重复的标签不会去重,并且会导致重复的标签条目,因此最好在条形图的样式也不同的情况下使用(例如,通过传递一个列表给 color,如下所示。)
x = ["a", "b", "c"]
y = [10, 20, 15]
color = ['C0', 'C1', 'C2']
fig, ax = plt.subplots()
ax.bar(x, y, color=color, label=x)
ax.legend()
(Source code, 2x.png, png)
新样式格式字符串用于颜色条刻度#
colorbar 的 format 参数(以及其他颜色条方法)现在接受 {} 样式的格式字符串。
fig, ax = plt.subplots()
im = ax.imshow(z)
fig.colorbar(im, format='{x:.2e}') # Instead of '%.2e'
负轮廓的线条样式可以单独设置#
负轮廓的线条样式可以通过传递 negative_linestyles 参数给 Axes.contour 来设置。以前,这种样式只能通过 rcParams["contour.negative_linestyles"] 全局设置。
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
fig, axs = plt.subplots(1, 2)
CS = axs[0].contour(X, Y, Z, 6, colors='k')
axs[0].clabel(CS, fontsize=9, inline=True)
axs[0].set_title('Default negative contours')
CS = axs[1].contour(X, Y, Z, 6, colors='k', negative_linestyles='dotted')
axs[1].clabel(CS, fontsize=9, inline=True)
axs[1].set_title('Dotted negative contours')
(Source code, 2x.png, png)
通过 ContourPy 改进的四边形轮廓计算#
等高线函数 contour 和 contourf 新增了一个关键字参数 algorithm,用于控制计算等高线时使用的算法。可以选择四种算法之一,默认使用 algorithm='mpl2014',这是自2014年以来Matplotlib一直在使用的算法。
之前 Matplotlib 自带了用于计算四边形网格等高线的 C++ 代码。现在改用外部库 ContourPy。
此时 algorithm 关键字参数的其他可能值是 'mpl2005'、'serial' 和 'threaded';更多详情请参阅 ContourPy 文档。
备注
使用 algorithm='mpl2014' 生成的等高线和多边形将与更改前的结果在浮点精度范围内相同。例外情况是重复点,即包含相邻相同 (x, y) 点的等高线;以前会移除这些重复点,现在则保留。受此影响的等高线将产生相同的视觉效果,但等高线中的点数将会增加。
使用 clabel 获得的等高线标签位置也可能不同。
errorbar 支持 markerfacecoloralt#
现在,markerfacecoloralt 参数从 Axes.errorbar 传递给线条绘图器。文档现在准确列出了传递给 Line2D 的属性,而不是声称所有关键字参数都被传递。
x = np.arange(0.1, 4, 0.5)
y = np.exp(-x)
fig, ax = plt.subplots()
ax.errorbar(x, y, xerr=0.2, yerr=0.4,
linestyle=':', color='darkgrey',
marker='o', markersize=20, fillstyle='left',
markerfacecolor='tab:blue', markerfacecoloralt='tab:orange',
markeredgecolor='tab:brown', markeredgewidth=2)
(Source code, 2x.png, png)
streamplot 可以禁用流线断裂#
现在可以指定流图具有连续、不间断的流线。以前,流线会结束以限制单个网格单元内的线条数量。请参见以下图表之间的差异:
(Source code, 2x.png, png)
新轴比例 asinh (实验性)#
新的 asinh 轴比例提供了一种替代 symlog 的方法,它在比例的准线性和渐近对数区域之间平滑过渡。这是基于一个反双曲正弦变换,允许绘制跨越多个数量级的正负值。
(Source code, 2x.png, png)
stairs(..., fill=True) 通过设置线宽隐藏补丁边缘#
stairs(..., fill=True) 之前通过设置 edgecolor="none" 隐藏了 Patch 的边缘。因此,稍后调用 set_color() 在 Patch 上会使 Patch 显得更大。
现在,通过使用 linewidth=0 ,可以防止这种明显的尺寸变化。同样,调用 stairs(..., fill=True, linewidth=3) 将表现得更加透明。
修复 Patch 类的虚线偏移#
以前,在使用破折号元组设置 Patch 对象的线条样式时,偏移量会被忽略。现在,偏移量会如预期地应用于 Patch,并且可以像在 Line2D 对象中那样使用。
矩形补丁旋转点#
Rectangle 的旋转点现在可以通过 rotation_point 参数设置为 'xy'、'center' 或一个由两个数字组成的 2-tuple。
(Source code, 2x.png, png)
颜色和颜色映射#
颜色序列注册表#
颜色序列注册表 ColorSequenceRegistry 包含了一系列(即简单的列表)Matplotlib 已知的颜色。通常不会直接使用它,而是通过 matplotlib.color_sequences 的全局实例来使用。
用于创建不同查找表大小的颜色映射方法#
新方法 Colormap.resampled 创建一个新的 Colormap 实例,并指定查找表的大小。这是通过 get_cmap 操作查找表大小的替代方法。
使用:
get_cmap(name).resampled(N)
代替:
get_cmap(name, lut=N)
用字符串设置规范#
现在可以使用相应尺度的字符串名称来设置规范(例如在图像上),例如 imshow(array, norm="log")。请注意,在这种情况下,也可以传递 vmin 和 vmax,因为会在幕后创建一个新的 Norm 实例。
标题、刻度和标签#
plt.xticks 和 plt.yticks 支持 minor 关键字参数#
现在可以通过设置 minor=True 来使用 pyplot.xticks 和 pyplot.yticks 设置或获取次刻度。
plt.figure()
plt.plot([1, 2, 3, 3.5], [2, 1, 0, -0.5])
plt.xticks([1, 2, 3], ["One", "Zwei", "Trois"])
plt.xticks([np.sqrt(2), 2.5, np.pi],
[r"$\sqrt{2}$", r"$\frac{5}{2}$", r"$\pi$"], minor=True)
(Source code, 2x.png, png)
图例#
图例可以控制标题和手柄的对齐方式#
Legend 现在支持通过关键字参数 alignment 控制标题和句柄的对齐方式。你也可以使用 Legend.set_alignment 来控制现有图例的对齐方式。
fig, axs = plt.subplots(3, 1)
for i, alignment in enumerate(['left', 'center', 'right']):
axs[i].plot(range(10), label='test')
axs[i].legend(title=f'{alignment=}', alignment=alignment)
(Source code, 2x.png, png)
ncol 关键字参数已重命名为 ncols#
用于控制列数的 legend 的 ncol 关键字参数已重命名为 ncols,以与 subplots 和 GridSpec 的 ncols 和 nrows 关键字保持一致。ncol 仍然支持向后兼容,但不推荐使用。
标记#
marker 现在可以设置为字符串 "none"#
字符串 "none" 表示 无标记,与其他支持小写版本的 API 一致。推荐使用 "none" 而不是 "None",以避免与 None 对象混淆。
自定义 MarkerStyle 的连接和封口样式#
新的 MarkerStyle 参数允许控制连接样式和端点样式,并允许用户提供一个应用于标记的变换(例如旋转)。
from matplotlib.markers import CapStyle, JoinStyle, MarkerStyle
from matplotlib.transforms import Affine2D
fig, axs = plt.subplots(3, 1, layout='constrained')
for ax in axs:
ax.axis('off')
ax.set_xlim(-0.5, 2.5)
axs[0].set_title('Cap styles', fontsize=14)
for col, cap in enumerate(CapStyle):
axs[0].plot(col, 0, markersize=32, markeredgewidth=8,
marker=MarkerStyle('1', capstyle=cap))
# Show the marker edge for comparison with the cap.
axs[0].plot(col, 0, markersize=32, markeredgewidth=1,
markerfacecolor='none', markeredgecolor='lightgrey',
marker=MarkerStyle('1'))
axs[0].annotate(cap.name, (col, 0),
xytext=(20, -5), textcoords='offset points')
axs[1].set_title('Join styles', fontsize=14)
for col, join in enumerate(JoinStyle):
axs[1].plot(col, 0, markersize=32, markeredgewidth=8,
marker=MarkerStyle('*', joinstyle=join))
# Show the marker edge for comparison with the join.
axs[1].plot(col, 0, markersize=32, markeredgewidth=1,
markerfacecolor='none', markeredgecolor='lightgrey',
marker=MarkerStyle('*'))
axs[1].annotate(join.name, (col, 0),
xytext=(20, -5), textcoords='offset points')
axs[2].set_title('Arbitrary transforms', fontsize=14)
for col, (size, rot) in enumerate(zip([2, 5, 7], [0, 45, 90])):
t = Affine2D().rotate_deg(rot).scale(size)
axs[2].plot(col, 0, marker=MarkerStyle('*', transform=t))
(Source code, 2x.png, png)
字体和文本#
字体回退#
现在可以指定字体家族列表,Matplotlib 将按顺序尝试这些字体以找到所需的字形。
plt.rcParams["font.size"] = 20
fig = plt.figure(figsize=(4.75, 1.85))
text = "There are 几个汉字 in between!"
fig.text(0.05, 0.65, text, family=["Noto Sans CJK JP", "Noto Sans TC"])
fig.text(0.05, 0.45, text, family=["DejaVu Sans", "Noto Sans CJK JP", "Noto Sans TC"])
目前,这适用于 Agg(以及所有 GUI 嵌入)、svg、pdf、ps 和内联后端。
可用字体名称列表#
可用字体列表现在很容易访问。要获取 Matplotlib 中可用字体名称的列表,请使用:
from matplotlib import font_manager
font_manager.get_font_names()
math_to_image 现在有一个 color 关键字参数#
为了轻松支持依赖于 Matplotlib 的 MathText 渲染来生成方程图像的外部库,向 math_to_image 添加了一个 color 关键字参数。
from matplotlib import mathtext
mathtext.math_to_image('$x^2$', 'filename.png', color='Maroon')
活动URL区域随链接文本旋转#
当链接文本在图形中旋转时,活动URL区域现在将包括旋转后的链接区域。以前,活动区域保持在原始的、未旋转的位置。
rcParams 改进#
允许全局设置图标签的大小和权重,并与标题分开设置#
对于图形标签 Figure.supxlabel 和 Figure.supylabel,可以使用 rcParams["figure.labelsize"] (default: 'large') 和 rcParams["figure.labelweight"] (default: 'normal') 分别设置标签的大小和粗细,这与图形标题不同。
# Original (previously combined with below) rcParams:
plt.rcParams['figure.titlesize'] = 64
plt.rcParams['figure.titleweight'] = 'bold'
# New rcParams:
plt.rcParams['figure.labelsize'] = 32
plt.rcParams['figure.labelweight'] = 'bold'
fig, axs = plt.subplots(2, 2, layout='constrained')
for ax in axs.flat:
ax.set(xlabel='xlabel', ylabel='ylabel')
fig.suptitle('suptitle')
fig.supxlabel('supxlabel')
fig.supylabel('supylabel')
(Source code, 2x.png, png)
请注意,如果您更改了 rcParams["figure.titlesize"] (default: 'large') 或 rcParams["figure.titleweight"] (default: 'normal'),您现在还必须更改引入的参数,以获得与过去行为一致的结果。
可以全局禁用数学文本解析#
可以使用 rcParams["text.parse_math"] (default: True) 设置来禁用所有 Text 对象(特别是来自 Axes.text 方法)中的 mathtext 解析。
matplotlibrc 中的双引号字符串#
你现在可以在字符串周围使用双引号。这允许在字符串中使用 '#' 字符。没有引号时,'#' 被解释为注释的开始。特别是,你现在可以定义十六进制颜色:
grid.color: "#b0b0b0"
3D 轴改进#
主平面视图角度的标准化视图#
当在一个主视图平面(即垂直于XY、XZ或YZ平面)中查看3D图时,轴将显示在标准位置。有关3D视图的更多信息,请参见 mplot3d 视角 和 主要3D视图平面。
3D 摄像机的自定义焦距#
3D Axes 现在可以通过指定虚拟相机的焦距更好地模拟真实世界的相机。默认焦距为1对应于90°的视场角(FOV),并且与现有的3D图向后兼容。增加1到无穷大之间的焦距会“压平”图像,而减少1到0之间的焦距会夸张透视效果,使图像显得更有深度。
焦距可以通过所需的 FOV 通过以下公式计算:

from mpl_toolkits.mplot3d import axes3d
X, Y, Z = axes3d.get_test_data(0.05)
fig, axs = plt.subplots(1, 3, figsize=(7, 4),
subplot_kw={'projection': '3d'})
for ax, focal_length in zip(axs, [0.2, 1, np.inf]):
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
ax.set_proj_type('persp', focal_length=focal_length)
ax.set_title(f"{focal_length=}")
(Source code, 2x.png, png)
3D 图表增加了第三个“滚动”视角#
现在可以通过添加第三个滚动角度从任何方向查看3D图,该角度围绕视图轴旋转图。使用鼠标进行交互式旋转仍然只控制仰角和方位角,这意味着此功能与以编程方式创建更复杂相机角度的用户相关。默认的滚动角度为0,与现有的3D图向后兼容。
from mpl_toolkits.mplot3d import axes3d
X, Y, Z = axes3d.get_test_data(0.05)
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
ax.view_init(elev=0, azim=0, roll=30)
ax.set_title('elev=0, azim=0, roll=30')
(Source code, 2x.png, png)
3D 图形的等比例纵横比#
用户可以为3D图的X、Y、Z轴设置纵横比为'equal'、'equalxy'、'equalxz'或'equalyz',而不是默认的'auto'。
from itertools import combinations, product
aspects = [
['auto', 'equal', '.'],
['equalxy', 'equalyz', 'equalxz'],
]
fig, axs = plt.subplot_mosaic(aspects, figsize=(7, 6),
subplot_kw={'projection': '3d'})
# Draw rectangular cuboid with side lengths [1, 1, 5]
r = [0, 1]
scale = np.array([1, 1, 5])
pts = combinations(np.array(list(product(r, r, r))), 2)
for start, end in pts:
if np.sum(np.abs(start - end)) == r[1] - r[0]:
for ax in axs.values():
ax.plot3D(*zip(start*scale, end*scale), color='C0')
# Set the aspect ratios
for aspect, ax in axs.items():
ax.set_box_aspect((3, 4, 5))
ax.set_aspect(aspect)
ax.set_title(f'set_aspect({aspect!r})')
(Source code, 2x.png, png)
交互工具改进#
旋转、纵横比校正和添加/移除状态#
RectangleSelector 和 EllipseSelector 现在可以在 -45° 到 45° 之间进行交互式旋转。范围限制目前由实现决定。旋转功能可以通过按下 r 键('r' 是 state_modifier_keys 中映射到 'rotate' 的默认键)或通过调用 selector.add_state('rotate') 来启用或禁用。
在使用“square”状态时,现在可以考虑轴的纵横比。这是通过在初始化选择器时指定 use_data_coordinates='True' 来启用的。
除了使用在 state_modifier_keys 中定义的修饰键以交互方式更改选择器状态外,现在还可以使用 add_state 和 remove_state 方法以编程方式更改选择器状态。
from matplotlib.widgets import RectangleSelector
values = np.arange(0, 100)
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(values, values)
selector = RectangleSelector(ax, print, interactive=True,
drag_from_anywhere=True,
use_data_coordinates=True)
selector.add_state('rotate') # alternatively press 'r' key
# rotate the selector interactively
selector.remove_state('rotate') # alternatively press 'r' key
selector.add_state('square')
MultiCursor 现在支持在多个图形中分割的轴#
之前,MultiCursor 只有在所有目标 Axes 属于同一个图形时才能工作。
由于这一更改,MultiCursor 构造函数的第一个参数已变为未使用(它之前是所有 Axes 的联合画布,但现在画布直接从 Axes 列表中推断)。
PolygonSelector 边界框#
PolygonSelector 现在有一个 draw_bounding_box 参数,当设置为 True 时,将在多边形完成后在其周围绘制一个边界框。边界框可以调整大小和移动,从而可以轻松调整多边形的点。
设置 PolygonSelector 顶点#
现在可以通过使用 PolygonSelector.verts 属性以编程方式设置 PolygonSelector 的顶点。以这种方式设置顶点将重置选择器,并使用提供的顶点创建一个新的完整选择器。
SpanSelector 小部件现在可以对齐到指定值#
.SpanSelector 小部件现在可以吸附到由 snap_values 参数指定的值。
更多工具栏图标为深色主题进行了样式设计#
在macOS和Tk后端,当使用深色主题时,工具栏图标现在将会反转。
特定平台的更改#
Wx 后端使用标准工具栏#
工具栏不是自定义的尺寸器,而是作为标准工具栏设置在Wx窗口上。
macosx 后端的改进#
修饰键处理更加一致#
macosx 后端现在以更一致的方式处理修饰键,与其他后端一致。更多信息请参见 事件连接 中的表格。
savefig.directory rcParam 支持#
macosx 后端现在将遵循 rcParams["savefig.directory"] (default: '~') 设置。如果设置为非空字符串,则保存对话框将默认为此目录,并保留后续保存目录的更改。
figure.raise_window rcParam 支持#
macosx 后端现在将遵循 rcParams["figure.raise_window"] (default: True) 设置。如果设置为 False,更新时图窗窗口将不会被提升到顶部。
全屏切换支持#
与其他后端支持一样,macosx 后端现在支持切换全屏视图。默认情况下,可以通过按 f 键来切换此视图。
改进了动画和blitting支持#
macosx 后端已得到改进,修复了 blitting、带有新艺术家的动画帧,并减少了不必要的绘制调用。
macOS 应用程序图标应用于 Qt 后端#
在使用基于Qt的macOS后端时,应用程序图标现在将被设置,就像在其他后端/平台上一样。
新的最低 macOS 版本#
macosx 后端现在要求 macOS >= 10.12。
Windows on ARM 支持#
已添加对 arm64 目标 Windows 的初步支持。此支持需要 FreeType 2.11 或更高版本。
尚无可用的二进制轮子,但可以从源代码构建。