summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenise sur Lya <sekhmet@lya>2021-04-17 13:47:35 +0200
committerDenise sur Lya <sekhmet@lya>2021-04-17 13:47:35 +0200
commit3d7da80ac11bb87ab441fb51f93b738be02de2c3 (patch)
tree1280ab37f4ccf548f84270d661a4292d1576ef9c
parent857e655d3b2963fed1a7c1a8c56169bf1c0a4809 (diff)
downloadoms-3d7da80ac11bb87ab441fb51f93b738be02de2c3.tar.gz
oms-3d7da80ac11bb87ab441fb51f93b738be02de2c3.tar.zst
oms-3d7da80ac11bb87ab441fb51f93b738be02de2c3.zip
Extrapolation améliorée + possibilité de voir le point voulu
-rw-r--r--calculs_extrapole.py189
-rw-r--r--data/changelog_data.txt8
-rw-r--r--gestion_donnees.py5
-rw-r--r--templates/index.html8
-rw-r--r--trace_courbe.py65
5 files changed, 219 insertions, 56 deletions
diff --git a/calculs_extrapole.py b/calculs_extrapole.py
index ab22502..509402b 100644
--- a/calculs_extrapole.py
+++ b/calculs_extrapole.py
@@ -10,8 +10,95 @@ from gestion_erreurs import warning, debug
10from configuration import CONFIG 10from configuration import CONFIG
11from gestion_donnees import convertit_age_vers_texte 11from gestion_donnees import convertit_age_vers_texte
12import gestion_unites as u 12import gestion_unites as u
13from math import ceil
13 14
14#### Les fonctions qui permettent de faire les calculs additionnels une fois qu'on a l'extrapolation 15#### Les fonctions qui permettent de faire les calculs additionnels une fois qu'on a l'extrapolation (ou pas)
16
17def interpole_lineaire(dates, donnees, t, liste_err):
18 """ simple interpolation linéaire.
19 dates et donnees sont les dates et données de l'enfant.
20 t est le temps (jours) auquel on veut l'interpolation. On renvoie la donnée interpolée.
21 On interpole linéairement entre les deux données. Si ça
22 n'est pas possible parce que t n'est pas dans les bornes, on renvoie -1
23 """
24
25 if t<dates[0] or t>dates[-1]:
26 return -1 # en dehors des bornes
27
28 i=0 # on cherche l'intervalle : entre dates[i] et dates[i+1] on a la donnée t
29 while i<len(dates)-1 and dates[i+1]<t:
30 i+=1
31
32 m = (donnees[i+1] - donnees[i])/(dates[i+1] - dates[i]) # pente de la courbe
33 valeur = m * (t - dates[i]) + donnees[i]
34 return valeur
35
36
37def interpole_lineaire_ordonnee(dates, donnees, val, liste_err):
38 """ interpolation linéaire des données.
39 dates et donnees sont les dates et données de l'enfant.
40 val est la valeur pour laquelle on veut trouver le temps.
41 On interpole linéairement entre les deux données. Si ça
42 n'est pas possible parce que t n'est pas dans les bornes, on renvoie -1
43
44 Comportement potentiellement foireux si jamais les données ne sont pas
45 croissantes (poids qui chute, etc)..."""
46
47 if val>max(donnees) or val<min(donnees):
48 return -1 # en dehors des maxi et mini
49
50 i = 0 # On cherche dans quel intervalles de données on se situe (donnnes[i]
51 # et donnees [i+1])
52 while i<len(donnees)-1 and donnees[i+1]<val:
53 i+=1
54
55 m = (dates[i+1] - dates[i])/(donnees[i+1] - donnees[i])
56 temps = m * (val - donnees[i]) + dates[i]
57
58 return ceil(temps)
59
60
61######################################
62
63
64
65
66
67def calcule_donnee_extrapolee(dates_extrapole, donnees_extrapole, age_voulu, liste_err):
68 """ prend en argument les données extrapolées, l'âge voulu en jours.
69 Renvoie la donnée, ou -1 si ça n'a pas marché"""
70 age_voulu = int(age_voulu) # pour avoir les choses bien
71 debug("On veut la donnée à l'âge "+str(age_voulu), liste_err)
72 try:
73 i_date_voulue = dates_extrapole.index(age_voulu)
74 donnee_voulue = donnees_extrapole[i_date_voulue]
75
76 return donnee_voulue
77 #return formate_resultat_donnee(age_voulu, donnee_voulue, typedonnee, "", liste_err)
78 except:
79 warning("Impossible de calculer la donnée à l'âge "+age_voulu, liste_err)
80 return -1
81
82
83
84def calcule_age_extrapole(dates_extrapole, donnees_extrapole, donnee_voulue, liste_err):
85 """ prend en argument les données extrapolées, la donnée voulue (dans l'unité adaptée)
86 Renvoie la donnée, ou -1 si ça n'a pas marché"""
87
88 debug("On veut savoir à quel âge on a "+str(donnee_voulue), liste_err)
89 try:
90 i=0
91 while i<len(donnees_extrapole) and donnees_extrapole[i]<donnee_voulue:
92 i+=1
93
94 return dates_extrapole[i]
95 #return formate_resultat_age(dates_extrapole[i], donnee_voulue, typedonnee, "", liste_err)
96 except:
97 warning("Impossible de calculer l'âge pour la donnée "+str(donnee_voulue), liste_err)
98 return -1
99
100######################################
101### Formatage du résultat "joli"
15 102
16def met_s(chaine): 103def met_s(chaine):
17 """ renvoie un s si pluriel, rien sinon""" 104 """ renvoie un s si pluriel, rien sinon"""
@@ -27,7 +114,7 @@ def joliechaine_age(age):
27 nombre = "" 114 nombre = ""
28 for char in age: 115 for char in age:
29 if char=="a": 116 if char=="a":
30 retour+=nombre+" année"+met_s(nombre)+", " 117 retour+=nombre+" an"+met_s(nombre)+", "
31 nombre="" 118 nombre=""
32 elif char=="m": 119 elif char=="m":
33 retour+=nombre+" mois, " 120 retour+=nombre+" mois, "
@@ -42,48 +129,62 @@ def joliechaine_age(age):
42 nombre+=char 129 nombre+=char
43 #print(retour) 130 #print(retour)
44 return retour[:-2] 131 return retour[:-2]
45
46 132
133def formate_resultat_donnee(age, donnee, typedonnee, extra, liste_err):
134 """ Formate le tout en une zolie phrase
135 age et donnee sont les données,
136 typedonnee est le type de donnée (poids, etc)
137 extra est un truc additionnel à mettre entre parenthèses"""
47 138
48def calcule_donnee_extrapolee(dates_extrapole, donnees_extrapole, age_voulu, typedonnee, liste_err): 139 donnee_arrondie = u.arrondit_donnee(donnee, typedonnee)
49 """ prend en argument les données extrapolées, l'âge voulu en jours, 140 chaine = "À "+joliechaine_age(convertit_age_vers_texte(age))
50 et le type de données qu'on veut afficher, et renvoie une jolie phrase 141
51 à afficher""" 142 if typedonnee == "poids":
52 age_voulu = int(age_voulu) # pour avoir les choses bien 143 chaine+= ", l'enfant pèsera "+str(donnee_arrondie)+" kg"
53 debug("On veut la donnée à l'âge "+str(age_voulu), liste_err) 144 elif typedonnee == "taille":
54 try: 145 chaine+= ", l'enfant mesurera "+str(donnee_arrondie)+" cm"
55 i_date_voulue = dates_extrapole.index(age_voulu) 146 else: # phrase générique
56 donnee_voulue = donnees_extrapole[i_date_voulue] 147 chaine+= ", la donnée sera : "+str(donnee_arrondie)+" "+CONFIG["unites_typedonnees"][typedonnee]
57 donnee_arrondie = u.arrondit_donnee(donnee_voulue, typedonnee) 148
58 chaine = "À "+joliechaine_age(convertit_age_vers_texte(age_voulu)) 149 if extra!="":
59 150 ajout=" ("+extra+")"
60 if typedonnee == "poids": 151 else:
61 return chaine+", l'enfant pèsera "+str(donnee_arrondie)+" kg." 152 ajout=""
62 elif typedonnee == "taille": 153
63 return chaine+", l'enfant mesurera "+str(donnee_arrondie)+" cm." 154 chaine+=ajout+"."
64 else: # phrase générique 155 return chaine
65 return chaine+", la donnée sera : "+str(donnee_arrondie)+" "+CONFIG["unites_typedonnees"][typedonnee]+"." 156
66 except: 157def formate_resultat_age(age, donnee, typedonnee, extra, liste_err):
67 warning("Impossible de calculer la donnée à l'âge "+age_voulu, liste_err) 158 """ formate les données en une zolie phrase
68 return "" 159 age et donnee sont les données
69 160 typedonnee est le type de donnée (poids, etc)
70def calcule_age_extrapole(dates_extrapole, donnees_extrapole, donnee_voulue, typedonnee, liste_err): 161 extra est un truc additionnel à mettre entre parenthèses"""
71 """ prend en argument les données extrapolées, la donnée voulue (dans l'unité adaptée) 162 age_joli = joliechaine_age(convertit_age_vers_texte(age))
72 et son type, et renvoie la jolie phrase à afficher""" 163 if typedonnee=="poids":
164 chaine= "L'enfant atteindra un poids de "+str(donnee)+" kg à l'âge de "+age_joli
165 elif typedonnee=="taille":
166 chaine= "L'enfant atteindra la taille "+str(donnee)+ "cm à l'âge de "+age_joli
167 else:# phrase générique
168 chaine= "L'enfant atteindra la donnée "+typedonnee+" "+str(donnee)+" à l'âge de "+age_joli
73 169
74 debug("On veut savoir à quel âge on a "+str(donnee_voulue), liste_err) 170 if extra!="":
75 try: 171 ajout=" ("+extra+")"
76 i=0 172 else:
77 while i<len(donnees_extrapole) and donnees_extrapole[i]<donnee_voulue: 173 ajout=""
78 i+=1 174
79 175 chaine+=ajout+"."
80 age_joli = joliechaine_age(convertit_age_vers_texte(dates_extrapole[i])) 176 return chaine
81 if typedonnee=="poids": 177
82 return "L'enfant atteindra un poids de "+str(donnee_voulue)+" kg à l'âge de "+age_joli+"." 178def formate_extrapole(nb_extra):
83 elif typedonnee=="taille": 179 """ Renvoie une chaîne qui dit sur cb on a extrapolé"""
84 return "L'enfant atteindra la taille "+str(donnee_voulue)+ "cm à l'âge de "+age_joli+"." 180 message="extrapolation sur "
85 else:# phrase générique 181 if nb_extra== 0:
86 return "L'enfant atteindra la donnée "+typedonnee+" "+str(donnee_voulue)+" à l'âge de "+age_joli+"." 182 message+="l'ensemble des données"
87 except: 183 elif nb_extra==1:
88 warning("Impossible de calculer l'âge pour la donnée "+str(donnee_voulue), liste_err) 184 message+="la donnée la plus récente"
89 return "" 185 else:
186 message+="les "+str(nb_extra)+" dernières données"
187 return message
188
189def formate_interpole():
190 return "interpolation sur les données existantes" \ No newline at end of file
diff --git a/data/changelog_data.txt b/data/changelog_data.txt
index 9d48c19..6ba20dd 100644
--- a/data/changelog_data.txt
+++ b/data/changelog_data.txt
@@ -1,3 +1,11 @@
1"Version 2.31","17/04/2021","<p>Bêta : Les calculs de données sont améliorés :
2<ul>
3<li>Si l'âge demandé (ou la donnée) est entre les données saisies, c'est une simple interpolation linéaires entre les données existantes,</li>
4<li>Si c'est en dehors, alors on fait un calcul d'extrapolation comme avant</li>
5</ul>
6En plus, on peut décider de marquer sur le graphique, ou pas, le point qu'on cherche.
7</p>"
8
1"Version 2.3001","13/03/2021","<p>Petit changement : on peut maintenant mettre le poids en grammes. Si le poids saisi est supérieur à 500 il sera automatiquement converti.</p>" 9"Version 2.3001","13/03/2021","<p>Petit changement : on peut maintenant mettre le poids en grammes. Si le poids saisi est supérieur à 500 il sera automatiquement converti.</p>"
2 10
3"Version 2.3","26/02/2021","<p>Nouveauté : extrapolation de la courbe améliorée, ainsi que la possibilité de faire des ""calculs"" sur la courbe. Il y a aussi deux-trois petits changements cosmétiques.</p>" 11"Version 2.3","26/02/2021","<p>Nouveauté : extrapolation de la courbe améliorée, ainsi que la possibilité de faire des ""calculs"" sur la courbe. Il y a aussi deux-trois petits changements cosmétiques.</p>"
diff --git a/gestion_donnees.py b/gestion_donnees.py
index 2583007..2153a55 100644
--- a/gestion_donnees.py
+++ b/gestion_donnees.py
@@ -333,6 +333,11 @@ def gere_configuration(data,liste_err):
333 else: 333 else:
334 configuration["non_sauve"]["calculextratemps_type"] = "" 334 configuration["non_sauve"]["calculextratemps_type"] = ""
335 335
336 # Tracer les calculs sur la grille
337 configuration["non_sauve"]["calculextradata_trace"] = gere_checkbox(data.get("calculextradata_trace"))
338 configuration["non_sauve"]["calculextratemps_trace"] = gere_checkbox(data.get("calculextratemps_trace"))
339
340
336 return configuration 341 return configuration
337 342
338 343
diff --git a/templates/index.html b/templates/index.html
index 64fb9e1..32c45e1 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -121,19 +121,23 @@
121<ul id="extra"> 121<ul id="extra">
122 <li>Calculer le prolongement de la courbe à partir des <input type="text" name="nbextradata" size="4" value="1"> dernières données (mettre 0 pour "toutes").</li> 122 <li>Calculer le prolongement de la courbe à partir des <input type="text" name="nbextradata" size="4" value="1"> dernières données (mettre 0 pour "toutes").</li>
123 <li><input type="checkbox" name="prolongercourbes">Tracer l'extrapolation sur le graphique.</li> 123 <li><input type="checkbox" name="prolongercourbes">Tracer l'extrapolation sur le graphique.</li>
124
124 <li>Calculer <select name="calculextradata_type"> 125 <li>Calculer <select name="calculextradata_type">
125 <option value="">Choisir la donnée</option> 126 <option value="">Choisir la donnée</option>
126 {% for val in CONFIG.liste_typedonnees %} 127 {% for val in CONFIG.liste_typedonnees %}
127 <option value="{{val}}">{{val}}</option> 128 <option value="{{val}}">{{val}}</option>
128 {% endfor %} 129 {% endfor %}
129 </select> à l'âge <input type="text" name="calculextradata_age" value="6m"></li> 130 </select> à l'âge <input type="text" name="calculextradata_age" value="6m">
131 <input type="checkbox" name="calculextradata_trace"> ... et le voir sur le graphique.</li>
132
130 <li>Calculer l'âge auquel l'enfant aura <input type="text" name="calculextratemps_val"> 133 <li>Calculer l'âge auquel l'enfant aura <input type="text" name="calculextratemps_val">
131 <select name="calculextratemps_type"> 134 <select name="calculextratemps_type">
132 <option value="">Choisir la donnée</option> 135 <option value="">Choisir la donnée</option>
133 {% for val in CONFIG.liste_typedonnees %} 136 {% for val in CONFIG.liste_typedonnees %}
134 <option value="{{val}}">{{ CONFIG.unites_typedonnees[val]}} ({{val}})</option> 137 <option value="{{val}}">{{ CONFIG.unites_typedonnees[val]}} ({{val}})</option>
135 {% endfor %} 138 {% endfor %}
136 </select></li> 139 </select>
140 <input type="checkbox" name="calculextratemps_trace"> ... et le voir sur le graphique.</li>
137 141
138</ul> 142</ul>
139 143
diff --git a/trace_courbe.py b/trace_courbe.py
index e725607..28ee5b4 100644
--- a/trace_courbe.py
+++ b/trace_courbe.py
@@ -5,8 +5,10 @@ import gestionOMS as oms
5import gestion_unites as u 5import gestion_unites as u
6from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python, convertit_age_vers_texte 6from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python, convertit_age_vers_texte
7from gestion_erreurs import debug, erreur, warning 7from gestion_erreurs import debug, erreur, warning
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
8from numpy import arange 10from numpy import arange
9from calculs_extrapole import calcule_donnee_extrapolee, calcule_age_extrapole 11
10 12
11import matplotlib.pyplot as plt 13import matplotlib.pyplot as plt
12 14
@@ -167,6 +169,7 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err):
167 jextrapole = jextrapole or conf["non_sauve"][calextra+"_type"] == typedonnee 169 jextrapole = jextrapole or conf["non_sauve"][calextra+"_type"] == typedonnee
168 170
169 #print(jextrapole) 171 #print(jextrapole)
172 ############################## Là où on extrapole ################################
170 if jextrapole: 173 if jextrapole:
171 try: 174 try:
172 debug("Il faut extrapoler les courbes !", liste_err) 175 debug("Il faut extrapoler les courbes !", liste_err)
@@ -181,6 +184,7 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err):
181 184
182 debug("On extrapole sur les jours : "+str(sources_extrap), liste_err) 185 debug("On extrapole sur les jours : "+str(sources_extrap), liste_err)
183 186
187 # On récupère toutes les données extrapolées
184 dates_extrapole, donnees_extrapole = prolongecourbe(t, sources_extrap, sources_extrap_data, conf["typecourbe"], liste_err) 188 dates_extrapole, donnees_extrapole = prolongecourbe(t, sources_extrap, sources_extrap_data, conf["typecourbe"], liste_err)
185 debug("données extrapolées !", liste_err) 189 debug("données extrapolées !", liste_err)
186 #debug(str(dates_extrapole[0:10])+str(donnees_extrapole[0:10]), liste_err) 190 #debug(str(dates_extrapole[0:10])+str(donnees_extrapole[0:10]), liste_err)
@@ -201,19 +205,50 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err):
201 plt.plot(dates_extrapole_trace, donnees_extrapole_trace,color=conf["couleurs"]["cadretxt"], linestyle=(0, (5,7)), marker=None) 205 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) 206 debug("Tracé de la courbe extrapolée ok", liste_err)
203 207
204 # Calculer une donnée à l'âge x 208 ### Calculer une donnée à l'âge x
205 if conf["non_sauve"]["calculextradata_type"] == typedonnee: 209 if conf["non_sauve"]["calculextradata_type"] == typedonnee:
206 r = calcule_donnee_extrapolee(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextradata_age"], typedonnee, liste_err) 210 # On essaie l'interpolation
207 if r!="": 211 r = interpole_lineaire(l_jours,l_poids,conf["non_sauve"]["calculextradata_age"], liste_err)
208 liste_extracalculs.append(r) 212 if r==-1:
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"])
216# if == 0:
217# message+="l'ensemble des données"
218# else:
219# message+="les "+str(conf["non_sauve"]["nbextradata"])+" dernière"+met_s(conf["non_sauve"]["nbextradata"])+" données"
220 else:
221 message=formate_interpole()
222
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)
225 if texte!="":
226 liste_extracalculs.append(texte)
209 print(liste_extracalculs) 227 print(liste_extracalculs)
228 # Ajouter le trait ?
229 if conf["non_sauve"]["calculextradata_trace"] == "oui":
230 dessine_guides(conf["non_sauve"]["calculextradata_age"], r, conf["couleurs"]["cadretxt"], unite, ax, liste_err)
210 231
211 # Calculer un âge où on atteint cette donnée 232 ### Calculer un âge où on atteint cette donnée
212 if conf["non_sauve"]["calculextratemps_type"] == typedonnee: 233 if conf["non_sauve"]["calculextratemps_type"] == typedonnee:
213 r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err) 234 # interpolation
214 if r!="": 235 r = interpole_lineaire_ordonnee(l_jours,l_poids,conf["non_sauve"]["calculextratemps_val"], liste_err)
215 liste_extracalculs.append(r) 236 if r==-1:
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"])
240 else:
241 message=formate_interpole()
242
243 texte = formate_resultat_age(r, conf["non_sauve"]["calculextratemps_val"], typedonnee, message, liste_err)
244
245 #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
246 if texte!="":
247 liste_extracalculs.append(texte)
216 print(liste_extracalculs) 248 print(liste_extracalculs)
249 # Ajouter le trait ?
250 if conf["non_sauve"]["calculextratemps_trace"]:
251 dessine_guides(r, conf["non_sauve"]["calculextratemps_val"], conf["couleurs"]["cadretxt"], unite, ax, liste_err)
217 252
218 except: 253 except:
219 warning("Des problèmes pour extrapoler...", liste_err) 254 warning("Des problèmes pour extrapoler...", liste_err)
@@ -371,4 +406,14 @@ def prolongecourbe(tableauOMS, dates, donnees, typecourbe, liste_err):
371 ligne2 = tableauOMS[int(j)] 406 ligne2 = tableauOMS[int(j)]
372 nouvdonnees.append(coeff_moyen*ligne2[imin]+ (1-coeff_moyen)*ligne2[imax]) 407 nouvdonnees.append(coeff_moyen*ligne2[imin]+ (1-coeff_moyen)*ligne2[imax])
373 408
374 return nouvdates,nouvdonnees \ No newline at end of file 409 return nouvdates,nouvdonnees
410
411
412def 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)