|
|
## C) Atelier 2 : un graphique avec un 2e axe des y ; les objets d'une figure
|
|
|
## C) Atelier 2 : un graphique avec 3 variables d'unités différentes : 2e axe des y, subplots ; les objets d'une figure
|
|
|
Cet objectif ne semble pas hyper ambitieux, et vous trouverez des tutos pour réaliser facilement cette figure, et pourtant la syntaxe peut sembler étrange... Nous allons passer par un peu de théorie pour comprendre ce qui se passe et afficher une légende correcte.
|
|
|
|
|
|
### C1) le fichier d'un TD de bilan hydrologique avec 4 colonnes : date, T, pluie, Q
|
... | ... | @@ -45,7 +45,7 @@ plt.suptitle("En utilisant les possibilités de pandas") |
|
|
plt.legend()
|
|
|
plt.show()
|
|
|
```
|
|
|
|
|
|
[Graphique P,T, Q avec pandas](https://gitlab.irstea.fr/christine.poulard/atelier-matplotlib/-/blob/master/illustrations/Figure_2_graphique_pandas.png)
|
|
|
La bonne nouvelle : l'outil zoom montre que l'affichage des étiquettes de date est correct quel que soit le niveau de zoom, contrairement à la première expérience.
|
|
|
On utilisera dans la suite des instructions qui donnent ce rendu même en dehors de Pandas.
|
|
|
La mauvaise nouvelle : les trois variables, qui s'expriment dans des unités différentes, sont toutes les 3 tracées dans le même repère. Cela permet de voir les données rapidement, mais évidemment la mise en forme n'est pas du tout satisfaisante pour un rapport. On va donc retravailler cela dans la suite.
|
... | ... | @@ -54,11 +54,77 @@ La mauvaise nouvelle : les trois variables, qui s'expriment dans des unités dif |
|
|
|
|
|
On vous a donné du code déjà écrit, comme ce que vous pourriez trouver en ligne.
|
|
|
Ca marche, même si c'est plutôt moche, donc n'hésitez pas à mettre en forme pour vous exercer.
|
|
|
Mais par contre, la syntaxe peut paraître vraiment bizarre.
|
|
|
[Figure mise en forme, chaque variable a son axe](https://gitlab.irstea.fr/christine.poulard/atelier-matplotlib/-/blob/master/illustrations/Figure_3_graphique_PTQ_subplots.png)
|
|
|
|
|
|
De prime abord, certaines syntaxes peuvent paraître vraiment bizarres.
|
|
|
Pour comprendre, on n'échappera pas à un peu de théorie ; certains sites expliquent très bien la structure des figures, et cela aide vraiment à progresser et à s'approprier les notions.
|
|
|
|
|
|
Voir les diapos.
|
|
|
|
|
|
De retour, on a donc sur ce graphique deux notions importantes et quelques mot-clés intéressants :
|
|
|
* **la notion de subplot** qui permet de définir plusieurs vignettes sur une même figure ; cette architecture est plutôt bien décrite dans les tutoriels (vois aussi gridspec). On insistera ici sur l'argument "sharex=True" ) qui permet de coupler les graphiques : on zoome en même temps sur les deux. (même chose avec "sharey = True".)
|
|
|
* **la notion d'ax** qui est en fait un **système d'axes" ; la méthode un_axe.twinx() permet de créer un autre système d'axes qui partage le même axe des x que un_axe (et idem avec twiny pour l'axe des y). C'est en fait une information moins bien mise en avant, les tutoriels qui l'expliquent bien annoncent en introduction que le nom "ax" est assez mal choisi et prête à confusion... et que l'on peut avoir vraiment des difficultés à assimiler les procédures tant que l'on n'a pas compris ce que l'on manipule. |
|
|
\ No newline at end of file |
|
|
``` python
|
|
|
# on découpe la figure en deux subplots, sur 1 colonne et 2 lignes.
|
|
|
# La méthode subplots renvoie un objet figure et un tuple de deux subplots
|
|
|
# sharex = True lie l'axe des x des deux subplots : on zoome sur les 2 en même temps
|
|
|
# on va nommer la figure fig et les subplots ax_pluie et ax_q
|
|
|
fig, (ax_pluie, ax_q) = plt.subplots(ncols=1, nrows=2, sharex=True)
|
|
|
fig.subplots_adjust(bottom=0.15) # marge en bas
|
|
|
fig.suptitle("Forçages en haut, réponse du bassin en bas") #titre de la figure
|
|
|
|
|
|
# première variable : LA PLUIE, bien sûr dans le système ax_pluie
|
|
|
etiquette_pluie = nom_colonnes[1]
|
|
|
ax_pluie.set_ylabel(etiquette_pluie, color='lightblue') # on agit sur l'axe ax_pluie
|
|
|
#on va utiliser des lignes verticales, ce n'est pas forcément la meilleure solution ni la meilleure couleur
|
|
|
#il faut transformer la colonne numéro 1 en objet numpy que mpl comprend, avec la méthode tolist()
|
|
|
ax_pluie.vlines(x=liste_dates, ymin=0, ymax=DF_TD4[etiquette_pluie].tolist(), color='lightblue', lw=2,
|
|
|
label=etiquette_pluie)
|
|
|
ax_pluie.invert_yaxis() # pour respecter une convention ; peut se faire aussi via ylim
|
|
|
|
|
|
# 2e variable : LA TEMPERATURE, dans la même vignette la pluie en partageant son axe des x
|
|
|
ax_t = ax_pluie.twinx() # nouvel "ax" partageant l'axe des x de ax_pluie
|
|
|
etiquette_temperatures = nom_colonnes[0]
|
|
|
ax_t.set_ylabel(etiquette_temperatures)
|
|
|
ax_t.plot(liste_dates, DF_TD4[etiquette_temperatures].tolist(), marker='*', color='orange', ls=':',
|
|
|
label=etiquette_temperatures)
|
|
|
# todo : le tracé d'une variable à pas de temps fixe est plus correct avec step
|
|
|
# ax_t.step(liste_dates, DF_TD4[etiquette_temperatures].tolist(), marker='None', color='orange', ls=':',
|
|
|
# label=etiquette_temperatures + " (step)", where="post")
|
|
|
|
|
|
# 3e variable : Le DEBIT, dans l'autre vignette
|
|
|
etiquette_debit = nom_colonnes[2]
|
|
|
ax_q.set_ylabel(etiquette_debit, color='blue')
|
|
|
ax_q.plot(liste_dates, DF_TD4[etiquette_debit].tolist(), marker='>', color='blue', ls=':', label=etiquette_debit)
|
|
|
```
|
|
|
|
|
|
|
|
|
Les messages essentiels sont :
|
|
|
* même si le mot-clé "plt" permet en général de déclencher les bonnes instructions (façon de faire inspirée de matlab) , il est plus rigoureux d'utiliser la syntaxe orientée objet. Il est possible de nommer les objets (fig, ax, et même les courbes si besoin) ce qui facilite les actions, et donne davantage de contrôle (fig.legend() n'est pas tout à fait la même chose que ax.legend()).
|
|
|
Attention, les méthodes de la la classe Axes sont parfois différentes : on va écrire par exemple:
|
|
|
plt.xlabel() → ax.set_xlabel() ; plt.ylabel() → ax.set_ylabel()
|
|
|
plt.xlim() → ax.set_xlim() ; plt.ylim() → ax.set_ylim()
|
|
|
plt.title() → ax.set_title()
|
|
|
["matplotlib gotchas" dans le livre de JVanderPlas](https://www.oreilly.com/library/view/python-data-science/9781491912126/ch04.html)
|
|
|
|
|
|
On met donc en pratique sur ce graphique deux notions importantes :
|
|
|
* **la notion de subplot** qui permet de définir plusieurs vignettes sur une même figure ; cette architecture est plutôt bien décrite dans les tutoriels (vois aussi gridspec pour définir les proportions). L'argument "sharex=True" ) qui permet de coupler les graphiques : on zoome en même temps sur les deux. (même chose avec "sharey = True".)
|
|
|
* **la notion d'ax** qui est en fait une **aire sur laquelle on peut tracer des points selon un système de coordonnées**, que l'on se contentera d'appeler **système d'axes".
|
|
|
Quand on a compris que "un_axe" est un système d'axes, il est plus facile de décoder la méthode twinx : l'instruction un_axe.twinx() permet de créer un autre système d'axes qui partage le même axe des x que un_axe (et idem avec twiny pour l'axe des y).
|
|
|
Heureusement, plusieurs tutoriels mettent l'accent sur cette notion, en disant que le nom de classe Axes, avec le nom d'instance habituel "ax", est sans doute mal choisi. Grâce à ces ressources, notamment python-simple, on comprend ce que l'on manipule et il est ensuite plus facile d'assimiler les procédures.
|
|
|
|
|
|
|
|
|
### C4)La légende, toute une histoire.
|
|
|
Dans le code, on a utilisé une méthode legend appliquée à l'objet fig. Ainsi, cette légende regroupe les symboles et étiquettes de l'ensemble des plots de la figure. Les diapos s'étendent davantage sur ses arguments.
|
|
|
``` python
|
|
|
fig.legend(bbox_to_anchor=(1, 0), loc="lower right",
|
|
|
bbox_transform=fig.transFigure, ncol=4)
|
|
|
```
|
|
|
Pour se rendre compte de la différence, mettez cette instruction en commentaire (faire précéder de # et essayez les syntaxes suivantes :
|
|
|
``` python
|
|
|
plt.legend()
|
|
|
```
|
|
|
|
|
|
``` python
|
|
|
ax_pluie.legend()
|
|
|
ax_t.legend()
|
|
|
ax_q.legend()
|
|
|
|
|
|
``` |
|
|
\ No newline at end of file |