]> git.immae.eu Git - perso/Denise/oms.git/blob - trace_courbe.py
extrapolation des courbes et calculs associés
[perso/Denise/oms.git] / trace_courbe.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 from configuration import CONFIG
4 import gestionOMS as oms
5 import gestion_unites as u
6 from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python, convertit_age_vers_texte
7 from gestion_erreurs import debug, erreur, warning
8 from numpy import arange
9 from calculs_extrapole import calcule_donnee_extrapolee, calcule_age_extrapole
10
11 import matplotlib.pyplot as plt
12
13 # Essentiellement, la fonction qui trace la courbe, mais on y trouve également les fonctions d'extrapolation.
14 # Ainsi que les calculs additionnels.
15
16
17 def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err):
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))
22 Renvoie la figure tracée, et les calculs additionnels sont mis sous forme de chaîne dans la liste
23 liste_extracalculs"""
24 debug("debut de cree_figure. Config : "+str(conf),liste_err)
25 try:
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)
27 except:
28 erreur("bug avec liste data labels",liste_err)
29 return ""
30
31 ######################## Gestion des bornes #############################
32 # y a-t-il un maxi saisi par l'utilisateur ?
33 if conf["maxi"] ==0:
34 # Est-ce qu'on a donné un maxi quand même (car même échelle) ?
35 if conf["non_sauve"].get("maxi",0) == 0:
36 jour_maxi = calcule_max_graphique(l_jours)
37 else:
38 jour_maxi = conf["non_sauve"]["maxi"]+1
39 else:
40 jour_maxi = conf["maxi"]+1
41
42 # On s'assure que c'est bien compris dans les bornes
43 jour_maxi = max(CONFIG["jours_mini_courbe"],min(jour_maxi,CONFIG["jours_maxi_courbe"]))
44 debug("cree_figure : gestion du jour max : "+str(jour_maxi),liste_err)
45
46 ##################### Gestion des unités ###############################
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","") == "":
49 unite = u.choix_unite(jour_maxi)
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
56 ##################### Gestion de la prématurité #######################"
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.
62 debug("Prématurité : "+str(prema)+" age corrigé : "+conf["agecorrige"],liste_err)
63 if prema>0 and conf["agecorrige"] == "oui":
64 l_jours = [j-prema for j in l_jours]
65 jour_maxi = jour_maxi - prema
66
67
68 ###################### Conversion des unités ###########################""
69 l_jours_conv = u.convertit_tableau(l_jours,unite,liste_err)
70 # Attention, comme les jours commencent à partir de 0, faut enlever 1 pour avoir la borne...
71 age_maxi = u.convertitunite(jour_maxi-1,unite,liste_err)
72
73 debug("cree_figure : conversion des unités ok : "+str(l_jours_conv),liste_err)
74
75 #####################" Courbes OMS et titre ######################################"
76 titre = "Courbe de "+typedonnee+" OMS"
77 if conf["typecourbe"] == "P":
78 # percentiles
79 liste_data_labels = liste_data_labels_p
80 if conf["sexe"] == "M":
81 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_garcon"]#f_poids_perc_garcon
82 titre += " (percentiles, garçon)"
83 elif conf["sexe"] == "F":
84 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_fille"]
85 titre += " (percentiles, fille)"
86 else:
87 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["perc_mixte"]
88 titre += " (percentiles)"
89 elif conf["typecourbe"] == "Z":
90 liste_data_labels = liste_data_labels_z
91 if conf["sexe"] == "M":
92 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_garcon"]
93 titre += " (moyenne et écarts-types, garçon)"
94 elif conf["sexe"] == "F":
95 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_fille"]
96 titre += " (moyenne et écarts-types, fille)"
97 else:
98 fichier_oms = CONFIG["fichiersOMS"][typedonnee]["z_mixte"]
99 titre += " (moyenne et écarts-types)"
100 else:
101 erreur("Type de courbe invalide"+conf["typecourbe"],liste_err)
102 return ""
103
104 # Si y'a un nom on met "courbe de machin"
105 if conf["nom"] !="":
106 titre += " de " +conf["nom"]
107
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
115 #debug("cree_figure : géré le type de courbe ok. Liste des data labels : "+str(liste_data_labels),liste_err)
116 debug("Fichier d'où extraire les données : "+fichier_oms,liste_err)
117
118
119 #### On extrait les données des courbes, et on convertit les jours dans l'unité voulues
120 try:
121 t = oms.lire_fichier_csv(fichier_oms)
122 except:
123 erreur("cree_figure : Impossible d'ouvrir le fichier "+fichier_oms, liste_err)
124 return ""
125
126 debug("cree_figure : Conversion des données OMS à la bonne unité",liste_err)
127 try:
128 coljour= (oms.extraire_colonne(t,0,jour_maxi))
129 if prema>0 and conf["agecorrige"] != "oui":
130 coljour = [j + prema for j in coljour]
131 coljour = u.convertit_tableau(coljour,unite,liste_err)
132 except:
133 erreur("Problème à la conversion du tableau OMS. jour_maxi = "+str(jour_maxi)+" unite = "+unite,liste_err)
134 return ""
135
136 ##################### Création de la figure et du graphique ###################
137 debug("cree_figure : prête à créer la figure",liste_err)
138 #### La figure, params
139
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"]
147 ax = plt.axes()
148
149 ###################### Tracé des différentes courbes
150 #Tracé des courbes OMS
151 for (i,label,couleur) in liste_data_labels:
152 ax.plot(coljour,oms.extraire_colonne(t,i,jour_maxi),label=label,color=couleur)
153
154 debug("cree_figure : tracé des courbes OMS ok",liste_err)
155
156 ### Tracé pour de bon
157 if l_jours != []:
158 ax.plot(l_jours_conv,l_poids,label=conf["nom"],color=conf["couleurs"]["cadretxt"],marker='o')
159 debug("Tracé de la courbe enfant, avec les jours "+str(l_jours_conv),liste_err)
160
161 #### extrapolatios éventuelles
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)
220
221 else:
222 debug("On ne trace pas de courbe enfant", liste_err)
223
224 ###################" Gestion de l'échelle #####################
225 debug("Courbes tracées. Il n'y a plus qu'à gérer l'échelle", liste_err)
226 ### échelle à régler
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]
231
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 ?
250 if conf["non_sauve"]["grilleamelio"] == "oui":
251 debug("On a choisi la grille plus jolie", liste_err)
252 pas=u.choix_echelle_data(typedonnee, poids_max)
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
268 pas=u.choix_echelle_temps(unite, age_maxi)
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
279 ################################# Aspect du graphique
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
288 plt.xlabel("Âge en "+unite,color=conf["couleurs"]["cadretxt"])
289 plt.ylabel(typedonnee.capitalize()+" en "+CONFIG["unites_typedonnees"][typedonnee],color=conf["couleurs"]["cadretxt"])
290 plt.title(titre,color=conf["couleurs"]["cadretxt"])
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])
295
296
297 if conf['legende']=="oui":
298 legende = plt.legend(loc=conf['positionlegende'])
299 plt.setp(legende.get_texts(), color=conf["couleurs"]["cadretxt"])
300
301
302 fig.tight_layout()
303
304 debug("Fin de cree_figure, tout va bien.", liste_err)
305 return fig
306
307
308
309
310 ######################################## Pour extrapoler la courbe
311
312 def 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
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
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)
323
324
325
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
330 if typecourbe == "P":
331 idep=4
332 else:
333 idep = 1
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)
363
364 # On utilisera la même chose pour les nouvelle donnee
365
366 # extrapolations
367 nouvdates =oms.extraire_colonne(tableauOMS,0) # On sort tout.
368 #print(nouvdates)
369 nouvdonnees = []
370 for j in nouvdates:
371 ligne2 = tableauOMS[int(j)]
372 nouvdonnees.append(coeff_moyen*ligne2[imin]+ (1-coeff_moyen)*ligne2[imax])
373
374 return nouvdates,nouvdonnees