复杂和语义图形组合#

警告

本教程记录了实验性/临时 API。我们将在 v3.3 中发布此功能以获取用户反馈。我们可能会在没有警告的情况下在未来的版本中进行重大更改。

在非统一网格中布置图形中的轴可能既乏味又冗长。对于我们拥有的密集、均匀的网格,Figure.subplots但对于更复杂的布局,例如跨越布局的多列/行或将图形的某些区域留空的轴,您可以使用 gridspec.GridSpec(请参阅在图中排列多个轴)或手动放置您的轴。Figure.subplot_mosaic旨在提供一个界面来直观地布置您的轴(作为 ASCII 艺术或嵌套列表)以简化此过程。

这个界面自然支持命名你的轴。 Figure.subplot_mosaic返回一个字典,该字典以用于布置图形的标签为键。通过返回带有名称的数据结构,可以更轻松地编写独立于图形布局的绘图代码。

这是受到提议的 MEP和 R拼凑库的启发。虽然我们没有实现运算符重载样式,但我们确实提供了一个 Pythonic API 来指定(嵌套)Axes 布局。

import matplotlib.pyplot as plt
import numpy as np


# Helper function used for visualization in the following examples
def identify_axes(ax_dict, fontsize=48):
    """
    Helper to identify the Axes in the examples below.

    Draws the label in a large font in the center of the Axes.

    Parameters
    ----------
    ax_dict : dict[str, Axes]
        Mapping between the title / label and the Axes.
    fontsize : int, optional
        How big the label should be.
    """
    kw = dict(ha="center", va="center", fontsize=fontsize, color="darkgrey")
    for k, ax in ax_dict.items():
        ax.text(0.5, 0.5, k, transform=ax.transAxes, **kw)

如果我们想要一个 2x2 网格,我们可以使用Figure.subplots它返回一个 2D 数组axes.Axes,我们可以索引该数组来进行绘图。

np.random.seed(19680801)
hist_data = np.random.randn(1_500)


fig = plt.figure(constrained_layout=True)
ax_array = fig.subplots(2, 2, squeeze=False)

ax_array[0, 0].bar(["a", "b", "c"], [5, 7, 9])
ax_array[0, 1].plot([1, 2, 3])
ax_array[1, 0].hist(hist_data, bins="auto")
ax_array[1, 1].imshow([[1, 2], [2, 1]])

identify_axes(
    {(j, k): a for j, r in enumerate(ax_array) for k, a in enumerate(r)},
)
马赛克

使用Figure.subplot_mosaic我们可以产生相同的马赛克,但给轴语义名称

fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(
    [
        ["bar", "plot"],
        ["hist", "image"],
    ],
)
ax_dict["bar"].bar(["a", "b", "c"], [5, 7, 9])
ax_dict["plot"].plot([1, 2, 3])
ax_dict["hist"].hist(hist_data)
ax_dict["image"].imshow([[1, 2], [2, 1]])
identify_axes(ax_dict)
马赛克

Figure.subplots和 之间的一个关键区别Figure.subplot_mosaic是返回值。前者返回一个用于索引访问的数组,后者返回一个字典,将标签映射到axes.Axes创建的实例

print(ax_dict)
{'bar': <AxesSubplot: label='bar'>, 'plot': <AxesSubplot: label='plot'>, 'hist': <AxesSubplot: label='hist'>, 'image': <AxesSubplot: label='image'>}

字符串简写#

通过将轴标签限制为单个字符,我们可以将我们想要的轴“绘制”为“ASCII 艺术”。以下

mosaic = """
    AB
    CD
    """

将为我们提供以 2x2 网格布局的 4 个轴,并生成与上面相同的图形马赛克(但现在用而不是标记)。{"A", "B", "C", "D"}{"bar", "plot", "hist", "image"}

fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
马赛克

或者,您可以使用更紧凑的字符串表示法

mosaic = "AB;CD"

将为您提供相同的组合,其中将";"用作行分隔符而不是换行符。

fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
马赛克

跨越多行/列的轴#

我们可以做而Figure.subplot_mosaic您不能做的事情Figure.subplots是指定轴应跨越多行或多列。

