自动缩放轴#

轴的限制可以手动设置(例如 ax.set_xlim(xmin, xmax)),或者 Matplotlib 可以根据 Axes 上已有的数据自动设置。关于这种自动缩放行为的选项有很多,下面将进行讨论。

我们将从一个简单的线图开始,展示自动缩放将轴的极限扩展到数据极限(-2π,2π)之外的5%。

import matplotlib.pyplot as plt
import numpy as np

import matplotlib as mpl

x = np.linspace(-2 * np.pi, 2 * np.pi, 100)
y = np.sinc(x)

fig, ax = plt.subplots()
ax.plot(x, y)
autoscale

页边距#

数据限制周围的默认边距是5%,这是基于默认配置设置 rcParams["axes.xmargin"] (default: 0.05)、rcParams["axes.ymargin"] (default: 0.05) 和 rcParams["axes.zmargin"] (default: 0.05) 的值:

print(ax.margins())
(0.05, 0.05)

可以使用 margins 覆盖边距大小,使其变小或变大:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(0.2, 0.2)
autoscale

一般来说,边距可以在 (-0.5, ∞) 范围内,其中负边距将轴限制设置为数据范围的子范围,即它们裁剪数据。使用单个数字作为边距会影响两个轴,可以使用关键字参数 xy 自定义单个边距,但不能同时使用位置和关键字接口。

fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(y=-0.2)
autoscale

粘性边缘#

有一些绘图元素(Artist)通常在使用时不需要留白。例如,假彩色图像(例如使用`.Axes.imshow`创建的图像)在计算留白时不会被考虑在内。

xx, yy = np.meshgrid(x, x)
zz = np.sinc(np.sqrt((xx - 1)**2 + (yy - 1)**2))

fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].imshow(zz)
ax[0].set_title("default margins")
ax[1].imshow(zz)
ax[1].margins(0.2)
ax[1].set_title("margins(0.2)")
default margins, margins(0.2)

这种边距的覆盖是由“粘性边缘”决定的,这是 Artist 类的一个属性,可以抑制在轴限制上添加边距。可以通过更改 use_sticky_edges 来禁用 Axes 上的粘性边缘效果。Artists 有一个属性 Artist.sticky_edges,粘性边缘的值可以通过写入 Artist.sticky_edges.xArtist.sticky_edges.y 来改变。

以下示例展示了重写的工作原理以及何时需要重写。

fig, ax = plt.subplots(ncols=3, figsize=(16, 10))
ax[0].imshow(zz)
ax[0].margins(0.2)
ax[0].set_title("default use_sticky_edges\nmargins(0.2)")
ax[1].imshow(zz)
ax[1].margins(0.2)
ax[1].use_sticky_edges = False
ax[1].set_title("use_sticky_edges=False\nmargins(0.2)")
ax[2].imshow(zz)
ax[2].margins(-0.2)
ax[2].set_title("default use_sticky_edges\nmargins(-0.2)")
default use_sticky_edges margins(0.2), use_sticky_edges=False margins(0.2), default use_sticky_edges margins(-0.2)

我们可以看到,将 use_sticky_edges 设置为 False 会以请求的边距渲染图像。

虽然粘性边缘不会通过额外的边距增加轴的限制,但仍然会考虑负边距。这可以从第三张图像的减少限制中看出。

控制自动缩放#

默认情况下,每次向图表添加新曲线时,限制都会重新计算:

fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].plot(x, y)
ax[0].set_title("Single curve")
ax[1].plot(x, y)
ax[1].plot(x * 2.0, y)
ax[1].set_title("Two curves")
Single curve, Two curves

然而,在某些情况下,您可能不希望自动调整视口以适应新数据。

禁用自动缩放的一种方法是手动设置轴的限制。假设我们只想更详细地查看数据的一部分。设置 xlim 即使在向数据添加更多曲线后仍然有效。要重新计算新的限制,调用 Axes.autoscale 将手动切换该功能。

fig, ax = plt.subplots(ncols=2, figsize=(12, 8))
ax[0].plot(x, y)
ax[0].set_xlim(left=-1, right=1)
ax[0].plot(x + np.pi * 0.5, y)
ax[0].set_title("set_xlim(left=-1, right=1)\n")
ax[1].plot(x, y)
ax[1].set_xlim(left=-1, right=1)
ax[1].plot(x + np.pi * 0.5, y)
ax[1].autoscale()
ax[1].set_title("set_xlim(left=-1, right=1)\nautoscale()")
set_xlim(left=-1, right=1) , set_xlim(left=-1, right=1) autoscale()

我们可以通过使用 Axes.get_autoscale_on() 来检查第一个图是否禁用了自动缩放,以及第二个图是否再次启用了自动缩放:

print(ax[0].get_autoscale_on())  # False means disabled
print(ax[1].get_autoscale_on())  # True means enabled -> recalculated
False
True

autoscale 函数的参数为我们提供了对自动缩放过程的精确控制。参数 enableaxis 的组合为选定的轴(或两者)设置了自动缩放功能。参数 tight 将选定轴的边距设置为零。要保留 enabletight 的设置,可以将相反的设置为 None,这样它就不会被修改。然而,将 enable 设置为 None 并将 tight 设置为 True 会影响两个轴,无论 axis 参数如何。

fig, ax = plt.subplots()
ax.plot(x, y)
ax.margins(0.2, 0.2)
ax.autoscale(enable=None, axis="x", tight=True)

print(ax.margins())
autoscale
(0, 0)

使用集合#

Autoscale 对添加到 Axes 的所有线条、补丁和图像开箱即用。它无法处理的一种艺术家是 Collection。在将集合添加到 Axes 后,必须手动触发 autoscale_view() 以重新计算轴的限制。

fig, ax = plt.subplots()
collection = mpl.collections.StarPolygonCollection(
    5, rotation=0, sizes=(250,),  # five point star, zero angle, size 250px
    offsets=np.column_stack([x, y]),  # Set the positions
    offset_transform=ax.transData,  # Propagate transformations of the Axes
)
ax.add_collection(collection)
ax.autoscale_view()
autoscale

脚本的总运行时间: (0 分钟 1.968 秒)

由 Sphinx-Gallery 生成的图库