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