Ceci est une ancienne révision du document !
Matplotlib
Un simple graphique
import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5] y = [e**2 for e in x] plt.plot(x, y) # un plt.plot par courbe à afficher plt.show()
Ajouter un titre et légender les axes
import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5] y = [e**2 for e in x] fig, ax = plt.subplots() plt.plot(x, y) ax.set(xlabel='X', ylabel='X^2', title='y=x^2') plt.show()
Délimiter les axes
Axe des ordonnées (source):
ax.set_ylim(bottom=0)
Axe des abscisses: (source):
ax.set_xlim(20000, 26000)
On peut récupérer les valeurs que Matplotlib avait prévu d'utiliser (source):
ymin, ymax = axes.get_ylim()
Changer l'aspect de la courbe
plt.plot(x, y, 'ro-')
Le troisième paramètre permet de rapidement spécifier l'aspect de la courbe:
r: la courbe sera en rougeo: les points seront représentés par des points (rien par défaut) (liste des symboles disponibles)-: la ligne est continue
Aucun de ces paramètres n'est obligatoire. Voir la documentation pour toutes les possibilités.
Paramètres optionnels:
color: la valeur peut être la lettre d'une couleur, le code hexadécimal, ou un tuple RGB (ou RGBA) avec des valeurs entre 0 et 1linewidth: épaisseur de la ligne (1 est une petite valeur)markersize: taille des points (4 est une petite valeur, la valeur par défaut est 6, elle est dansplt.rcParams['lines.markersize'])alpha: transparence des points (flottant entre 0 et 1)
Légende
plt.plot(x, y, label='curve') ax.legend()
Paramètres facultatifs de ax.legend():
handletextpad: espacement entre le symbole et le texteborderpad: padding de la boîte de légendeborderaxespad: décalage par rapport aux bordures du graphiquehandlelength: longueur du symbolencol: sur combien de colonnes répartir les éléments de la légendeprop={'size': 6}oufontsize: change la taille du texte de la légende (accepte un entier ou les valeursxx-small,x-small,small,medium,large,x-large,xx-largetitle=“Un titre”: donne un titre à la légende (source)
La taille de la police de la légende peut être définie par défaut:
plt.rcParams['legend.fontsize'] = 8
Aligner le titre de la légende (source):
leg = plt.legend(title="Title") leg._legend_box.align = "left" # ou "right"
Échelles logarithmiques
plt.semilogy(t, np.exp(-t/5.0)) plt.semilogx(t, np.sin(2*np.pi*t)) plt.loglog(t, 20*np.exp(-t/10.0), basex=2) # ou plt.plot(...) ax.set_xscale("log", basex=2) ax.set_yscale("log", basey=10)
Placement des légendes des axes
# Axe des abscisses: placement en bas à gauche de l'axe: ax.text(0, -0.025, 'Taille de la matrice', horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) # Axe des ordonnées: placement en haut à gauche de l'axe: ax.text(-0.01, 1, 'Gflops', horizontalalignment='right', verticalalignment='top', transform=ax.transAxes)
Ajouter une ligne horizontale
plt.axhline(y=0.5, color='r', linestyle='-')
Graphe avec deux ordonnées
# courbes de l'axes gauche: comme d'habitude plt.subplots_adjust(right=0.85) # pour éviter que la légende de l'axe à droite se retrouve coupée avec la taille par défaut ax2 = ax.twinx() ax2.set_ylabel("CPU frequency (MHz)") plt.plot(cpu_freqs_x, cpu_freqs, color='r', label="AVG of CPU frequencies")
Pour que toutes les légendes soient dans une même boîte de légende (Source):
lns1 = ax.plot(time, Swdown, '-', label = 'Swdown') lns2 = ax.plot(time, Rn, '-', label = 'Rn') ax2 = ax.twinx() lns3 = ax2.plot(time, temp, '-r', label = 'temp') lns = lns1+lns2+lns3 labs = [l.get_label() for l in lns] ax.legend(lns, labs, loc=0)
Afficher une grille
ax.grid()
Afficher une grille par défaut, sur tous les futurs graphes (source):
plt.rcParams['axes.grid'] = True
La grille se placera par défaut au premier plan, pour éviter ça (source):
ax.set_axisbelow(True) # ou plt.rcParams['axes.axisbelow'] = True
Pour n'afficher qu'un seul axe de la grille (source):
ax.grid(axis='y')
Pour changer le style de la grille suivant les ticks majeurs ou mineurs :
from matplotlib.ticker import AutoMinorLocator ax.grid(axis="y", which="major", linestyle="-") ax.grid(axis="y", which="minor", linestyle="-", alpha=0.2) ax.yaxis.set_minor_locator(AutoMinorLocator())
Obtenir la liste des symboles possibles
La documentation est ici
from matplotlib.lines import Line2D Line2D.markers list(Line2D.markers)
Automatiquement changer le marqueur utilisé
from matplotlib.lines import Line2D from cycler import cycler ax.set_prop_cycle(cycler(color=plt.rcParams["axes.prop_cycle"].by_key()["color"]) + cycler(marker=list(Line2D.markers)[:len(colors)]))
Voir aussi cette doc.
Obtenir la figure actuelle
fig = plt.gcf() # "get current figure"
Obtenir l'axe actuel
ax = plt.gca() # "get current axis"
Ne pas afficher le graphe
Seulement le sauvegarder dans une image.
https://stackoverflow.com/questions/15713279/calling-pylab-savefig-without-display-in-ipython
# Create a new figure, plot into it, then close it so it never gets displayed fig = plt.figure() plt.plot([1,2,3]) plt.savefig('test0.png') plt.close(fig)
Labels des axes
Changer les valeurs affichées sur les axes
plt.xticks(x) plt.xticks(x, " ")
En échelle logarithmique Source:
for axis in [ax.xaxis, ax.yaxis]: formatter = ScalarFormatter() formatter.set_scientific(False) axis.set_major_formatter(formatter)
Cacher les valeurs de l'axe des abscisses (source):
ax.xaxis.set_ticklabels([]) # or: plt.xticks([]) # also hide grid lines
Pivoter les labels des abscisses
plt.plot(x, y) # You can specify a rotation for the tick labels in degrees or with keywords. plt.xticks(x, labels, rotation='vertical') plt.xticks(x, labels, rotation=90) # or just: plt.xticks(rotation="vertical") # or: for tick in ax.get_xticklabels(): tick.set_rotation(45) # Pad margins so that markers don't get clipped by the axes plt.margins(0.2) # Tweak spacing to prevent clipping of tick-labels plt.subplots_adjust(bottom=0.15) plt.show()
Réduire la taille des labels des abscisses
# De façon générale : plt.rc('xtick', labelsize=8) # 8 est petit # Uniquement pour un axe : for label in ax.get_xticklabels(): label.set_fontsize(8)
Forcer l'utilisation d'entiers
from matplotlib.ticker import MaxNLocator ax.xaxis.set_major_locator(MaxNLocator(integer=True)) # ou bien : ax.set_major_locator(MaxNLocator(nbins="auto", steps=[1, 2, 2.5, 5, 10], integer=True)) # AutoLocator utilise les deux premières options.
Types de graphiques
Histogramme
Avec deux séries
width = 0.35 fig, ax = plt.subplots() ax.bar([i - (width / 2) for i in range(nb_x)], y1, width, label='Y1', log=False) ax.bar([i + (width / 2) for i in range(nb_x)], y2, width, label='Y2', log=False) plt.xlabel("X label") plt.ylabel("Y label") plt.title("Titre") plt.xticks(range(nb_x)) # ou plt.xticks(range(nb_x), list_labels, rotation="vertical") plt.legend() plt.show()
Il est possible d'ajouter des barres d'erreur avec les paramètres optionnels xerr et yerr, les valeurs peuvent varier selon les dimensions du tableau passé en argument (voir la doc)
de distribution
N_points = 100000 n_bins = 20 # Generate a normal distribution, center at x=0 and y=5 x = np.random.randn(N_points) y = .4 * x + np.random.randn(100000) + 5 fig, axs = plt.subplots(1, 2, sharey=True, tight_layout=True) # We can set the number of bins with the `bins` kwarg axs[0].hist(x, bins=n_bins) axs[1].hist(y, bins=n_bins, rwidth=0.8) # rwidth permet de laisser de l'espace entre les barres
Échelles logarithmiques
En Y:
axs[0].hist(x, bins=n_bins, log=True)
En X (source):
import numpy as np axs[0].hist(durations, bins=np.logspace(np.log10(1), np.log10(max(durations)), 50), rwidth=0.8) axs[0].set_xscale("log")
Réduire l'espace entre les barres et la bordure du graphique
plt.gca().margins(x=0.01)
Changer le motif des barres
Pour avoir le même motif sur toutes les barres :
ax.bar(..., hatch="+")
Pour avoir un motif différent sur chaque barre :
bars = ax.bar(...) for i in range(len(bars)): bars[i].set_hatch(hatches[i])
Heatmap
Deux heatmaps normalisés avec une unique barre de légende:
CMAP = "binary" vmin = min([min(l) for l in data_coop + data_seq]) vmax = max([max(l) for l in data_coop + data_seq]) norm = colors.Normalize(vmin=vmin, vmax=vmax) fig, axes = plt.subplots(ncols=2) ax1, ax2 = axes im1 = ax1.imshow(data_seq[::-1], cmap=CMAP) im1.set_norm(norm) ax1.set_xticks([i for i in range(0, nb_nodes_seq, 5)]) ax1.set_xticklabels(["dst " + str(i) for i in range(0, nb_nodes_seq, 5)]) ax1.set_yticks([i for i in range(0, nb_nodes_seq, 5)]) ax1.set_yticklabels(["src " + str(i) for i in range(nb_nodes_seq-1, -1, -5)]) ax1.set_title("Seq") im2 = ax2.imshow(data_coop[::-1], cmap=CMAP) im2.set_norm(norm) ax2.set_xticks([i for i in range(0, nb_nodes_coop, 5)]) ax2.set_xticklabels(["dst " + str(i) for i in range(0, nb_nodes_coop, 5)]) ax2.set_yticks([i for i in range(0, nb_nodes_coop, 5)]) ax2.set_yticklabels(["src " + str(i) for i in range(nb_nodes_coop-1, -1, -5)]) ax2.set_title("Coop") c_bar = fig.colorbar(im1, ax=axes.ravel().tolist()) c_bar.set_label(cbar_legend) plt.show()
Placer l'origine en bas à gauche :
ax.imshow(matrix, origin="lower")
Changer les couleurs utilisées (voir la liste ici) :
ax.imshow(matrix, cmap="Grey")
Placer l'axe des abscisses en haut du graphe:
ax1.xaxis.tick_top()
Les fonctions avec juste ticks indiquent où placer des labels, les fonctions ticklabels donnent les labels à affichent.
Pivoter les labels de l'axe des abscisses (voir la ref) :
plt.setp(ax2.get_xticklabels(), rotation=90, ha="right", va="center", rotation_mode="anchor")
Ajouter un titre englobant les deux graphes :
fig.suptitle(title)
Dessiner un rectangle (source) :
import matplotlib.patches as patches ax.add_patch( patches.Rectangle( (5, 6), 1.0, 35.0, edgecolor='red', fill=False, lw=2 ) )
Pour ne pas forcer que les cases soient carrées (source) :
ax.set_aspect("auto")
Pour agrandir la heatmap, il peut être aussi utile de ne pas utiliser tight_layout.
Courbes empilées
https://matplotlib.org/stable/gallery/lines_bars_and_markers/stackplot_demo.html
plt.stackplot(x, [comm_with_comp_bw, bw_with_comm], labels=["Comm bw", "Comp bw"])
Légendes
Indiquer la position de la légende
Source (contient la liste des positions possibles)
plt.legend(loc="upper center")
Placer la légende sous le graphe (source, qui contient aussi d'autres infos pour le placement général des légendes):
plt.legend(loc="upper center", bbox_to_anchor=(0.5, -0.15)) plt.tight_layout()
Créer une légende personnalisée
from matplotlib.lines import Line2D legend_elements = [ Line2D([0], [0], marker='o', label='A'), Line2D([0], [0], marker='+', label='B') # linewidth et linestyle sont aussi dispo ] # handlelength: taille du trait sous le point ax.legend(handles=legend_elements, handletextpad=1, borderpad=1, borderaxespad=1, handlelength=0)
Pour ajouter une légende qui ne correspond à aucune courbe tracée (source):
cholesky_dots = ax.plot(cholesky['Id'], cholesky['gflops'], 'o') vertical_line = lines.Line2D([], [], color='r', marker='|', linestyle='None', markersize=10, markeredgewidth=1.5) plt.legend([vertical_line]+cholesky_dots, ["Trace flush", "POTRF"])
Pour ajouter un élément avec un motif, ajouter cet objet à la liste des handles :
from matplotlib.patches import Patch Patch(hatch="+", label="Label", alpha=0)
Inverser l'ordre des éléments
handles, labels = ax.get_legend_handles_labels() ax.legend(handles[::-1], labels[::-1], title='Line', loc='upper left')
Ajouter une colorbar
Ceci est aussi intéressant si on souhaite que toutes les courbes aient une couleur différente suivant une échelle qui sera la colorbar.
from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list("mylist", [(0, 1, 0), (1, 0, 0)], N=len(y)) # from green to red sm = plt.cm.ScalarMappable(cmap=cm, norm=plt.Normalize(vmin=y[0], vmax=y[-1])) sm._A = [] cbar = fig.colorbar(sm, ticks=y) cbar.set_label("Color of y")
Avoir une échelle logarithmique
from matplotlib.colors import LogNorm sm = plt.cm.ScalarMappable(cmap=cm, norm=LogNorm(vmin=x_size[0], vmax=x_size[-1]))
Une couleur par valeur
from matplotlib.colors import BoundaryNorm sm = plt.cm.ScalarMappable(cmap=cm, norm=BoundaryNorm([1.5 * d for d in data_size], len(data_size)))
Colormap prédéfinies
https://matplotlib.org/examples/color/colormaps_reference.html
cm = plt.get_cmap("jet", len(data_size))
Pour obtenir directement la couleur:
color = cm(i) # 0 <= i < len(data_size)
Spécifier comment placer la colorbar
axins = inset_axes(ax2, width="5%", # width = 5% of parent_bbox width height="100%", # height : 50% loc='lower left', bbox_to_anchor=(1.05, 0., 1, 1), bbox_transform=ax2.transAxes, borderpad=0, ) c_bar = fig.colorbar(im2, cax=axins) c_bar.set_label(cbar_legend)
Définir le centre de la colorbar
Pour les palettes des couleurs divergentes (source) :
from matplotlib.colors import TwoSlopeNorm divnorm = TwoSlopeNorm(vmin=0, vcenter=1) im = ax.imshow(matrix, cmap="seismic", norm=divnorm)
3D
Afficher un nuage de points
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) ax.scatter(x_msg_size, y_comm_size, z_ratio, color=color) ax.set(xlabel="Msg size", ylabel="Comm size", zlabel="Ratio") plt.show()
Ajouter un plan
import numpy as np x_surface, y_surface = np.meshgrid(np.arange(min(x_msg_size), max(x_msg_size)), np.arange(min(y_comm_size), max(y_comm_size))) ax.plot_surface(x_surface, y_surface, np.full_like(x_surface, 1), alpha=0.2)
Sauvegarder le graphique
plt.savefig("name.png")
À placer avant plt.show().
Pour ne pas avoir de larges bordures blanches, ajouter le paramètre bbox_inches=“tight”.
Préciser la taille
Pour agrandir, notamment:
fig.set_size_inches(15, 9) plt.savefig("name.png", dpi=100)
Pour connaître la taille utilisée par défaut:
plt.rcParams["figure.figsize"]
Barres d'erreur
Quand les barres d'erreur sont différentes pour chaque point:
for i in range(len(errors)): ax.errorbar(x[i], y[i], yerr=[[y[i] - errors[i][0], [errors[i][-1] - y[i]]], elinewidth=0.8, capsize=5, ecolor='k')
Les valeurs données pour les barres d'erreurs sont les distances au point décrit par les premiers paramètres de la fonction.
Paramètres:
capsize: longueur des tirets aux extrémités des barres d'erreurecolor: couleur de la barre d'erreurelinewidth: épaisseur de la barre d'erreurfmt: marqueur du point décrit par les premiers paramètres de la fonction, en l'absence, le point n'est pas affiché
Pour une barre d'erreur constante:
ax.errorbar(X, Y, yerr=Y_error)
Ici X et Y sont les listes qui contiennent les coordonnées des points et Y_error est une constante indiquant l'erreur relative.
Changer le style d'une barre d'erreur
Pour que le trait de barre d'erreur soit pointillé:
(_, _, barline) = ax.errorbar(...) barline[0].set_linestyle('--')
Zone d'erreur
y_error_coop_inf = [y_flops_coop[i] - (y_error_coop[i]/2) for i in range(len(results_coop))] y_error_coop_sup = [y_flops_coop[i] + (y_error_coop[i]/2) for i in range(len(results_seq))] plt.plot(x_matrix_size, y_flops_coop, 'o-', color='r', label='Coop ') plt.fill_between(x_matrix_size, y_error_coop_inf, y_error_coop_sup, alpha=0.3, color='r')
Sous-graphes
Alignés sur un axe
import numpy as np import matplotlib.pyplot as plt x1 = np.linspace(0.0, 5.0) x2 = np.linspace(0.0, 2.0) y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) y2 = np.cos(2 * np.pi * x2) plt.subplot(2, 1, 1) plt.plot(x1, y1, 'o-') plt.title('A tale of 2 subplots') plt.ylabel('Damped oscillation') plt.subplot(2, 1, 2) plt.plot(x2, y2, '.-') plt.xlabel('time (s)') plt.ylabel('Undamped') plt.show()
Le triplet de paramètres pour subplot, correspond, dans l'ordre:
- nombre de lignes
- nombre de colonnes
- index du graphe actuel dans cette matrice
Partager les axes
ax1 = plt.subplot(311) plt.plot(t, s1) plt.setp(ax1.get_xticklabels(), fontsize=6) # share x only ax2 = plt.subplot(312, sharex=ax1) plt.plot(t, s2) # make these tick labels invisible plt.setp(ax2.get_xticklabels(), visible=False)
Mosaïque de graphes
fig, axs = plt.subplots(4, 4, sharex=True, sharey=True, gridspec_kw={'wspace':0.05, 'hspace':0.27}) axs[2,3].plot(...)
Les paramètres dans gridpsec_kw permettent de préciser l'espacement entre les graphes.
On peut définir la largeur relative de chaque graphe : gridspec_kw={“width_ratios”: width_ratios} (width_ratios est une liste de taille le nombre de graphes horizontalement et le graphe i aura la largeur width_ratios[i]/sum(width_ratios)).
Pour ne garder les valeurs sur les axes des ordonnées que sur les graphiques de la première colonne :
axs[i,j].label_outer()
S'il y a un deuxième axe des ordonnées à droite, pour faire la même chose :
if i != 3: ax_right.yaxis.set_tick_params(which="both", labelright=False)
Pour enlever toutes les légendes des axes et mettre une unique légende pour tous les graphes :
# pour tous les i, j : axs[i,j].set_xlabel(None) axs[i,j].set_ylabel(None) fig.text(0.5, 0.07, "Axe des X", va='center', ha='center', fontsize=17) fig.text(0.09, 0.5, "Axe des Y", va='center', ha='center', rotation='vertical', fontsize=17)
Pour n'afficher qu'une légende, sous tous les graphes :
handles_left, labels_left = axs[0,0].get_legend_handles_labels() fig.legend(handles_left, labels_left, loc='lower left', bbox_to_anchor=(0.11, -0.05))
Pour ne pas afficher certains graphes dans la mosaïque (source) :
fig.delaxes(axs[i, j])
Pour définir le titre de chaque sous-graphe :
axes[j_msg_size,i_comm_size].set_title("Titre", fontdict={"fontsize": 9})
Un graphe dans un autre
# faire le graphe parent # sous-graphe: ax = plt.axes([.2, .6, .2, .2]) # faire le sous-graphe plt.show()
Changer les tailles de tous les textes
SMALL_SIZE = 11 MEDIUM_SIZE = 12 plt.rc('font', size=SMALL_SIZE) # controls default text sizes plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels plt.rc('xtick', labelsize=SMALL_SIZE) # fontsize of the tick labels plt.rc('ytick', labelsize=SMALL_SIZE) # fontsize of the tick labels plt.rc('legend', fontsize=SMALL_SIZE) # legend fontsize plt.rc('figure', titlesize=MEDIUM_SIZE) # fontsize of the figure title
Couleurs
Récupérer la couleur d'une courbe
r = plt.plot(x, y, 'o-') color = r[0].get_color()
Obtenir la palette de couleurs du thème
Donne la liste des couleurs utilisées par Matplotlib (Source):
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
Couleur de fond sur des zones en arrière-plan
ax.axvspan(x_start, x_end, facecolor="0.9", zorder=0.1)
Le zorder permet de mettre la zone à l'arrière-plan du graphe. La même fonction en horizontal: axhspan.
Générer de nombreuses couleurs
Pour que la couleur suivante soit bien distincte de la précédente.
from matplotlib import colors data_colors = [colors.hsv_to_rgb([(i * 0.618033988749895) % 1.0, 0.7, 1]) for i in range(len(stacked_data))]
Backends
Définir le backend, pour éviter que Matplotlib n'essaie de lancer quelquechose d'interactif et plante car il n'arrive pas à se connecter au serveur X:
MPLBACKEND=agg python simple_plot.py
Lister les backends disponibles
import matplotlib print(matplotlib.rcsetup.interactive_bk) print(matplotlib.rcsetup.non_interactive_bk) print(matplotlib.rcsetup.all_backends)
Obtenir le backend actuellement sélectionné
print(matplotlib.get_backend()