如果我们想重新排列我们的四个轴,"C"使其底部为水平跨度,"D"右侧为垂直跨度,我们会这样做

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """
    ABD
    CCD
    """
)
identify_axes(axd)
马赛克

如果我们不想用 Axes 填充图中所有的空格,我们可以指定网格中的一些空格为空白

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """
    A.C
    BBB
    .D.
    """
)
identify_axes(axd)
马赛克

如果我们更喜欢使用另一个字符(而不是句"."点)来标记空白,我们可以使用empty_sentinel来指定要使用的字符。

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """
    aX
    Xb
    """,
    empty_sentinel="X",
)
identify_axes(axd)
马赛克

我们使用的字母在内部没有任何意义,任何 Unicode 代码点都是有效的!

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """αб
       ℝ☢"""
)
identify_axes(axd)
马赛克

不建议使用空格作为标签或带有字符串速记的空标记,因为它可能会在处理输入时被剥离。

控制马赛克和子图的创建

此功能建立在基础之上,gridspec您可以将关键字参数传递给底层gridspec.GridSpec (与 相同Figure.subplots)。

在这种情况下,我们希望使用输入来指定排列,但通过gridspec_kw设置行/列的相对宽度。

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """
    .a.
    bAc
    .d.
    """,
    # set the height ratios between the rows
    height_ratios=[1, 3.5, 1],
    # set the width ratios between the columns
    width_ratios=[1, 3.5, 1],
)
identify_axes(axd)
马赛克

或者使用 { left , right , bottom , top } 关键字参数来定位整体马赛克以将同一马赛克的多个版本放在一个图中

mosaic = """AA
            BC"""
fig = plt.figure()
axd = fig.subplot_mosaic(
    mosaic,
    gridspec_kw={
        "bottom": 0.25,
        "top": 0.95,
        "left": 0.1,
        "right": 0.5,
        "wspace": 0.5,
        "hspace": 0.5,
    },
)
identify_axes(axd)

axd = fig.subplot_mosaic(
    mosaic,
    gridspec_kw={
        "bottom": 0.05,
        "top": 0.75,
        "left": 0.6,
        "right": 0.95,
        "wspace": 0.5,
        "hspace": 0.5,
    },
)
identify_axes(axd)
马赛克

或者,您可以使用子图功能:

mosaic = """AA
            BC"""
fig = plt.figure(constrained_layout=True)
left, right = fig.subfigures(nrows=1, ncols=2)
axd = left.subplot_mosaic(mosaic)
identify_axes(axd)

axd = right.subplot_mosaic(mosaic)
identify_axes(axd)
马赛克

我们还可以传递用于创建子图的参数(同样,与 相同Figure.subplots)。

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    "AB", subplot_kw={"projection": "polar"}
)
identify_axes(axd)
马赛克

嵌套列表输入#

我们可以用字符串速记做的所有事情,我们在传入列表时也可以做(在内部我们将字符串速记转换为嵌套列表),例如使用 spans、blanks 和gridspec_kw

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    [
        ["main", "zoom"],
        ["main", "BLANK"],
    ],
    empty_sentinel="BLANK",
    width_ratios=[2, 1],
)
identify_axes(axd)
马赛克

此外,使用列表输入,我们可以指定嵌套马赛克。内部列表的任何元素都可以是另一组嵌套列表:

inner = [
    ["inner A"],
    ["inner B"],
]

outer_nested_mosaic = [
    ["main", inner],
    ["bottom", "bottom"],
]
axd = plt.figure(constrained_layout=True).subplot_mosaic(
    outer_nested_mosaic, empty_sentinel=None
)
identify_axes(axd, fontsize=36)
马赛克

我们也可以传入一个 2D NumPy 数组来做类似的事情

mosaic = np.zeros((4, 4), dtype=int)
for j in range(4):
    mosaic[j, j] = j + 1
axd = plt.figure(constrained_layout=True).subplot_mosaic(
    mosaic,
    empty_sentinel=0,
)
identify_axes(axd)
马赛克

脚本总运行时间:(0分9.170秒)

由 Sphinx-Gallery 生成的画廊