Composizione di figure complesse e semantiche #

Avvertimento

Questo tutorial documenta l'API sperimentale/provvisoria. Stiamo rilasciando questo in v3.3 per ottenere il feedback degli utenti. Potremmo apportare modifiche sostanziali nelle versioni future senza preavviso.

Disporre gli assi in una figura in una griglia non uniforme può essere noioso e prolisso. Per griglie dense e uniformi abbiamo Figure.subplotsma per layout più complessi, come Assi che si estendono su più colonne/righe del layout o lasciano vuote alcune aree della Figura, puoi usare gridspec.GridSpec(vedi Disporre più Assi in una Figura ) o posizionare manualmente il tuo assi. Figure.subplot_mosaicmira a fornire un'interfaccia per disporre visivamente i tuoi assi (come arte ASCII o elenchi nidificati) per semplificare questo processo.

Questa interfaccia supporta naturalmente la denominazione degli assi. Figure.subplot_mosaicrestituisce un dizionario digitato sulle etichette utilizzate per disporre la figura. Restituendo strutture dati con nomi, è più semplice scrivere codice di tracciamento indipendente dal layout Figure.

Questo è ispirato da un MEP proposto e dalla libreria patchwork per R. Sebbene non implementiamo lo stile di sovraccarico dell'operatore, forniamo un'API Pythonic per specificare i layout degli assi (nidificati).

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 vogliamo una griglia 2x2 possiamo usare Figure.subplotswhich restituisce un array 2D di axes.Axescui possiamo indicizzare per fare il nostro tracciato.

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_mosaicpossiamo produrre lo stesso mosaico ma dare agli assi nomi semantici

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

Una differenza fondamentale tra Figure.subplotse Figure.subplot_mosaicè il valore restituito. Mentre il primo restituisce un array per l'accesso all'indice, il secondo restituisce un dizionario che mappa le etichette alle axes.Axesistanze create

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

Corda abbreviata #

Limitando le nostre etichette degli assi a singoli caratteri possiamo "disegnare" gli assi che vogliamo come "arte ASCII". Il seguente

mosaic = """
    AB
    CD
    """

ci darà 4 assi disposti in una griglia 2x2 e genera lo stesso mosaico di figure come sopra (ma ora etichettato con anziché ).{"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

In alternativa, puoi usare la notazione per stringhe più compatta

mosaic = "AB;CD"

ti darà la stessa composizione, dove ";"viene usato come separatore di riga invece di newline.

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

Assi che si estendono su più righe/colonne #

Qualcosa che possiamo fare con Figure.subplot_mosaicciò che non puoi fare Figure.subplotsè specificare che un Axes dovrebbe estendersi su più righe o colonne.

Se vogliamo riorganizzare i nostri quattro assi in modo che "C"siano una campata orizzontale in basso e "D"una campata verticale a destra, faremmo

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

Se non vogliamo riempire tutti gli spazi della Figura con Assi, possiamo specificare che alcuni spazi della griglia siano vuoti

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

Se preferiamo utilizzare un altro carattere (piuttosto che un "."punto) per contrassegnare lo spazio vuoto, possiamo utilizzare empty_sentinel per specificare il carattere da utilizzare.

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

Internamente non c'è alcun significato associato alle lettere che usiamo, qualsiasi punto di codice Unicode è valido!

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

Non è consigliabile utilizzare lo spazio bianco come etichetta o sentinella vuota con la stringa abbreviata perché potrebbe essere rimossa durante l'elaborazione dell'input.

Controllo della creazione di mosaici e sottotrame #

Questa funzionalità è basata su gridspece puoi passare gli argomenti della parola chiave al sottostante gridspec.GridSpec (lo stesso di Figure.subplots).

In questo caso vogliamo utilizzare l'input per specificare la disposizione, ma impostare le larghezze relative delle righe/colonne tramite 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

Oppure usa gli argomenti della parola chiave { left , right , bottom , top } per posizionare il mosaico complessivo per inserire più versioni dello stesso mosaico in una 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

In alternativa, puoi utilizzare la funzionalità sub-Figure:

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

Possiamo anche passare attraverso argomenti usati per creare le sottotrame (di nuovo, lo stesso di Figure.subplots).

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

Ingresso elenco nidificato #

Tutto ciò che possiamo fare con la stringa abbreviata lo possiamo fare anche quando passiamo una lista (internamente convertiamo la stringa abbreviata in una lista nidificata), ad esempio usando span, spazi vuoti 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

Inoltre, utilizzando l'input list possiamo specificare i mosaici nidificati. Qualsiasi elemento dell'elenco interno può essere un altro insieme di elenchi nidificati:

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

Possiamo anche passare un array NumPy 2D per fare cose come

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 di esecuzione totale dello script: (0 minuti 9,170 secondi)

Galleria generata da Sphinx-Gallery