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 calculs_extrapole
import calcule_donnee_extrapolee
, calcule_age_extrapole
, interpole_lineaire
, interpole_lineaire_ordonnee
, formate_resultat_donnee
, formate_resultat_age
, formate_interpole
, formate_extrapole
10 from numpy
import arange
13 import matplotlib
.pyplot
as plt
15 # Essentiellement, la fonction qui trace la courbe, mais on y trouve également les fonctions d'extrapolation.
16 # Ainsi que les calculs additionnels.
19 def cree_figure(conf
,l_jours
,l_poids
,typedonnee
,liste_extracalculs
, liste_err
):
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))
24 Renvoie la figure tracée, et les calculs additionnels sont mis sous forme de chaîne dans la liste
26 debug("debut de cree_figure. Config : "+str(conf
),liste_err
)
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
)
30 erreur("bug avec liste data labels",liste_err
)
33 ######################## Gestion des bornes #############################
34 # y a-t-il un maxi saisi par l'utilisateur ?
36 # Est-ce qu'on a donné un maxi quand même (car même échelle) ?
37 if conf
["non_sauve"].get("maxi",0) == 0:
38 jour_maxi
= calcule_max_graphique(l_jours
)
40 jour_maxi
= conf
["non_sauve"]["maxi"]+1
42 jour_maxi
= conf
["maxi"]+1
44 # On s'assure que c'est bien compris dans les bornes
45 jour_maxi
= max(CONFIG
["jours_mini_courbe"],min(jour_maxi
,CONFIG
["jours_maxi_courbe"]))
46 debug("cree_figure : gestion du jour max : "+str(jour_maxi
),liste_err
)
48 ##################### Gestion des unités ###############################
49 # si l'unité n'est pas précisée, ni en "non sauvé" ni par l'utilisateur
50 if conf
["unite"] == "" and conf
["non_sauve"].get("unite","") == "":
51 unite
= u
.choix_unite(jour_maxi
)
52 debug("Unité non précisée, on choisit "+unite
,liste_err
)
53 elif conf
["unite"] != "":
56 unite
= conf
["non_sauve"]["unite"]
58 ##################### Gestion de la prématurité #######################"
59 prema
= int(convertit_jours_vers_python(conf
["prematurite"],liste_err
))
60 ## Gestion des prémas, deux cas :
61 # Si agecorrige est oui, alors on veut juste soustraire la valeur de préma
62 # à toutes les données.
63 # Si agecorrige est non, alors on veut ajouter la valeur de préma aux courbes de référence.
64 debug("Prématurité : "+str(prema
)+" age corrigé : "+conf
["agecorrige"],liste_err
)
65 if prema
>0 and conf
["agecorrige"] == "oui":
66 l_jours
= [j
-prema
for j
in l_jours
]
67 jour_maxi
= jour_maxi
- prema
70 ###################### Conversion des unités ###########################""
71 l_jours_conv
= u
.convertit_tableau(l_jours
,unite
,liste_err
)
72 # Attention, comme les jours commencent à partir de 0, faut enlever 1 pour avoir la borne...
73 age_maxi
= u
.convertitunite(jour_maxi
-1,unite
,liste_err
)
75 debug("cree_figure : conversion des unités ok : "+str(l_jours_conv
),liste_err
)
77 #####################" Courbes OMS et titre ######################################"
78 titre
= "Courbe de "+typedonnee
+" OMS"
79 if conf
["typecourbe"] == "P":
81 liste_data_labels
= liste_data_labels_p
82 if conf
["sexe"] == "M":
83 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_garcon"]#f_poids_perc_garcon
84 titre
+= " (percentiles, garçon)"
85 elif conf
["sexe"] == "F":
86 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_fille"]
87 titre
+= " (percentiles, fille)"
89 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_mixte"]
90 titre
+= " (percentiles)"
91 elif conf
["typecourbe"] == "Z":
92 liste_data_labels
= liste_data_labels_z
93 if conf
["sexe"] == "M":
94 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_garcon"]
95 titre
+= " (moyenne et écarts-types, garçon)"
96 elif conf
["sexe"] == "F":
97 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_fille"]
98 titre
+= " (moyenne et écarts-types, fille)"
100 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_mixte"]
101 titre
+= " (moyenne et écarts-types)"
103 erreur("Type de courbe invalide"+conf
["typecourbe"],liste_err
)
106 # Si y'a un nom on met "courbe de machin"
108 titre
+= " de " +conf
["nom"]
111 titre
+= ", préma de "+conf
["prematurite"]
112 if conf
["agecorrige"] == "oui":
113 titre
+=" (courbe en âge corrigé)"
115 titre
+=" (courbe en âge réel, données OMS décalées)"
117 #debug("cree_figure : géré le type de courbe ok. Liste des data labels : "+str(liste_data_labels),liste_err)
118 debug("Fichier d'où extraire les données : "+fichier_oms
,liste_err
)
121 #### On extrait les données des courbes, et on convertit les jours dans l'unité voulues
123 t
= oms
.lire_fichier_csv(fichier_oms
)
125 erreur("cree_figure : Impossible d'ouvrir le fichier "+fichier_oms
, liste_err
)
128 debug("cree_figure : Conversion des données OMS à la bonne unité",liste_err
)
130 coljour
= (oms
.extraire_colonne(t
,0,jour_maxi
))
131 if prema
>0 and conf
["agecorrige"] != "oui":
132 coljour
= [j
+ prema
for j
in coljour
]
133 coljour
= u
.convertit_tableau(coljour
,unite
,liste_err
)
135 erreur("Problème à la conversion du tableau OMS. jour_maxi = "+str(jour_maxi
)+" unite = "+unite
,liste_err
)
138 ##################### Création de la figure et du graphique ###################
139 debug("cree_figure : prête à créer la figure",liste_err
)
140 #### La figure, params
142 fig
= plt
.figure(num
=None, figsize
=(conf
["largeur"], conf
["hauteur"]), dpi
=100, facecolor
=conf
["couleurs"]["fond"])
143 plt
.rcParams
['axes.facecolor'] = conf
["couleurs"]["fond"]
144 plt
.rcParams
['axes.edgecolor']= conf
["couleurs"]["cadretxt"]
145 plt
.rcParams
['xtick.color'] = conf
["couleurs"]["cadretxt"]
146 plt
.rcParams
['ytick.color'] = conf
["couleurs"]["cadretxt"]
147 plt
.rcParams
['grid.color'] = conf
["couleurs"]["grille"]
148 plt
.rcParams
['legend.edgecolor'] = conf
["couleurs"]["grille"]
151 ###################### Tracé des différentes courbes
152 #Tracé des courbes OMS
153 for (i
,label
,couleur
) in liste_data_labels
:
154 ax
.plot(coljour
,oms
.extraire_colonne(t
,i
,jour_maxi
),label
=label
,color
=couleur
)
156 debug("cree_figure : tracé des courbes OMS ok",liste_err
)
158 ### Tracé pour de bon
160 ax
.plot(l_jours_conv
,l_poids
,label
=conf
["nom"],color
=conf
["couleurs"]["cadretxt"],marker
='o')
161 debug("Tracé de la courbe enfant, avec les jours "+str(l_jours_conv
),liste_err
)
163 #### extrapolatios éventuelles
164 # a-t-on demndé des calculs ?
165 jextrapole
= conf
["non_sauve"]["prolongercourbes"] == "oui"
166 # Est-ce qu'on a demandé un calcul sur cette donnée ?
168 for calextra
in CONFIG
["extradata"]:
169 jextrapole
= jextrapole
or conf
["non_sauve"][calextra
+"_type"] == typedonnee
172 ############################## Là où on extrapole ################################
175 debug("Il faut extrapoler les courbes !", liste_err
)
176 # Prendre l'ensemble des dates "source"
177 # print(conf["non_sauve"]["nbdataextra"])
178 if conf
["non_sauve"]["nbextradata"] == 0:
179 sources_extrap
= l_jours
180 sources_extrap_data
= l_poids
182 sources_extrap
= l_jours
[-conf
["non_sauve"]["nbextradata"]:] # les derniers jours
183 sources_extrap_data
= l_poids
[-conf
["non_sauve"]["nbextradata"]:]
185 debug("On extrapole sur les jours : "+str(sources_extrap
), liste_err
)
187 # On récupère toutes les données extrapolées
188 dates_extrapole
, donnees_extrapole
= prolongecourbe(t
, sources_extrap
, sources_extrap_data
, conf
["typecourbe"], liste_err
)
189 debug("données extrapolées !", liste_err
)
190 #debug(str(dates_extrapole[0:10])+str(donnees_extrapole[0:10]), liste_err)
192 # QUe veut-on maintenant sur ces données extrapolées ?
194 if conf
["non_sauve"]["prolongercourbes"] == "oui":
195 # On va prendre les extrapolations de la dernière donnée jusqu'à l fin du graphe
196 debut_extr
= int(l_jours
[-conf
["non_sauve"]["nbextradata"]])
197 i_debut_extr
= dates_extrapole
.index(debut_extr
)
198 i_fin_extr
= dates_extrapole
.index(jour_maxi
)
199 # Voilà ce qu'on veut tracer
200 dates_extrapole_trace
= dates_extrapole
[i_debut_extr
:i_fin_extr
+1]
201 donnees_extrapole_trace
= donnees_extrapole
[i_debut_extr
:i_fin_extr
+1]
202 dates_extrapole_trace
= u
.convertit_tableau(dates_extrapole_trace
,unite
,liste_err
)
204 # tracé des données extrapolées
205 plt
.plot(dates_extrapole_trace
, donnees_extrapole_trace
,color
=conf
["couleurs"]["cadretxt"], linestyle
=(0, (5,7)), marker
=None)
206 debug("Tracé de la courbe extrapolée ok", liste_err
)
208 ### Calculer une donnée à l'âge x
209 if conf
["non_sauve"]["calculextradata_type"] == typedonnee
:
210 # On essaie l'interpolation
211 r
= interpole_lineaire(l_jours
,l_poids
,conf
["non_sauve"]["calculextradata_age"], liste_err
)
213 # ça sera donc une extrapolation
214 r
= calcule_donnee_extrapolee(dates_extrapole
, donnees_extrapole
, conf
["non_sauve"]["calculextradata_age"], liste_err
)
215 message
=formate_extrapole(conf
["non_sauve"]["nbextradata"])
217 # message+="l'ensemble des données"
219 # message+="les "+str(conf["non_sauve"]["nbextradata"])+" dernière"+met_s(conf["non_sauve"]["nbextradata"])+" données"
221 message
=formate_interpole()
223 texte
= formate_resultat_donnee(conf
["non_sauve"]["calculextradata_age"], r
, typedonnee
, message
, liste_err
)
224 debug("calcul de la donnée extrapolée : "+texte
, liste_err
)
226 liste_extracalculs
.append(texte
)
227 print(liste_extracalculs
)
229 if conf
["non_sauve"]["calculextradata_trace"] == "oui":
230 dessine_guides(conf
["non_sauve"]["calculextradata_age"], r
, conf
["couleurs"]["cadretxt"], unite
, ax
, liste_err
)
232 ### Calculer un âge où on atteint cette donnée
233 if conf
["non_sauve"]["calculextratemps_type"] == typedonnee
:
235 r
= interpole_lineaire_ordonnee(l_jours
,l_poids
,conf
["non_sauve"]["calculextratemps_val"], liste_err
)
237 # ça sera donc une extrapolation
238 r
= calcule_age_extrapole(dates_extrapole
, donnees_extrapole
, conf
["non_sauve"]["calculextratemps_val"], liste_err
)
239 message
=formate_extrapole(conf
["non_sauve"]["nbextradata"])
241 message
=formate_interpole()
243 texte
= formate_resultat_age(r
, conf
["non_sauve"]["calculextratemps_val"], typedonnee
, message
, liste_err
)
245 #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
247 liste_extracalculs
.append(texte
)
248 print(liste_extracalculs
)
250 if conf
["non_sauve"]["calculextratemps_trace"]:
251 dessine_guides(r
, conf
["non_sauve"]["calculextratemps_val"], conf
["couleurs"]["cadretxt"], unite
, ax
, liste_err
)
254 warning("Des problèmes pour extrapoler...", liste_err
)
257 debug("On ne trace pas de courbe enfant", liste_err
)
259 ###################" Gestion de l'échelle #####################
260 debug("Courbes tracées. Il n'y a plus qu'à gérer l'échelle", liste_err
)
263 # On extrait la valeur min et la valeur max des poids des courbes OMS et des données
264 (colonne_min
,_
,_
) = liste_data_labels
[-1]
265 (colonne_max
,_
,_
) = liste_data_labels
[0]
268 poids_min
= min(oms
.extraire_colonne(t
,colonne_min
,jour_maxi
))
269 poids_max
= max(oms
.extraire_colonne(t
,colonne_max
,jour_maxi
))
271 poids_min
= min(min(l_poids
),poids_min
)
272 # Pour le poids max, voir la dernière valeur du tableau
274 while i
<len(l_jours
) and l_jours
[i
]<jour_maxi
:
276 poids_max
= max(max(l_poids
[0:i
+1]),poids_max
)
277 # On ajuste un peu ces min et max
278 # min : valeur min -1kg
279 poids_min
= max(0,poids_min
-1)
281 poids_max
= poids_max
* 1.05
285 if conf
["non_sauve"]["grilleamelio"] == "oui":
286 debug("On a choisi la grille plus jolie", liste_err
)
287 pas
=u
.choix_echelle_data(typedonnee
, poids_max
)
289 minechelle
= int(poids_min
/pas
[0])*pas
[0]
291 debug("pas choisis pour l'échelle en y : "+str(pas
), liste_err
)
292 echellemajeure
= arange(minechelle
, poids_max
, pas
[0])
295 echellemineure
= arange(minechelle
, poids_max
, pas
[1])
299 ax
.set_yticks(echellemajeure
, minor
=False)
300 ax
.set_yticks(echellemineure
, minor
=True)
303 pas
=u
.choix_echelle_temps(unite
, age_maxi
)
304 debug("pas choisis pour l'échelle en x : "+str(pas
), liste_err
)
306 echellemajeure
= arange(0,age_maxi
, pas
[0])
308 echellemineure
= arange(0,age_maxi
, pas
[1])
311 ax
.set_xticks(echellemajeure
, minor
=False)
312 ax
.set_xticks(echellemineure
, minor
=True)
314 ################################# Aspect du graphique
316 debug("On commende la déco du graphique", liste_err
)
319 ax
.grid(conf
["grille"]=="oui")
320 ax
.grid(conf
["grille"] == "oui", which
="minor", linestyle
="--")
323 plt
.xlabel("Âge en "+unite
,color
=conf
["couleurs"]["cadretxt"])
324 plt
.ylabel(typedonnee
.capitalize()+" en "+CONFIG
["unites_typedonnees"][typedonnee
],color
=conf
["couleurs"]["cadretxt"])
325 plt
.title(titre
,color
=conf
["couleurs"]["cadretxt"])
326 if l_jours_conv
== []:
327 plt
.axis([0,age_maxi
, poids_min
, poids_max
])
329 plt
.axis([min(0,l_jours_conv
[0]),age_maxi
,poids_min
,poids_max
])
332 if conf
['legende']=="oui":
333 legende
= plt
.legend(loc
=conf
['positionlegende'])
334 plt
.setp(legende
.get_texts(), color
=conf
["couleurs"]["cadretxt"])
339 debug("Fin de cree_figure, tout va bien.", liste_err
)
345 ######################################## Pour extrapoler la courbe
347 def prolongecourbe(tableauOMS
, dates
, donnees
, typecourbe
, liste_err
):
348 """ tableauOMS est le ableau des données OMS. dates et donnees sont les dates (jours)
349 et les données d'où on extrapole. On calcule toutes les dates comme des sauvages.
350 On renvoie la liste des jours totale et la liste des data_totales
352 typecourbe est P ou Z. Pour P il faut commencer à regarder à l'indice 4, pour Z
354 On renvoie [],[] si pas pu extrapoler. """
355 # les lignes OMS correspondant aux dates données
356 lignesoms
= [tableauOMS
[int(date
)] for date
in dates
]
357 debug("prolongecourbe : Lignes OMS :"+str(lignesoms
)+" valeur de données : "+str(donnees
), liste_err
)
361 # Principe : on cherche dans quel intervalle de "colonnes" on se situe.
362 # On va donc regarder pour chaque donnée entre quels i on se situe,et après
363 # prendre le plus grand intervalle.
364 # Numéros de colonnes d'où on part. Pour la fin c'est forcément longueur-1
365 if typecourbe
== "P":
371 for k
in range(len(dates
)):
374 while i
<len(ligne
) and ligne
[i
]<donnees
[k
]:
376 debug("prolongecourbe : on a trouvé la valeur de i : "+str(i
),liste_err
)
378 warning("prolongation de courbe : pas réussi... donnée trop haute !", liste_err
)
381 warning("prolongation de courbe : pas réussi... donnée trop basse !", liste_err
)
383 liste_indices
.append(i
)
384 imin
=min(liste_indices
) -1
385 imax
=max(liste_indices
)
386 debug("Les données se situent dans les indices : "+str(imin
)+", "+str(imax
),liste_err
)
387 # Maintenant on doit trouver les coeffs : on se situe en coeff * l[imin]+ (1-coeff)*ligne[imax]
388 # Et faire la moyenne de ces coeffs
390 for k
in range(len(dates
)):
393 total
+= (donnee
- ligne
[imax
])/(ligne
[imin
] - ligne
[imax
])
395 coeff_moyen
= total
/len(dates
)
397 debug("Coeff moyen calculé : "+str(coeff_moyen
), liste_err
)
399 # On utilisera la même chose pour les nouvelle donnee
402 nouvdates
=oms
.extraire_colonne(tableauOMS
,0) # On sort tout.
406 ligne2
= tableauOMS
[int(j
)]
407 nouvdonnees
.append(coeff_moyen
*ligne2
[imin
]+ (1-coeff_moyen
)*ligne2
[imax
])
409 return nouvdates
,nouvdonnees
412 def dessine_guides(t
, data
, couleur
, unite
, ax
, liste_err
):
413 """ dessine deux lignes, horizontales et verticales qui vont "vers" la courbe
414 jusqu'aux points (t, data). En pointillés et avec un point dessus."""
415 debug("Début de dessine_guides"+str(t
)+", "+str(data
), liste_err
)
416 t_conv
= u
.convertitunite(t
,unite
,liste_err
)
417 ax
.vlines(t_conv
, 0, data
, colors
=couleur
, linestyles
="dashed")
418 ax
.hlines(data
, 0, t_conv
, color
=couleur
, linestyles
="dashed")
419 ax
.plot([t_conv
], [data
], color
=couleur
, marker
="*", ms
=13)