Noter
Cliquez ici pour télécharger l'exemple de code complet
Composition de figures complexes et sémantiques #
Avertissement
Ce tutoriel documente l'API expérimentale/provisoire. Nous le publions dans la v3.3 pour obtenir les commentaires des utilisateurs. Nous pouvons apporter des modifications avec rupture dans les futures versions sans avertissement.
Disposer les axes d'une figure dans une grille non uniforme peut être à la fois fastidieux et verbeux. Pour les grilles denses et uniformes que nous avons, Figure.subplots
mais pour les mises en page plus complexes, telles que les axes qui s'étendent sur plusieurs colonnes/lignes de la mise en page ou qui laissent certaines zones de la figure vides, vous pouvez utiliser
gridspec.GridSpec
(voir Disposition de plusieurs axes dans une figure ) ou placer manuellement votre axes. Figure.subplot_mosaic
vise à fournir une interface pour présenter visuellement vos axes (sous forme d'art ASCII ou de listes imbriquées) afin de rationaliser ce processus.
Cette interface prend naturellement en charge le nommage de vos axes.
Figure.subplot_mosaic
renvoie un dictionnaire indexé sur les étiquettes utilisées pour mettre en page la figure. En renvoyant des structures de données avec des noms, il est plus facile d'écrire du code de traçage indépendant de la disposition de la figure.
Ceci est inspiré d'un MEP proposé et de la bibliothèque patchwork pour R. Bien que nous n'implémentions pas le style de surcharge d'opérateur, nous fournissons une API Pythonic pour spécifier les dispositions d'axes (imbriquées).
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 nous voulons une grille 2x2, nous pouvons utiliser Figure.subplots
qui renvoie un tableau 2D dans axes.Axes
lequel nous pouvons indexer pour effectuer notre tracé.
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)},
)
En utilisant Figure.subplot_mosaic
nous pouvons produire la même mosaïque mais donner aux axes des noms sémantiques
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)
Une différence clé entre Figure.subplots
et
Figure.subplot_mosaic
est la valeur de retour. Alors que le premier renvoie un tableau pour l'accès à l'index, le second renvoie un dictionnaire mappant les étiquettes aux axes.Axes
instances créées
print(ax_dict)
{'bar': <AxesSubplot: label='bar'>, 'plot': <AxesSubplot: label='plot'>, 'hist': <AxesSubplot: label='hist'>, 'image': <AxesSubplot: label='image'>}
Chaîne abrégée #
En limitant nos étiquettes d'axes à des caractères uniques, nous pouvons "dessiner" les axes que nous voulons comme "art ASCII". Ce qui suit
mosaic = """
AB
CD
"""
nous donnera 4 axes disposés dans une grille 2x2 et générera la même mosaïque de figures que ci-dessus (mais maintenant étiquetée avec plutôt que ).{"A", "B", "C",
"D"}
{"bar", "plot", "hist", "image"}
fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
Alternativement, vous pouvez utiliser la notation de chaîne plus compacte
mosaic = "AB;CD"
vous donnera la même composition, où le ";"
est utilisé comme séparateur de ligne au lieu de nouvelle ligne.
fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(mosaic)
identify_axes(ax_dict)
Axes couvrant plusieurs lignes/colonnes #
Quelque chose que nous pouvons faire avec Figure.subplot_mosaic
ce que vous ne pouvez pas faire Figure.subplots
est de spécifier qu'un Axe doit s'étendre sur plusieurs lignes ou colonnes.
Si nous voulons réorganiser nos quatre axes pour avoir "C"
une portée horizontale en bas et "D"
une portée verticale à droite, nous ferions
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"""
ABD
CCD
"""
)
identify_axes(axd)
Si nous ne voulons pas remplir tous les espaces de la figure avec des axes, nous pouvons spécifier que certains espaces de la grille soient vides
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"""
A.C
BBB
.D.
"""
)
identify_axes(axd)
Si nous préférons utiliser un autre caractère (plutôt qu'un point "."
) pour marquer l'espace vide, nous pouvons utiliser empty_sentinel pour spécifier le caractère à utiliser.
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"""
aX
Xb
""",
empty_sentinel="X",
)
identify_axes(axd)
En interne, il n'y a aucune signification attachée aux lettres que nous utilisons, tout point de code Unicode est valide !
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"""αб
ℝ☢"""
)
identify_axes(axd)
Il n'est pas recommandé d'utiliser un espace blanc comme étiquette ou comme sentinelle vide avec le raccourci de chaîne car il peut être supprimé lors du traitement de l'entrée.
Contrôler la création de mosaïques et de sous-parcelles #
Cette fonctionnalité est construite au-dessus de gridspec
et vous pouvez transmettre les arguments de mots-clés au sous-jacent gridspec.GridSpec
(identique à Figure.subplots
).
Dans ce cas, nous voulons utiliser l'entrée pour spécifier la disposition, mais définir les largeurs relatives des lignes/colonnes 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)
Ou utilisez les arguments de mot clé { left , right , bottom , top } pour positionner la mosaïque globale afin de mettre plusieurs versions de la même mosaïque dans une figure
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)
Alternativement, vous pouvez utiliser la fonctionnalité de sous-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)
Nous pouvons également passer par les arguments utilisés pour créer les sous-parcelles (encore une fois, identiques à Figure.subplots
).
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"AB", subplot_kw={"projection": "polar"}
)
identify_axes(axd)
Entrée de liste imbriquée #
Tout ce que nous pouvons faire avec le raccourci de chaîne, nous pouvons également le faire lors du passage dans une liste (en interne, nous convertissons le raccourci de chaîne en une liste imbriquée), par exemple en utilisant des plages, des blancs et gridspec_kw :
axd = plt.figure(constrained_layout=True).subplot_mosaic(
[
["main", "zoom"],
["main", "BLANK"],
],
empty_sentinel="BLANK",
width_ratios=[2, 1],
)
identify_axes(axd)
De plus, en utilisant l'entrée de liste, nous pouvons spécifier des mosaïques imbriquées. Tout élément de la liste interne peut être un autre ensemble de listes imbriquées :
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)
Nous pouvons également passer un tableau NumPy 2D pour faire des choses comme
Durée totale d'exécution du script : (0 minutes 9,170 secondes)