... | ... | @@ -22,7 +22,10 @@ Le même problème existe pour les images intégrées dans une interface, il fau |
|
|
|
|
|
### à propos des codes :
|
|
|
|
|
|
**ProbaCruesMaxAn_SurNannees.py** : c'est le code le plus simple, qui traite d'une seule fonction qui tient en une ligne et qui dépend de deux paramètres, N (nombre d'années) et T (période de retour, inverse d'une fréquence). Sa courbe est tracée avec "plot". La figure est munie de deux sliders qui font varier N et T, et qui activent tous les deux la même fonction de mise à jour du tracé : recalcul et remplacement des vecteurs x et y de la courbe (méthode set_data). Le titre change aussi.
|
|
|
**ProbaCruesMaxAn_SurNannees.py** : c'est le code le plus simple, qui traite d'une seule fonction qui tient en une ligne et qui dépend de deux paramètres, N (nombre d'années) et T (période de retour, inverse d'une fréquence). Sa courbe est tracée avec "plot" ; on représente les probas par des points, sans ligne pour les relier, car ce sont des probas discrètes :
|
|
|
La figure est munie de deux sliders qui font varier N et T, et qui activent tous les deux la même fonction de mise à jour du tracé : recalcul et remplacement des vecteurs x et y de la courbe (méthode set_data). Le titre change aussi.
|
|
|
Les "sliders" sont intéressants pour faire varier "en direct", et créer presque des animations en direct, mais il est difficile de viser une valeur en particulier. Le widget "textBox" serait meilleur pour saisir des valeurs.
|
|
|
***ProbaCruesMaxAn_SurNannees_stairs** est une autre version qui propose un graphique en escalier, intéressant car on doit jouer avec les Locator et Formatter pour que l'étiquette se place au milieu de chaque marche d'escalier.
|
|
|
|
|
|
**Chegodaiev.py** : c'est ce code qui est commenté ici. C'est une petite démonstration des fréquence empiriques, avec la formule de Tchégodaiev et une formule plus générique paramétrée par a et b, dont les valeurs sont modifiables avec des "sliders". Une case à cocher permet de changer l'abscisse de fréquence en période de retour.
|
|
|
Il est utilisable, mais il reste quelques maladresses à rectifier, dans les définitions des xlim par exemple ou le choix des méthodes de tracé pour Tchgodaiev (les vlines allant de 0 à la valeur max ne sont pas forcément le meilleur choix, et surtout ils sont bien plus compliqués à mettre à jour !). Comme il a aussi une vocation d'exercice, on a utilisé le widget "checkbutton" même si le rendu est catastrophique... Un simple bouton serait mieux.
|
... | ... | @@ -32,6 +35,8 @@ Il reprend les bases de Chegodaiev.py (en corrigeant quelques maladresses) pour |
|
|
|
|
|
|
|
|
# CODE **ProbaCruesMaxAn_SurNannees.py**
|
|
|
Il s'agit de probabilités discrètes, calculées sur des valeurs de p entiers, avec deux paramètres N et T que l'on souhaite faire varier.
|
|
|
On peut donc représenter ces probabilités en fonction de p soit pas **plot** avec des markers non reliés, soit par une fonction de type "step". On va présenter ici le premier cas car les courbes tracées avec **plot** sont plus faciles à modifier, et on présentera à la fin une variante avec une graphique en escalier.
|
|
|
|
|
|
## 1. La fonction et ses paramètres
|
|
|
On rappelle que la période de retour T est l’inverse de la fréquence au dépassement : T= 1/f.
|
... | ... | @@ -77,7 +82,6 @@ p, liste_probas_exactement, liste_probas_auplus = calcul_courbes(n, 1 / T) |
|
|
Deux sliders vont permettre ensuite de modifier N et T ; on les utilise ensuite pour calculer et tracer des résultats via une fonction ; il faut donc que la modification soit répercutée dans tout le code. Cela va nous permettre de manipuler la notion de portée des variables.
|
|
|
|
|
|
|
|
|
|
|
|
## 2. La figure
|
|
|
La figure est divisée en une grille de 1 colonne et 4 lignes, dont une ligne plus haute pour le graphique, les ratios sont précisés avec l'argument gridspec_kw, par mots-clés (KeyWord) : à la clé 'height_ratios' on associe un vecteur avec les proportions . Deux autres lignes vont recevoir un curseur, pour éviter les superpositions de texte on a défini entre le graphique et les sliders une ligne "vide"
|
|
|
|
... | ... | @@ -106,8 +110,8 @@ plt.show() |
|
|
En haut, on a donc une vignette "ax" dans laquelle on va tracer deux courbes avec "plot", avec les résultats qui viennent d'être calculés. On nomme le premier objet retourné par la fonction "plot", puisqu'on aura besoin d'agir sur lui : on remplacera les données (vecteurs des x et vecteurs des y) après chaque action sur les sliders.
|
|
|
|
|
|
``` python
|
|
|
courbe_exactement, = ax.plot(range(p + 1), liste_probas_exactement, label="exactement p crues")
|
|
|
courbe_cumul, = ax.plot(range(p + 1), liste_probas_auplus, label="p crues ou moins de p")
|
|
|
courbe_exactement, = ax.plot(range(p + 1), liste_probas_exactement, label="exactement p crues",ls='None', marker='o', markersize=10))
|
|
|
courbe_cumul, = ax.plot(range(p + 1), liste_probas_auplus, label="p crues ou moins de p",ls='None', marker='o', markersize=10)).
|
|
|
```
|
|
|
|
|
|
### définition des sliders et liaison avec une fonction "par widget"mise à jour de la courbe"
|
... | ... | @@ -179,6 +183,75 @@ fig.canvas.draw_idle() force les objets modifiés à se retracer. |
|
|
#### remarque sur la portée des variables
|
|
|
Ni fig ni ax ni les courbes n'ont été passés en argument, pourtant ils sont connus depuis l'intérieur de la fonction. Comme c'est un petit code, on sait que l'on va manipuler les bons objets, il n'y a pas d'ambiguité. Dans la fonction, on ne pourrait pas écraser l'un ou l'autre objet, par contre si on applique sur eux une méthode (suptitle, set_data, set_xlim...) la modification de leurs attributs correspondant est répercutée.
|
|
|
|
|
|
## Variante avec une courbe "en escalier"
|
|
|
|
|
|
On a réécrit un code mais en gardant la possibilité de représenter la courbe soit avec **plot** soit avec un escalier en utilisant **hlines** et **fillbetween**.
|
|
|
Pour passer d'une représentation à l'autre, il faut changer la valeur du booléen TRACE_PAR_PLOT (on rappelle que les valeurs du booléen sont False et True, avec une majuscule).
|
|
|
|
|
|
### fonction "stair_plot"
|
|
|
En attendant que la fonction **stairs** soit implémentée dans la version stable, on a repris une solution proposée sur un forum
|
|
|
|
|
|
``` python
|
|
|
|
|
|
def stair_plot(x,y, couleur):
|
|
|
x = [*x, x[-1]] # duplicate last to draw last line
|
|
|
ax.hlines(y, xmin=x[:-1], xmax=x[1:], linewidth=3, color=couleur)
|
|
|
# fill under line : y with duplicated last value to draw last step as well ; hide edge
|
|
|
ax.fill_between(x, [*y, y[-1]],
|
|
|
step='post', facecolor=couleur, edgecolor=None, alpha=0.5)
|
|
|
|
|
|
```
|
|
|
|
|
|
### premier tracé
|
|
|
On distingue donc les deux cas.
|
|
|
Or remarque que dans le cas d'un **plot** on nomme les objets renvoyés car on va agir dessus.
|
|
|
Dans le cas d'un tracé en marches d'escalier, on va simplement effacer et retracer, donc on ne nomme pas.
|
|
|
Au passage, on en profite pour choisir quelle fonction update_graphique sera liée aux Sliders : update_graphique_plot est équivalente à la fonction de la version simple, tandis que update_graphique_stairs traite le cas d'un graphique en escalier.
|
|
|
|
|
|
|
|
|
``` python
|
|
|
if TRACE_PAR_PLOT:
|
|
|
courbe_exactement, = ax.plot(range(p + 1), liste_probas_exactement, label="exactement p crues",ls='None', marker='o', markersize=10)
|
|
|
courbe_cumul, = ax.plot(range(p + 1), liste_probas_auplus, label="p crues ou moins de p", ls='None', marker='o', markersize=10)
|
|
|
update_graphique = update_graphique_plot
|
|
|
else:
|
|
|
stair_plot(range(p + 1),liste_probas_exactement, couleur="blue")
|
|
|
stair_plot(range(p + 1),liste_probas_auplus, couleur="sienna")
|
|
|
update_graphique = update_graphique_stairs
|
|
|
|
|
|
```
|
|
|
### fontion update, cas graphique_stairs
|
|
|
|
|
|
Les calculs sont les mêmes, mais au lieu de modifier une courbe on efface le contenu de la vignette avec "clear" et on retrace.
|
|
|
Plus intéressant : on veut que les étiquettes de p soient au milieu des classes. Pour cela, on utilise les Locator et Formattor :
|
|
|
- si p> 15 on place les ticks de 5 en 5 en commençant par 0.5 et les ticks secondaires de 1 en 1 depuis 0.5
|
|
|
- si p<= 15 on place les ticks de 1 en 1 en commençant par 0.5 et on enlève les ticks secondaires
|
|
|
- évidemment, on ne veut pas que les étiquettes soient "0.5, 1,5..." ; donc on les formatte au format entier.
|
|
|
|
|
|
|
|
|
``` python
|
|
|
def update_graphique_stairs(val):
|
|
|
global n, T
|
|
|
n = int(slider_n.val)
|
|
|
T = int(slider_T.val)
|
|
|
|
|
|
p, liste_probas_exactement, liste_probas_auplus = calcul_courbes(n, 1 / T)
|
|
|
fig.suptitle(f"Démo : probabilité d'avoir p crues > T={T}ans en {n} années")
|
|
|
|
|
|
ax.clear()
|
|
|
stair_plot(range(p + 1), liste_probas_exactement, couleur="blue")
|
|
|
stair_plot(range(p + 1), liste_probas_auplus, couleur="sienna")
|
|
|
|
|
|
ax.set_xlim(0, p + 1)
|
|
|
if p > 15:
|
|
|
ax.xaxis.set_major_locator(plt.FixedLocator([0.5 + i for i in range(0, p, 5)]))
|
|
|
ax.xaxis.set_minor_locator(plt.FixedLocator([0.5 + i for i in range(0, p, 1)]))
|
|
|
else:
|
|
|
ax.xaxis.set_major_locator(plt.FixedLocator([0.5 + i for i in range(0, p, 1)]))
|
|
|
ax.xaxis.set_minor_locator(plt.NullLocator())
|
|
|
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter("%d"))
|
|
|
fig.canvas.draw_idle()
|
|
|
```
|
|
|
|
|
|
|
|
|
# CODE **Chegodaiev.py**
|
... | ... | |