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
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 # 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
48 # On s'assure que c'est bien compris dans les bornes
49 jour_maxi
= max(CONFIG
["jours_mini_courbe"],min(jour_maxi
,CONFIG
["jours_maxi_courbe"]))
50 debug("cree_figure : gestion du jour max : "+str(jour_maxi
),liste_err
)
52 ##################### Gestion des unités ###############################
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","") == "":
55 unite
= u
.choix_unite(jour_maxi
)
56 debug("Unité non précisée, on choisit "+unite
,liste_err
)
57 elif conf
["unite"] != "":
60 unite
= conf
["non_sauve"]["unite"]
62 ##################### Gestion de la prématurité #######################"
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.
68 debug("Prématurité : "+str(prema
)+" age corrigé : "+conf
["agecorrige"],liste_err
)
69 if prema
>0 and conf
["agecorrige"] == "oui":
70 l_jours
= [j
-prema
for j
in l_jours
]
71 jour_maxi
= jour_maxi
- prema
74 ###################### Conversion des unités ###########################""
75 l_jours_conv
= u
.convertit_tableau(l_jours
,unite
,liste_err
)
76 # Attention, comme les jours commencent à partir de 0, faut enlever 1 pour avoir la borne...
77 age_maxi
= u
.convertitunite(jour_maxi
-1,unite
,liste_err
)
79 debug("cree_figure : conversion des unités ok : "+str(l_jours_conv
),liste_err
)
81 #####################" Courbes OMS et titre ######################################"
82 titre
= "Courbe de "+typedonnee
+" OMS"
83 if conf
["typecourbe"] == "P":
85 liste_data_labels
= liste_data_labels_p
86 if conf
["sexe"] == "M":
87 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_garcon"]#f_poids_perc_garcon
88 titre
+= " (percentiles, garçon)"
89 elif conf
["sexe"] == "F":
90 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_fille"]
91 titre
+= " (percentiles, fille)"
93 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["perc_mixte"]
94 titre
+= " (percentiles)"
95 elif conf
["typecourbe"] == "Z":
96 liste_data_labels
= liste_data_labels_z
97 if conf
["sexe"] == "M":
98 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_garcon"]
99 titre
+= " (moyenne et écarts-types, garçon)"
100 elif conf
["sexe"] == "F":
101 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_fille"]
102 titre
+= " (moyenne et écarts-types, fille)"
104 fichier_oms
= CONFIG
["fichiersOMS"][typedonnee
]["z_mixte"]
105 titre
+= " (moyenne et écarts-types)"
107 erreur("Type de courbe invalide"+conf
["typecourbe"],liste_err
)
110 # Si y'a un nom on met "courbe de machin"
112 titre
+= " de " +conf
["nom"]
115 titre
+= ", préma de "+conf
["prematurite"]
116 if conf
["agecorrige"] == "oui":
117 titre
+=" (courbe en âge corrigé)"
119 titre
+=" (courbe en âge réel, données OMS décalées)"
121 #debug("cree_figure : géré le type de courbe ok. Liste des data labels : "+str(liste_data_labels),liste_err)
122 debug("Fichier d'où extraire les données : "+fichier_oms
,liste_err
)
125 #### On extrait les données des courbes, et on convertit les jours dans l'unité voulues
127 t
= oms
.lire_fichier_csv(fichier_oms
)
129 erreur("cree_figure : Impossible d'ouvrir le fichier "+fichier_oms
, liste_err
)
132 debug("cree_figure : Conversion des données OMS à la bonne unité",liste_err
)
134 coljour
= (oms
.extraire_colonne(t
,0,jour_maxi
))
135 if prema
>0 and conf
["agecorrige"] != "oui":
136 coljour
= [j
+ prema
for j
in coljour
]
137 coljour
= u
.convertit_tableau(coljour
,unite
,liste_err
)
139 erreur("Problème à la conversion du tableau OMS. jour_maxi = "+str(jour_maxi
)+" unite = "+unite
,liste_err
)
142 ##################### Création de la figure et du graphique ###################
143 debug("cree_figure : prête à créer la figure",liste_err
)
144 #### La figure, params
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"]
155 ###################### Tracé des différentes courbes
156 #Tracé des courbes OMS
157 for (i
,label
,couleur
) in liste_data_labels
:
158 ax
.plot(coljour
,oms
.extraire_colonne(t
,i
,jour_maxi
),label
=label
,color
=couleur
)
160 debug("cree_figure : tracé des courbes OMS ok",liste_err
)
162 ### Tracé pour de bon
164 ax
.plot(l_jours_conv
,l_poids
,label
=conf
["nom"],color
=conf
["couleurs"]["cadretxt"],marker
='o')
165 debug("Tracé de la courbe enfant, avec les jours "+str(l_jours_conv
),liste_err
)
167 #### extrapolatios éventuelles
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 ?
172 for calextra
in CONFIG
["extradata"]:
173 jextrapole
= jextrapole
or conf
["non_sauve"][calextra
+"_type"] == typedonnee
176 ############################## Là où on extrapole ################################
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
186 sources_extrap
= l_jours
[-conf
["non_sauve"]["nbextradata"]:] # les derniers jours
187 sources_extrap_data
= l_poids
[-conf
["non_sauve"]["nbextradata"]:]
189 debug("On extrapole sur les jours : "+str(sources_extrap
), liste_err
)
191 # On récupère toutes les données extrapolées
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)
196 # QUe veut-on maintenant sur ces données extrapolées ?
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
)
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
)
212 ### Calculer une donnée à l'âge x
213 if conf
["non_sauve"]["calculextradata_type"] == typedonnee
:
214 # On essaie l'interpolation
215 r
= interpole_lineaire(l_jours
,l_poids
,conf
["non_sauve"]["calculextradata_age"], liste_err
)
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"])
221 # message+="l'ensemble des données"
223 # message+="les "+str(conf["non_sauve"]["nbextradata"])+" dernière"+met_s(conf["non_sauve"]["nbextradata"])+" données"
225 message
=formate_interpole()
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
)
230 liste_extracalculs
.append(texte
)
231 print(liste_extracalculs
)
233 if conf
["non_sauve"]["calculextradata_trace"] == "oui":
234 dessine_guides(conf
["non_sauve"]["calculextradata_age"], r
, conf
["couleurs"]["cadretxt"], unite
, ax
, liste_err
)
236 ### Calculer un âge où on atteint cette donnée
237 if conf
["non_sauve"]["calculextratemps_type"] == typedonnee
:
239 r
= interpole_lineaire_ordonnee(l_jours
,l_poids
,conf
["non_sauve"]["calculextratemps_val"], liste_err
)
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"])
245 message
=formate_interpole()
247 texte
= formate_resultat_age(r
, conf
["non_sauve"]["calculextratemps_val"], typedonnee
, message
, liste_err
)
249 #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
251 liste_extracalculs
.append(texte
)
252 print(liste_extracalculs
)
254 if conf
["non_sauve"]["calculextratemps_trace"]:
255 dessine_guides(r
, conf
["non_sauve"]["calculextratemps_val"], conf
["couleurs"]["cadretxt"], unite
, ax
, liste_err
)
258 warning("Des problèmes pour extrapoler...", liste_err
)
261 debug("On ne trace pas de courbe enfant", liste_err
)
263 ###################" Gestion de l'échelle #####################
264 debug("Courbes tracées. Il n'y a plus qu'à gérer l'échelle", liste_err
)
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]
272 poids_min
= min(oms
.extraire_colonne(t
,colonne_min
,jour_maxi
))
273 poids_max
= max(oms
.extraire_colonne(t
,colonne_max
,jour_maxi
))
275 poids_min
= min(min(l_poids
),poids_min
)
276 # Pour le poids max, voir la dernière valeur du tableau
278 while i
<len(l_jours
) and l_jours
[i
]<jour_maxi
:
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)
285 poids_max
= poids_max
* 1.05
289 if conf
["non_sauve"]["grilleamelio"] == "oui":
290 debug("On a choisi la grille plus jolie", liste_err
)
291 pas
=u
.choix_echelle_data(typedonnee
, poids_max
)
293 minechelle
= int(poids_min
/pas
[0])*pas
[0]
295 debug("pas choisis pour l'échelle en y : "+str(pas
), liste_err
)
296 echellemajeure
= arange(minechelle
, poids_max
, pas
[0])
299 echellemineure
= arange(minechelle
, poids_max
, pas
[1])
303 ax
.set_yticks(echellemajeure
, minor
=False)
304 ax
.set_yticks(echellemineure
, minor
=True)
307 pas
=u
.choix_echelle_temps(unite
, age_maxi
)
308 debug("pas choisis pour l'échelle en x : "+str(pas
), liste_err
)
310 echellemajeure
= arange(0,age_maxi
, pas
[0])
312 echellemineure
= arange(0,age_maxi
, pas
[1])
315 ax
.set_xticks(echellemajeure
, minor
=False)
316 ax
.set_xticks(echellemineure
, minor
=True)
318 ################################# Aspect du graphique
320 debug("On commende la déco du graphique", liste_err
)
323 ax
.grid(conf
["grille"]=="oui")
324 ax
.grid(conf
["grille"] == "oui", which
="minor", linestyle
="--")
327 plt
.xlabel("Âge en "+unite
,color
=conf
["couleurs"]["cadretxt"])
328 plt
.ylabel(typedonnee
.capitalize()+" en "+CONFIG
["unites_typedonnees"][typedonnee
],color
=conf
["couleurs"]["cadretxt"])
329 plt
.title(titre
,color
=conf
["couleurs"]["cadretxt"])
330 if l_jours_conv
== []:
331 plt
.axis([0,age_maxi
, poids_min
, poids_max
])
333 plt
.axis([min(0,l_jours_conv
[0]),age_maxi
,poids_min
,poids_max
])
336 if conf
['legende']=="oui":
337 legende
= plt
.legend(loc
=conf
['positionlegende'])
338 plt
.setp(legende
.get_texts(), color
=conf
["couleurs"]["cadretxt"])
343 debug("Fin de cree_figure, tout va bien.", liste_err
)
349 ######################################## Pour extrapoler la courbe
351 def 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
356 typecourbe est P ou Z. Pour P il faut commencer à regarder à l'indice 4, pour Z
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
)
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
369 if typecourbe
== "P":
375 for k
in range(len(dates
)):
378 while i
<len(ligne
) and ligne
[i
]<donnees
[k
]:
380 debug("prolongecourbe : on a trouvé la valeur de i : "+str(i
),liste_err
)
382 warning("prolongation de courbe : pas réussi... donnée trop haute !", liste_err
)
385 warning("prolongation de courbe : pas réussi... donnée trop basse !", liste_err
)
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
394 for k
in range(len(dates
)):
397 total
+= (donnee
- ligne
[imax
])/(ligne
[imin
] - ligne
[imax
])
399 coeff_moyen
= total
/len(dates
)
401 debug("Coeff moyen calculé : "+str(coeff_moyen
), liste_err
)
403 # On utilisera la même chose pour les nouvelle donnee
406 nouvdates
=oms
.extraire_colonne(tableauOMS
,0) # On sort tout.
410 ligne2
= tableauOMS
[int(j
)]
411 nouvdonnees
.append(coeff_moyen
*ligne2
[imin
]+ (1-coeff_moyen
)*ligne2
[imax
])
413 return nouvdates
,nouvdonnees
416 def 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)