]> git.immae.eu Git - perso/Denise/oms.git/blame - trace_courbe.py
messages du changelog
[perso/Denise/oms.git] / trace_courbe.py
CommitLineData
5679dfd0
DL
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
d03279e7 3from configuration import CONFIG
a680b2f7
DL
4import gestionOMS as oms
5import gestion_unites as u
438ef56d 6from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python
a680b2f7 7from gestion_erreurs import debug, erreur, warning
3d7da80a
DL
8from calculs_extrapole import calcule_donnee_extrapolee, calcule_age_extrapole, interpole_lineaire, interpole_lineaire_ordonnee, formate_resultat_donnee, formate_resultat_age, formate_interpole, formate_extrapole
9
685a5f75 10from numpy import arange
3d7da80a 11
fd69b6b5 12
5679dfd0
DL
13import matplotlib.pyplot as plt
14
cf0d4c8c
DL
15# Essentiellement, la fonction qui trace la courbe, mais on y trouve également les fonctions d'extrapolation.
16# Ainsi que les calculs additionnels.
d03279e7
DL
17
18
cf0d4c8c 19def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err):
a680b2f7
DL
20 """ conf est le dictionnaire de config. l_jours et l_poids les listes des temps (en jours) et de données
21 (donc pas forcément du poids)
22 typedonnee est le type de données (voir CONFIG["liste_typedonnees"]
23 liste_err la liste des erreurs à compléter (voir gestion_erreurs))
cf0d4c8c
DL
24 Renvoie la figure tracée, et les calculs additionnels sont mis sous forme de chaîne dans la liste
25 liste_extracalculs"""
a680b2f7 26 debug("debut de cree_figure. Config : "+str(conf),liste_err)
fd69b6b5 27 try:
a680b2f7 28 liste_data_labels_p,liste_data_labels_z = oms.renvoie_liste_labels(conf,CONFIG["liste_data_choisie_p"],CONFIG["liste_data_choisie_z"],liste_err)
fd69b6b5
DL
29 except:
30 erreur("bug avec liste data labels",liste_err)
31 return ""
32
a680b2f7
DL
33 ######################## Gestion des bornes #############################
34 # y a-t-il un maxi saisi par l'utilisateur ?
fd69b6b5 35 if conf["maxi"] ==0:
8b5845ff 36 # Est-ce qu'on a donné un maxi quand même (car même échelle) ?
8b5845ff 37 if conf["non_sauve"].get("maxi",0) == 0:
8b5845ff 38 jour_maxi = calcule_max_graphique(l_jours)
5679dfd0 39 else:
8b5845ff 40 jour_maxi = conf["non_sauve"]["maxi"]+1
5679dfd0
DL
41 else:
42 jour_maxi = conf["maxi"]+1
438ef56d
DL
43
44 # Si on cherche à extrapoler au-delà
45 if conf["non_sauve"]["calculextradata_type"] == typedonnee and conf["non_sauve"]["calculextradata_age"]>jour_maxi:
46 jour_maxi = int(conf["non_sauve"]["calculextradata_age"]) +1
248d9504 47
9e4c51c7 48 # On s'assure que c'est bien compris dans les bornes
9e4c51c7 49 jour_maxi = max(CONFIG["jours_mini_courbe"],min(jour_maxi,CONFIG["jours_maxi_courbe"]))
a680b2f7 50 debug("cree_figure : gestion du jour max : "+str(jour_maxi),liste_err)
5679dfd0 51
a680b2f7 52 ##################### Gestion des unités ###############################
8b5845ff
DL
53 # si l'unité n'est pas précisée, ni en "non sauvé" ni par l'utilisateur
54 if conf["unite"] == "" and conf["non_sauve"].get("unite","") == "":
a680b2f7 55 unite = u.choix_unite(jour_maxi)
8b5845ff
DL
56 debug("Unité non précisée, on choisit "+unite,liste_err)
57 elif conf["unite"] != "":
58 unite = conf["unite"]
59 else:
60 unite = conf["non_sauve"]["unite"]
61
a680b2f7 62 ##################### Gestion de la prématurité #######################"
b5ac625b
DL
63 prema = int(convertit_jours_vers_python(conf["prematurite"],liste_err))
64 ## Gestion des prémas, deux cas :
65 # Si agecorrige est oui, alors on veut juste soustraire la valeur de préma
66 # à toutes les données.
67 # Si agecorrige est non, alors on veut ajouter la valeur de préma aux courbes de référence.
a680b2f7 68 debug("Prématurité : "+str(prema)+" age corrigé : "+conf["agecorrige"],liste_err)
b5ac625b
DL
69 if prema>0 and conf["agecorrige"] == "oui":
70 l_jours = [j-prema for j in l_jours]
71 jour_maxi = jour_maxi - prema
c2fe511b 72
a680b2f7
DL
73
74 ###################### Conversion des unités ###########################""
75 l_jours_conv = u.convertit_tableau(l_jours,unite,liste_err)
5679dfd0 76 # Attention, comme les jours commencent à partir de 0, faut enlever 1 pour avoir la borne...
a680b2f7 77 age_maxi = u.convertitunite(jour_maxi-1,unite,liste_err)
5679dfd0 78
b5ac625b 79 debug("cree_figure : conversion des unités ok : "+str(l_jours_conv),liste_err)
fd69b6b5 80
a680b2f7 81 #####################" Courbes OMS et titre ######################################"
8b5845ff 82 titre = "Courbe de "+typedonnee+" OMS"
5679dfd0
DL
83 if conf["typecourbe"] == "P":
84 # percentiles
85 liste_data_labels = liste_data_labels_p
86 if conf["sexe"] == "M":
8b5845ff 87 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_garcon"]#f_poids_perc_garcon
5679dfd0 88 titre += " (percentiles, garçon)"
a46e1269 89 elif conf["sexe"] == "F":
8b5845ff 90 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_fille"]
5679dfd0 91 titre += " (percentiles, fille)"
a46e1269 92 else:
8b5845ff 93 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_mixte"]
a46e1269 94 titre += " (percentiles)"
5679dfd0
DL
95 elif conf["typecourbe"] == "Z":
96 liste_data_labels = liste_data_labels_z
d03279e7 97 if conf["sexe"] == "M":
8b5845ff 98 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_garcon"]
5679dfd0 99 titre += " (moyenne et écarts-types, garçon)"
a46e1269 100 elif conf["sexe"] == "F":
8b5845ff 101 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_fille"]
5679dfd0 102 titre += " (moyenne et écarts-types, fille)"
a46e1269 103 else:
8b5845ff 104 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_mixte"]
a46e1269 105 titre += " (moyenne et écarts-types)"
fd69b6b5 106 else:
248d9504
DL
107 erreur("Type de courbe invalide"+conf["typecourbe"],liste_err)
108 return ""
248d9504 109
5679dfd0
DL
110 # Si y'a un nom on met "courbe de machin"
111 if conf["nom"] !="":
112 titre += " de " +conf["nom"]
b5ac625b 113
b5ac625b
DL
114 if prema>0:
115 titre+= ", préma de "+conf["prematurite"]
116 if conf["agecorrige"] == "oui":
117 titre+=" (courbe en âge corrigé)"
118 else:
119 titre+=" (courbe en âge réel, données OMS décalées)"
120
a680b2f7 121 #debug("cree_figure : géré le type de courbe ok. Liste des data labels : "+str(liste_data_labels),liste_err)
b5ac625b 122 debug("Fichier d'où extraire les données : "+fichier_oms,liste_err)
a680b2f7 123
b5ac625b 124
5679dfd0 125 #### On extrait les données des courbes, et on convertit les jours dans l'unité voulues
a46e1269 126 try:
a680b2f7 127 t = oms.lire_fichier_csv(fichier_oms)
a46e1269 128 except:
a680b2f7 129 erreur("cree_figure : Impossible d'ouvrir le fichier "+fichier_oms, liste_err)
248d9504 130 return ""
5679dfd0 131
a680b2f7 132 debug("cree_figure : Conversion des données OMS à la bonne unité",liste_err)
b5ac625b 133 try:
a680b2f7 134 coljour= (oms.extraire_colonne(t,0,jour_maxi))
b5ac625b
DL
135 if prema>0 and conf["agecorrige"] != "oui":
136 coljour = [j + prema for j in coljour]
a680b2f7 137 coljour = u.convertit_tableau(coljour,unite,liste_err)
248d9504
DL
138 except:
139 erreur("Problème à la conversion du tableau OMS. jour_maxi = "+str(jour_maxi)+" unite = "+unite,liste_err)
140 return ""
141
a680b2f7 142 ##################### Création de la figure et du graphique ###################
248d9504 143 debug("cree_figure : prête à créer la figure",liste_err)
b5ac625b
DL
144 #### La figure, params
145
915e90bb
DL
146 fig = plt.figure(num=None, figsize=(conf["largeur"], conf["hauteur"]), dpi=100, facecolor=conf["couleurs"]["fond"])
147 plt.rcParams['axes.facecolor'] = conf["couleurs"]["fond"]
148 plt.rcParams['axes.edgecolor']= conf["couleurs"]["cadretxt"]
149 plt.rcParams['xtick.color'] = conf["couleurs"]["cadretxt"]
150 plt.rcParams['ytick.color'] = conf["couleurs"]["cadretxt"]
151 plt.rcParams['grid.color'] = conf["couleurs"]["grille"]
152 plt.rcParams['legend.edgecolor'] = conf["couleurs"]["grille"]
685a5f75 153 ax = plt.axes()
fd69b6b5 154
a680b2f7 155 ###################### Tracé des différentes courbes
c2fe511b 156 #Tracé des courbes OMS
5679dfd0 157 for (i,label,couleur) in liste_data_labels:
a680b2f7 158 ax.plot(coljour,oms.extraire_colonne(t,i,jour_maxi),label=label,color=couleur)
fd69b6b5 159
248d9504 160 debug("cree_figure : tracé des courbes OMS ok",liste_err)
a680b2f7 161
b5ac625b 162 ### Tracé pour de bon
5679dfd0 163 if l_jours != []:
685a5f75 164 ax.plot(l_jours_conv,l_poids,label=conf["nom"],color=conf["couleurs"]["cadretxt"],marker='o')
b5ac625b 165 debug("Tracé de la courbe enfant, avec les jours "+str(l_jours_conv),liste_err)
c2fe511b
DL
166
167 #### extrapolatios éventuelles
cf0d4c8c
DL
168 # a-t-on demndé des calculs ?
169 jextrapole = conf["non_sauve"]["prolongercourbes"] == "oui"
170 # Est-ce qu'on a demandé un calcul sur cette donnée ?
171 print()
172 for calextra in CONFIG["extradata"]:
173 jextrapole = jextrapole or conf["non_sauve"][calextra+"_type"] == typedonnee
174
175 #print(jextrapole)
3d7da80a 176 ############################## Là où on extrapole ################################
cf0d4c8c
DL
177 if jextrapole:
178 try:
179 debug("Il faut extrapoler les courbes !", liste_err)
180 # Prendre l'ensemble des dates "source"
181 # print(conf["non_sauve"]["nbdataextra"])
182 if conf["non_sauve"]["nbextradata"] == 0:
183 sources_extrap = l_jours
184 sources_extrap_data = l_poids
185 else:
186 sources_extrap = l_jours[-conf["non_sauve"]["nbextradata"]:] # les derniers jours
187 sources_extrap_data = l_poids[-conf["non_sauve"]["nbextradata"]:]
188
189 debug("On extrapole sur les jours : "+str(sources_extrap), liste_err)
190
3d7da80a 191 # On récupère toutes les données extrapolées
cf0d4c8c
DL
192 dates_extrapole, donnees_extrapole = prolongecourbe(t, sources_extrap, sources_extrap_data, conf["typecourbe"], liste_err)
193 debug("données extrapolées !", liste_err)
194 #debug(str(dates_extrapole[0:10])+str(donnees_extrapole[0:10]), liste_err)
195
196 # QUe veut-on maintenant sur ces données extrapolées ?
197 # Afficher la courbe
198 if conf["non_sauve"]["prolongercourbes"] == "oui":
199 # On va prendre les extrapolations de la dernière donnée jusqu'à l fin du graphe
200 debut_extr = int(l_jours[-conf["non_sauve"]["nbextradata"]])
201 i_debut_extr = dates_extrapole.index(debut_extr)
202 i_fin_extr = dates_extrapole.index(jour_maxi)
203 # Voilà ce qu'on veut tracer
204 dates_extrapole_trace = dates_extrapole[i_debut_extr:i_fin_extr+1]
205 donnees_extrapole_trace = donnees_extrapole[i_debut_extr:i_fin_extr+1]
206 dates_extrapole_trace = u.convertit_tableau(dates_extrapole_trace,unite,liste_err)
207
208 # tracé des données extrapolées
209 plt.plot(dates_extrapole_trace, donnees_extrapole_trace,color=conf["couleurs"]["cadretxt"], linestyle=(0, (5,7)), marker=None)
210 debug("Tracé de la courbe extrapolée ok", liste_err)
211
3d7da80a 212 ### Calculer une donnée à l'âge x
cf0d4c8c 213 if conf["non_sauve"]["calculextradata_type"] == typedonnee:
3d7da80a
DL
214 # On essaie l'interpolation
215 r = interpole_lineaire(l_jours,l_poids,conf["non_sauve"]["calculextradata_age"], liste_err)
216 if r==-1:
217 # ça sera donc une extrapolation
218 r = calcule_donnee_extrapolee(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextradata_age"], liste_err)
219 message=formate_extrapole(conf["non_sauve"]["nbextradata"])
220# if == 0:
221# message+="l'ensemble des données"
222# else:
223# message+="les "+str(conf["non_sauve"]["nbextradata"])+" dernière"+met_s(conf["non_sauve"]["nbextradata"])+" données"
224 else:
225 message=formate_interpole()
226
227 texte = formate_resultat_donnee(conf["non_sauve"]["calculextradata_age"], r, typedonnee, message, liste_err)
228 debug("calcul de la donnée extrapolée : "+texte, liste_err)
229 if texte!="":
230 liste_extracalculs.append(texte)
cf0d4c8c 231 print(liste_extracalculs)
3d7da80a
DL
232 # Ajouter le trait ?
233 if conf["non_sauve"]["calculextradata_trace"] == "oui":
234 dessine_guides(conf["non_sauve"]["calculextradata_age"], r, conf["couleurs"]["cadretxt"], unite, ax, liste_err)
cf0d4c8c 235
3d7da80a 236 ### Calculer un âge où on atteint cette donnée
cf0d4c8c 237 if conf["non_sauve"]["calculextratemps_type"] == typedonnee:
3d7da80a
DL
238 # interpolation
239 r = interpole_lineaire_ordonnee(l_jours,l_poids,conf["non_sauve"]["calculextratemps_val"], liste_err)
240 if r==-1:
241 # ça sera donc une extrapolation
242 r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], liste_err)
243 message=formate_extrapole(conf["non_sauve"]["nbextradata"])
244 else:
245 message=formate_interpole()
246
247 texte = formate_resultat_age(r, conf["non_sauve"]["calculextratemps_val"], typedonnee, message, liste_err)
248
249 #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
250 if texte!="":
251 liste_extracalculs.append(texte)
cf0d4c8c 252 print(liste_extracalculs)
3d7da80a
DL
253 # Ajouter le trait ?
254 if conf["non_sauve"]["calculextratemps_trace"]:
255 dessine_guides(r, conf["non_sauve"]["calculextratemps_val"], conf["couleurs"]["cadretxt"], unite, ax, liste_err)
cf0d4c8c
DL
256
257 except:
258 warning("Des problèmes pour extrapoler...", liste_err)
c2fe511b
DL
259
260 else:
261 debug("On ne trace pas de courbe enfant", liste_err)
262
a680b2f7
DL
263 ###################" Gestion de l'échelle #####################
264 debug("Courbes tracées. Il n'y a plus qu'à gérer l'échelle", liste_err)
685a5f75 265 ### échelle à régler
a680b2f7
DL
266
267 # On extrait la valeur min et la valeur max des poids des courbes OMS et des données
268 (colonne_min,_,_) = liste_data_labels[-1]
269 (colonne_max,_,_) = liste_data_labels[0]
685a5f75 270
a680b2f7
DL
271 # poids max OMS
272 poids_min = min(oms.extraire_colonne(t,colonne_min,jour_maxi))
273 poids_max = max(oms.extraire_colonne(t,colonne_max,jour_maxi))
274 if l_jours != []:
275 poids_min = min(min(l_poids),poids_min)
276 # Pour le poids max, voir la dernière valeur du tableau
277 i = 0
278 while i<len(l_jours) and l_jours[i]<jour_maxi:
279 i=i+1
280 poids_max = max(max(l_poids[0:i+1]),poids_max)
281 # On ajuste un peu ces min et max
282 # min : valeur min -1kg
283 poids_min = max(0,poids_min-1)
284 #max : +5%
285 poids_max = poids_max * 1.05
286
287
288 # Grille custom ?
685a5f75 289 if conf["non_sauve"]["grilleamelio"] == "oui":
a680b2f7
DL
290 debug("On a choisi la grille plus jolie", liste_err)
291 pas=u.choix_echelle_data(typedonnee, poids_max)
685a5f75
DL
292 # data_min_arrondie
293 minechelle = int(poids_min/pas[0])*pas[0]
294
295 debug("pas choisis pour l'échelle en y : "+str(pas), liste_err)
296 echellemajeure = arange(minechelle, poids_max, pas[0])
297
298 if pas[1] >0:
299 echellemineure = arange(minechelle, poids_max, pas[1])
300 else:
301 echellemineure = []
302
303 ax.set_yticks(echellemajeure, minor=False)
304 ax.set_yticks(echellemineure, minor=True)
305
306 # échelle en temps
a680b2f7 307 pas=u.choix_echelle_temps(unite, age_maxi)
685a5f75
DL
308 debug("pas choisis pour l'échelle en x : "+str(pas), liste_err)
309
310 echellemajeure = arange(0,age_maxi, pas[0])
311 if pas[1] >0:
312 echellemineure = arange(0,age_maxi, pas[1])
313 else:
314 echellemineure = []
315 ax.set_xticks(echellemajeure, minor=False)
316 ax.set_xticks(echellemineure, minor=True)
317
a680b2f7 318 ################################# Aspect du graphique
685a5f75
DL
319
320 debug("On commende la déco du graphique", liste_err)
321
322 # La grille
323 ax.grid(conf["grille"]=="oui")
324 ax.grid(conf["grille"] == "oui", which="minor", linestyle="--")
325
326
8b5845ff
DL
327 plt.xlabel("Âge en "+unite,color=conf["couleurs"]["cadretxt"])
328 plt.ylabel(typedonnee.capitalize()+" en "+CONFIG["unites_typedonnees"][typedonnee],color=conf["couleurs"]["cadretxt"])
915e90bb 329 plt.title(titre,color=conf["couleurs"]["cadretxt"])
c2fe511b
DL
330 if l_jours_conv == []:
331 plt.axis([0,age_maxi, poids_min, poids_max])
332 else:
333 plt.axis([min(0,l_jours_conv[0]),age_maxi,poids_min,poids_max])
c2fe511b 334
5679dfd0
DL
335
336 if conf['legende']=="oui":
fd69b6b5 337 legende = plt.legend(loc=conf['positionlegende'])
915e90bb 338 plt.setp(legende.get_texts(), color=conf["couleurs"]["cadretxt"])
685a5f75 339
5679dfd0
DL
340
341 fig.tight_layout()
fd69b6b5 342
a680b2f7 343 debug("Fin de cree_figure, tout va bien.", liste_err)
c2fe511b
DL
344 return fig
345
346
347
685a5f75 348
a680b2f7 349######################################## Pour extrapoler la courbe
685a5f75 350
cf0d4c8c
DL
351def prolongecourbe(tableauOMS, dates, donnees, typecourbe, liste_err):
352 """ tableauOMS est le ableau des données OMS. dates et donnees sont les dates (jours)
353 et les données d'où on extrapole. On calcule toutes les dates comme des sauvages.
354 On renvoie la liste des jours totale et la liste des data_totales
c2fe511b
DL
355 (tableaux de jours)
356 typecourbe est P ou Z. Pour P il faut commencer à regarder à l'indice 4, pour Z
357 à l'indice 1
cf0d4c8c
DL
358 On renvoie [],[] si pas pu extrapoler. """
359 # les lignes OMS correspondant aux dates données
360 lignesoms = [tableauOMS[int(date)] for date in dates]
361 debug("prolongecourbe : Lignes OMS :"+str(lignesoms)+" valeur de données : "+str(donnees), liste_err)
c2fe511b 362
c2fe511b
DL
363
364
cf0d4c8c
DL
365 # Principe : on cherche dans quel intervalle de "colonnes" on se situe.
366 # On va donc regarder pour chaque donnée entre quels i on se situe,et après
367 # prendre le plus grand intervalle.
368 # Numéros de colonnes d'où on part. Pour la fin c'est forcément longueur-1
c2fe511b
DL
369 if typecourbe == "P":
370 idep=4
371 else:
372 idep = 1
cf0d4c8c
DL
373
374 liste_indices = []
375 for k in range(len(dates)):
376 i= idep
377 ligne = lignesoms[k]
378 while i<len(ligne) and ligne[i]<donnees[k]:
379 i+=1
380 debug("prolongecourbe : on a trouvé la valeur de i : "+str(i),liste_err)
381 if i>=len(ligne):
382 warning("prolongation de courbe : pas réussi... donnée trop haute !", liste_err)
383 return [],[]
384 if i==idep:
385 warning("prolongation de courbe : pas réussi... donnée trop basse !", liste_err)
386 return [],[]
387 liste_indices.append(i)
388 imin=min(liste_indices) -1
389 imax=max(liste_indices)
390 debug("Les données se situent dans les indices : "+str(imin)+", "+str(imax),liste_err)
391 # Maintenant on doit trouver les coeffs : on se situe en coeff * l[imin]+ (1-coeff)*ligne[imax]
392 # Et faire la moyenne de ces coeffs
393 total = 0
394 for k in range(len(dates)):
395 ligne = lignesoms[k]
396 donnee = donnees[k]
397 total += (donnee - ligne[imax])/(ligne[imin] - ligne[imax])
398 #print(k)
399 coeff_moyen = total/len(dates)
400
401 debug("Coeff moyen calculé : "+str(coeff_moyen), liste_err)
c2fe511b 402
cf0d4c8c 403 # On utilisera la même chose pour les nouvelle donnee
c2fe511b
DL
404
405 # extrapolations
cf0d4c8c
DL
406 nouvdates =oms.extraire_colonne(tableauOMS,0) # On sort tout.
407 #print(nouvdates)
c2fe511b
DL
408 nouvdonnees = []
409 for j in nouvdates:
cf0d4c8c
DL
410 ligne2 = tableauOMS[int(j)]
411 nouvdonnees.append(coeff_moyen*ligne2[imin]+ (1-coeff_moyen)*ligne2[imax])
c2fe511b 412
3d7da80a
DL
413 return nouvdates,nouvdonnees
414
415
416def dessine_guides(t, data, couleur, unite, ax, liste_err):
417 """ dessine deux lignes, horizontales et verticales qui vont "vers" la courbe
418 jusqu'aux points (t, data). En pointillés et avec un point dessus."""
419 debug("Début de dessine_guides"+str(t)+", "+str(data), liste_err)
420 t_conv = u.convertitunite(t,unite,liste_err)
421 ax.vlines(t_conv, 0, data, colors=couleur, linestyles="dashed")
422 ax.hlines(data, 0, t_conv, color=couleur, linestyles="dashed")
423 ax.plot([t_conv], [data], color=couleur, marker="*", ms=13)