Composição de figuras complexas e semânticas #

Aviso

Este tutorial documenta a API experimental/provisória. Estamos lançando isso na v3.3 para obter feedback do usuário. Podemos fazer alterações importantes em versões futuras sem aviso prévio.

Colocar os eixos em uma figura em uma grade não uniforme pode ser tedioso e prolixo. Para grades densas e uniformes, temos, Figure.subplotsmas para layouts mais complexos, como eixos que abrangem várias colunas/linhas do layout ou deixam algumas áreas da figura em branco, você pode usar gridspec.GridSpec(consulte Organizar vários eixos em uma figura ) ou colocar manualmente machados. Figure.subplot_mosaicvisa fornecer uma interface para definir visualmente seus eixos (como arte ASCII ou listas aninhadas) para simplificar esse processo.

Essa interface suporta naturalmente a nomeação de seus eixos. Figure.subplot_mosaicretorna um dicionário digitado nos rótulos usados ​​para dispor a Figura. Ao retornar estruturas de dados com nomes, é mais fácil escrever código de plotagem independente do layout da figura.

Isso é inspirado por um MEP proposto e pela biblioteca patchwork para R. Embora não implementemos o estilo de sobrecarga do operador, fornecemos uma API Pythonic para especificar layouts de eixos (aninhados).

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)

Se quisermos uma grade 2x2, podemos usar o Figure.subplotsque retorna uma matriz 2D na axes.Axesqual podemos indexar para fazer nossa plotagem.

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)},
)
mosaico

Usando Figure.subplot_mosaicpodemos produzir o mesmo mosaico, mas dar nomes semânticos aos eixos

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)
mosaico

Uma diferença fundamental entre Figure.subplotse Figure.subplot_mosaicé o valor de retorno. Enquanto o primeiro retorna um array para acesso ao índice, o segundo retorna um dicionário mapeando os rótulos para as axes.Axesinstâncias criadas

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

String abreviada #

Ao restringir nossos rótulos de eixos a caracteres únicos, podemos "desenhar" os eixos que queremos como "arte ASCII". A seguir

mosaic = """
    AB
    CD
    """

nos dará 4 eixos dispostos em uma grade 2x2 e gerará o mesmo mosaico de figuras acima (mas agora rotulado com em vez de ).{"A", "B", "C", "D"}{"bar", "plot", "hist", "image"}

fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
mosaico

Como alternativa, você pode usar a notação de string mais compacta

mosaic = "AB;CD"

fornecerá a mesma composição, onde o ";"é usado como separador de linha em vez de nova linha.

fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
mosaico

Eixos abrangendo várias linhas/colunas #

Algo que podemos fazer com Figure.subplot_mosaico que você não pode fazer Figure.subplotsé especificar que um Axes deve abranger várias linhas ou colunas.

Se quisermos reorganizar nossos quatro eixos para que tenham "C"uma extensão horizontal na parte inferior e "D"uma extensão vertical à direita, faríamos

axd = plt.figure(constrained_layout=True).subplot_mosaic(
    """
    ABD
    CCD
    """
)
identify_axes(axd)
mosaico

Se não quisermos preencher todos os espaços da Figura com Eixos, podemos especificar alguns espaços na grade para ficarem em branco

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

Se preferirmos usar outro caractere (em vez de um ponto ".") para marcar o espaço vazio, podemos usar empty_sentinel para especificar o caractere a ser usado.

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

Internamente, não há significado associado às letras que usamos, qualquer ponto de código Unicode é válido!

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

Não é recomendado usar espaço em branco como um rótulo ou uma sentinela vazia com a abreviação da string porque ela pode ser removida durante o processamento da entrada.

Controlando a criação de mosaicos e subtramas #

Esse recurso é construído sobre gridspece você pode passar os argumentos de palavra-chave para o subjacente gridspec.GridSpec (o mesmo que Figure.subplots).

Neste caso, queremos usar a entrada para especificar o arranjo, mas definir as larguras relativas das linhas/colunas via 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)
mosaico

Ou use os argumentos de palavra-chave { esquerda , direita , inferior , superior } para posicionar o mosaico geral para colocar várias versões do mesmo mosaico em uma figura

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)
mosaico

Como alternativa, você pode usar a funcionalidade de subfigura:

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)
mosaico

Também podemos passar por argumentos usados ​​para criar as subtramas (novamente, o mesmo que Figure.subplots).

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

Entrada de lista aninhada #

Tudo o que podemos fazer com a string abreviada também podemos fazer ao passar em uma lista (internamente convertemos a string abreviada em uma lista aninhada), por exemplo, usando spans, blanks e gridspec_kw :

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

Além disso, usando a entrada de lista, podemos especificar mosaicos aninhados. Qualquer elemento da lista interna pode ser outro conjunto de listas aninhadas:

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)
mosaico

Também podemos passar um array NumPy 2D para fazer coisas como

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)
mosaico

Tempo total de execução do script: ( 0 minutos 9,170 segundos)

Galeria gerada por Sphinx-Gallery