Composición figurativa compleja y semántica #

Advertencia

Este tutorial documenta la API experimental/provisional. Estamos lanzando esto en v3.3 para obtener comentarios de los usuarios. Podemos realizar cambios importantes en futuras versiones sin previo aviso.

Colocar ejes en una figura en una cuadrícula no uniforme puede ser tedioso y detallado. Para cuadrículas densas y uniformes, Figure.subplotspero para diseños más complejos, como ejes que abarcan varias columnas/filas del diseño o dejan algunas áreas de la figura en blanco, puede usar gridspec.GridSpec(consulte Organización de varios ejes en una figura ) o colocar manualmente su hachas Figure.subplot_mosaictiene como objetivo proporcionar una interfaz para diseñar visualmente sus ejes (como arte ASCII o listas anidadas) para agilizar este proceso.

Esta interfaz, naturalmente, admite nombrar sus ejes. Figure.subplot_mosaicdevuelve un diccionario tecleado en las etiquetas utilizadas para diseñar la Figura. Al devolver estructuras de datos con nombres, es más fácil escribir código de trazado que sea independiente del diseño de la figura.

Esto está inspirado en un MEP propuesto y la biblioteca de mosaicos para R. Si bien no implementamos el estilo de sobrecarga del operador, proporcionamos una API Pythonic para especificar diseños de ejes (anidados).

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)

Si queremos una cuadrícula de 2x2, podemos usarla, Figure.subplotsque devuelve una matriz 2D en axes.Axesla que podemos indexar para hacer nuestro trazado.

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 producir el mismo mosaico pero dando a los ejes nombres semánticos

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 diferencia clave entre Figure.subplotsy Figure.subplot_mosaices el valor devuelto. Mientras que el primero devuelve una matriz para el acceso al índice, el segundo devuelve un diccionario que asigna las etiquetas a las axes.Axesinstancias creadas .

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

Cadena abreviada #

Al restringir las etiquetas de nuestros ejes a caracteres individuales, podemos "dibujar" los ejes que queremos como "arte ASCII". El seguimiento

mosaic = """
    AB
    CD
    """

nos dará 4 ejes dispuestos en una cuadrícula de 2x2 y generará el mismo mosaico de figuras que el anterior (pero ahora etiquetado con en lugar 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

Alternativamente, puede usar la notación de cadena más compacta

mosaic = "AB;CD"

le dará la misma composición, donde ";"se usa como separador de fila en lugar de nueva línea.

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

Ejes que abarcan múltiples filas/columnas #

Algo que podemos hacer con lo Figure.subplot_mosaicque usted no puede hacer Figure.subplotses especificar que los ejes deben abarcar varias filas o columnas.

Si queremos reorganizar nuestros cuatro ejes para que tengan "C"un tramo horizontal en la parte inferior y "D"un tramo vertical a la derecha, haríamos

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

Si no queremos llenar todos los espacios en la figura con ejes, podemos especificar algunos espacios en la cuadrícula para que estén en blanco

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

Si preferimos usar otro carácter (en lugar de un punto ".") para marcar el espacio vacío, podemos usar empty_sentinel para especificar el carácter a usar.

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

Internamente no hay ningún significado adjunto a las letras que usamos, ¡cualquier punto de código Unicode es válido!

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

No se recomienda usar espacios en blanco como una etiqueta o un centinela vacío con la abreviatura de cadena porque puede eliminarse mientras se procesa la entrada.

Controlando la creación de mosaicos y subparcelas #

Esta función se basa en gridspecy puede pasar los argumentos de palabras clave al subyacente gridspec.GridSpec (igual que Figure.subplots).

En este caso, queremos usar la entrada para especificar la disposición, pero establecer los anchos relativos de las filas/columnas a través de 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

O use los argumentos de palabra clave { izquierda , derecha , abajo , arriba } para posicionar el mosaico general para colocar múltiples versiones del mismo mosaico en 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

Alternativamente, puede utilizar la función 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

También podemos pasar los argumentos utilizados para crear las subparcelas (nuevamente, lo mismo que Figure.subplots).

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

Entrada de lista anidada #

Todo lo que podemos hacer con la taquigrafía de cadena también lo podemos hacer al pasar una lista (internamente convertimos la taquigrafía de cadena en una lista anidada), por ejemplo, usando intervalos, espacios en blanco y 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

Además, usando la entrada de lista podemos especificar mosaicos anidados. Cualquier elemento de la lista interna puede ser otro conjunto de listas anidadas:

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

También podemos pasar una matriz 2D NumPy para hacer cosas 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

Tiempo total de ejecución del script: (0 minutos 9.170 segundos)

Galería generada por Sphinx-Gallery