V2.6 : bugs d'extrapolation corrigé, prise en compte des dates dans les données,...
authorDenise sur ardoise <denise@ardoise>
Sat, 28 May 2022 17:22:58 +0000 (19:22 +0200)
committerDenise sur ardoise <denise@ardoise>
Sat, 28 May 2022 17:22:58 +0000 (19:22 +0200)
app.py
calculs_extrapole.py
configuration.py
data/changelog_data.txt
gestion_donnees.py
static/outilspage.js
static/requetes.js
templates/index.html
trace_courbe.py

diff --git a/app.py b/app.py
index 84e2ff111f4610848c480ad56391f5d56510e9a3..428416e36cf212a1b20662f5b6d38039afb7e1de 100644 (file)
--- a/app.py
+++ b/app.py
@@ -59,7 +59,7 @@ def courbe_image(ext):
 
     # récupérer les données du formulaire proprement
     config,listes_jours,listes_donnees = donnees.web_vers_python(data,liste_err)
-    debug(" * On a récupéré et traité les données du formulaire web",liste_err)
+    debug(" * On a récupéré et traité les données du formulaire web, "+str(listes_jours)+str(listes_donnees),liste_err)
 
     # Gérer les enfants additionnels
     enfants_add = donnees.gere_enfants_additionnels(data, flask.request.files, liste_err)
index fdd4c680830cc2315b5bb513673ae9ff512efde6..c84960d6b703d9ba5e75b7c60b80aaf3efd46c27 100644 (file)
@@ -130,15 +130,18 @@ def joliechaine_age(age):
     #print(retour)
     return retour[:-2]
 
-def formate_resultat_donnee(age, donnee, typedonnee, extra, liste_err):
+def formate_resultat_donnee(age, date, donnee, typedonnee, extra, liste_err):
     """ Formate le tout en une zolie phrase
-    age et donnee sont les données,
+    age date et donnee sont les données. date peut être None (sinon donnée de date)
     typedonnee est le type de donnée (poids, etc)
     extra est un truc additionnel à mettre entre parenthèses"""
 
     donnee_arrondie = u.arrondit_donnee(donnee, typedonnee)
     chaine = "À "+joliechaine_age(convertit_age_vers_texte(age))
 
+    if date != None:
+        chaine += ", le "+date.strftime("%d/%m/%Y")
+
     if typedonnee == "poids":
         chaine+= ", l'enfant pèsera "+str(donnee_arrondie)+" kg"
     elif typedonnee == "taille":
@@ -154,9 +157,9 @@ def formate_resultat_donnee(age, donnee, typedonnee, extra, liste_err):
     chaine+=ajout+"."
     return chaine
 
-def formate_resultat_age(age, donnee, typedonnee, extra, liste_err):
+def formate_resultat_age(age, date, donnee, typedonnee, extra, liste_err):
     """ formate les données en une zolie phrase
-    age et donnee sont les données
+    age, date et donnee sont les données. date est une donnée de date qui peut être vide.
     typedonnee est le type de donnée (poids, etc)
     extra est un truc additionnel à mettre entre parenthèses"""
     age_joli = joliechaine_age(convertit_age_vers_texte(age))
@@ -167,6 +170,9 @@ def formate_resultat_age(age, donnee, typedonnee, extra, liste_err):
     else:# phrase générique
         chaine= "L'enfant atteindra la donnée "+typedonnee+" "+str(donnee)+" à l'âge de "+age_joli
     
+    if date != None:
+        chaine += ", le "+date.strftime("%d/%m/%Y")
+    
     if extra!="":
         ajout=" ("+extra+")"
     else:
index b22c6e3fbd788141534217d62fbd113ec1387316..4ad42e6b698fc4d2679a08f19b861ea0c31eec44 100644 (file)
@@ -5,7 +5,7 @@
 CONFIG = {}
 
 ### La version de l'app
-CONFIG["version"] = 2.5
+CONFIG["version"] = 2.6
 # Nombre de versions anciennes dans le changelog
 CONFIG["nb_lignes_changelog"] = 4
 
index d9987fb8951f222214612aab81fde67b9c686fbd..4fa79d6573026b0d845f9d10d0b0843edf7d064f 100644 (file)
@@ -1,4 +1,10 @@
-"Version 2.51","26/25/2022","<p>Un test à faire : les dates sont prioritaires sur les âges pour éviter les soucis d'arrondis. À tester, et d'autres trucs arrivent.</p>"
+"Version 2.6","28/05/2022","<p>Des petites nouveautés :</p>
+<ul>
+       <li>Les dates sont désormais prioritaires sur les âges pour éviter les soucis d'arrondis.</li>
+       <li>Il est également possible de mettre une date sur un repère (et de repérer une date précise).</li>
+       <li>On peut également utiliser les dates pour les extrapolations (telle date l'enfant pèsera tant...)</li>
+       <li>Un bug corrigé : si on demande une taille de graphique supérieure à l'âge max des données OMS (5 ans), ça ne fait pas planter l'extrapolation (le tracé d'extrapolation s'arrêtera juste à 5 ans).</li>
+</ul>"
 
 "Version 2.501","14/05/2022","<p>Petit bug mineur corrigé : si on met une donnée avec une date inférieure à la date de naissance, elle est ignorée et un petit message s'affiche.</p>"
 
index 7c15486511eaa903367f5e2b2c4bb4e2ffc64ba3..eab75e95505ec264a33c648c8d63903ad988d640 100644 (file)
@@ -63,6 +63,7 @@ def convertit_age_vers_texte(nombre):
     annees = int(nombre / CONFIG["jours_dans_annee"])
     restant = nombre - annees*CONFIG["jours_dans_annee"]
     mois = int(restant/CONFIG["jours_dans_mois"])
+    #print("mois : ",mois, ", restant : ",nombre - mois*CONFIG["jours_dans_mois"])
     jours= round(nombre - mois*CONFIG["jours_dans_mois"] - annees*CONFIG["jours_dans_annee"])
     
     chaine = ""
@@ -160,6 +161,8 @@ def convertit_date_vers_texte(date):
 def delta_date(date1,datenaissance, liste_err):
     """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
     datenaissance est supposée antérieure. Erreur sinon."""
+    if type(date1) != datetime.date or type(datenaissance) != datetime.date:
+        return -1
     d = date1 - datenaissance
     jours = d.days
     if jours<0:
@@ -349,12 +352,25 @@ def gere_configuration(data,liste_err, court=False):
             nbextradata = 1
         configuration["non_sauve"]["nbextradata"] = nbextradata
         
-        if data.get("calculextradata_type","") in CONFIG["liste_typedonnees"]:
+        if data.get("calculextradata_type","") in CONFIG["liste_typedonnees"]: # Si on a choisi un type de données à calculer
+            
             configuration["non_sauve"]["calculextradata_type"] = data.get("calculextradata_type","")
-            configuration["non_sauve"]["calculextradata_age"] = convertit_jours_vers_python(data.get("calculextradata_age","0j"),liste_err)
+            age = convertit_jours_vers_python(data.get("calculextradata_age","0j"),liste_err)
+            date = convertit_date_vers_python(data.get("calculextradata_date", ""), [[],[]])
+            agecalcule = delta_date(date, configuration["naissance"], liste_err)
+            if configuration["naissance"] != "" and agecalcule != -1: # On garde plutôt la date
+                configuration["non_sauve"]["calculextradata_age"] = agecalcule
+                configuration["non_sauve"]["calculextradata_date"] = date
+            else: # On garde l'âge
+                configuration["non_sauve"]["calculextradata_age"] = age
+                if type(configuration["naissance"]) == datetime.date:
+#                    print(configuration["naissance"], type(configuration["naissance"]))
+                    configuration["non_sauve"]["calculextradata_date"] = configuration["naissance"] + datetime.timedelta(days=round(age))
+                else:
+                    configuration["non_sauve"]["calculextradata_date"] = None
         else:
             configuration["non_sauve"]["calculextradata_type"] = ""
-            # On ne met rien dans l'âge, pas la peine
+            # On ne met rien dans les autres données, pas la peine
         
         ctyped = data.get("calculextratemps_type","")
         if ctyped in CONFIG["liste_typedonnees"]:
@@ -373,12 +389,26 @@ def gere_configuration(data,liste_err, court=False):
         i=0
         while "repere_texte_"+str(i) in data: # Tant qu'il y a des trucs définis
             debug("Repère trouvé", liste_err)
+            jegardecerepere = False # On va passer à True uniquementsi tout va bien
+
             age=data.get("repere_age_"+str(i), "")
+            date=data.get("repere_date_"+str(i), "")
             trace=gere_checkbox(data.get("repere_trace_"+str(i), ""))
-            if age !="":
-                agec=convertit_jours_vers_python(age, liste_err)
+            affichedate=gere_checkbox(data.get("repere_affichedate_"+str(i), ""))
+
+            if date!="" and configuration['naissance'] != "": # Si on a saisi une date (et qu'il y a la date de naissance)
+                datepython = convertit_date_vers_python(date,liste_err)
+                if datepython !="": # Si la conversion s'est bien passée
+                    nbjours = delta_date(datepython, configuration['naissance'], liste_err)
+                    if nbjours != -1: # Si tout va bien jusque là
+                        jegardecerepere=True
+            elif age !="":
+                nbjours=convertit_jours_vers_python(age, liste_err)
+                jegardecerepere=True
+
+            if jegardecerepere:
                 texte = data.get("repere_texte_"+str(i), "") # Même si le texte est vide, osef
-                configuration["liste_reperes"].append({"typed": "age", "donnee": agec, "texte": texte, "trace": trace})
+                configuration["liste_reperes"].append({"typed": "age", "donnee": nbjours, "date": date, "texte": texte, "trace": trace, "affichedate":affichedate})
             i+=1
     
     return configuration   
@@ -487,8 +517,8 @@ def donnees_vers_json(l_jours,l_poids,l_jourst,l_taille,config):
     if gros_dico.get("naissance","") != "":
         gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"])
         # Calcul de toutes les dates de données
-        l_dates_poids = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=jours) ) for jours in l_jours]
-        l_dates_taille = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=jours) ) for jours in l_jourst]
+        l_dates_poids = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=round(jours)) ) for jours in l_jours]
+        l_dates_taille = [convertit_date_vers_texte( config["naissance"] + datetime.timedelta(days=round(jours)) ) for jours in l_jourst]
         gros_dico["data_dates_poids"]= l_dates_poids
         gros_dico["data_dates_taille"] = l_dates_taille
             
index dac70bff4ec7867ceb2f2f83fceb57f3ac652863..b0b3a1d81b4eeab31fdf62519882f33330f2e646 100644 (file)
@@ -205,7 +205,11 @@ function ajoute_reperes()
        for(var i=nblignes; i<nblignes+nb_additionnel ; i++) 
        {
                var elt = document.createElement("li") ;
-               elt.innerHTML = 'Âge&nbsp;: <input class="data" type="text" name="repere_age_'+i+'" value=""> Texte associé&nbsp;: <input class="texte" type="text" name="repere_texte_'+i+'" value=""> Tracer&nbsp;: <input type="checkbox" name="repere_trace_'+i+'">' ;
+               elt.innerHTML = 'Âge&nbsp;: <input class="data" type="text" name="repere_age_'+i+'" value=""> \
+               ou date&nbsp;: <input type="date" name="repere_date_{{ i }}" value=""> \
+               Texte associé&nbsp;: <input class="texte" type="text" name="repere_texte_'+i+'" value=""> \
+               Tracer&nbsp;: <input type="checkbox" name="repere_trace_'+i+'">\
+               Afficher la date&nbsp;: <input type="checkbox" name="repere_affichedate_{{ i }}">' ;
                eltul.appendChild(elt) ;
        }
        
index 465366c5dd1e4f0a3556e3098fbd9b0ac301ed1d..d374213090e043f19208dce86386d93808f73083 100644 (file)
@@ -39,6 +39,7 @@ function appelle_image()
                                        document.getElementById('sectioncourbe').style.display = "block";
                                        document.getElementById('section_courbe_poids').style.display = "block" ;
                                        document.getElementById('courbe_poids').src = 'data:image/png;base64,'+(image_poids);
+                                       document.getElementById('courbe_poids').alt = 'Courbe de poids de '+nomenfant ;                                 
                                        boutondl = document.getElementById("courbe_dl_poids") ;
                                        boutondl.setAttribute('onclick',"download_file('courbe_poids_"+nomenfant+".png', 'image/png;base64','"+image_poids +"')")
                                }
@@ -50,6 +51,7 @@ function appelle_image()
                                        document.getElementById('sectioncourbe').style.display = "block";
                                        document.getElementById('section_courbe_taille').style.display = "block" ;
                                        document.getElementById('courbe_taille').src = 'data:image/png;base64,'+(image_taille);
+                                       document.getElementById('courbe_taille').alt = 'Courbe de taille de '+nomenfant ;               
                                        boutondl = document.getElementById("courbe_dl_taille") ;
                                        boutondl.setAttribute('onclick',"download_file('courbe_taille_"+nomenfant+".png', 'image/png;base64','"+image_taille +"')")
                            }
index 066f60ee17ec9dd2f7a4e0187cfe726b263f7df3..c23cfc1d7e1b0ae136622db7067c135aa2c3f487 100644 (file)
@@ -12,7 +12,7 @@
 
 
   <label for="fichier_donnees" class="icon_button">
-       <img src="static/icons/import.png">
+       <img src="static/icons/import.png" alt="Importer">
        <span class="icon_legend">Importer un fichier</span>
   </label>
   <input type="file" name="fichier_donnees" id="fichier_donnees" oninput="upload_file('form_import_donnees')">
@@ -37,7 +37,7 @@
 <h3>Informations sur l'enfant</h3>
 <div>
        <label for="reset_donnees" class="icon_button">
-               <img src="static/icons/trash.png">
+               <img src="static/icons/trash.png" alt="Effacer">
                <span class="icon_legend">Effacer les données du formulaire</span>
        </label>         
        <input type="reset" id="reset_donnees" value="Effacer les données du formulaire">      
                <ul id="ajoutereperecourbe">
                        {% for i in range(valform.liste_reperes | length) %}
                        <li>Âge&nbsp;: <input class="data" type="text" name="repere_age_{{ i }}" value="{{ valform.liste_reperes[i].donnee }}"> 
+                       ou date&nbsp;: <input type="date" name="repere_date_{{ i }}" value="{{ valform.liste_reperes[i].date }}">
                         Texte associé&nbsp;: <input class="texte" type="text" name="repere_texte_{{ i }}" value="{{ valform.liste_reperes[i].texte }}">
-                        Tracer&nbsp;: <input type="checkbox" name="repere_trace_{{ i }}" {% if valform.liste_reperes[i].trace %} checked {% endif %}></li>
+                        Tracer&nbsp;: <input type="checkbox" name="repere_trace_{{ i }}" {% if valform.liste_reperes[i].trace %} checked {% endif %}>
+                        Afficher la date&nbsp;: <input type="checkbox" name="repere_affichedate_{{ i }}" {% if valform.liste_reperes[i].affichedate %} checked {% endif %}>
+                        </li>
                        {% endfor %}
                        {% for j in range(valform.liste_reperes | length, valform.nb_reperes_mini) %}
                        <li>Âge&nbsp;: <input class="data" type="text" name="repere_age_{{ j }}" value=""> 
+                       ou date&nbsp;: <input type="date" name="repere_date_{{ i }}" value="">
                         Texte associé&nbsp;: <input class="texte" type="text" name="repere_texte_{{ j }}" value="">
-                        Tracer&nbsp;: <input type="checkbox" name="repere_trace_{{ j }}"></li>
+                        Tracer&nbsp;: <input type="checkbox" name="repere_trace_{{ j }}">
+                        Afficher la date&nbsp;: <input type="checkbox" name="repere_affichedate_{{ i }}"></li>
+
                        {% endfor %}
                </ul>
                
        {% for val in CONFIG.liste_typedonnees %}
        <option value="{{val}}">{{val}}</option>
        {% endfor %}
-       </select> à l'âge <input type="text" class="data" name="calculextradata_age" value="6m">
+       </select> à l'âge <input type="text" class="data" name="calculextradata_age">
+       ou à la date <input type="date" name="calculextradata_date">
        <input type="checkbox" name="calculextradata_trace"> ... et le voir sur le graphique.</li>
        
        <li>Calculer l'âge auquel l'enfant aura <input type="text" class="data" name="calculextratemps_val">
 <!--- Le grobouton -->
 <div>
        <span onclick="appelle_image()" class="icon_button">
-       <img src="static/icons/courbe.png">
+       <img src="static/icons/courbe.png" alt="Tracer les courbes">
        <span class="icon_legend">Je veux les courbes !</span></span>
        <span id="statut_courbes"></span>
 </div>
 
        <h2>Courbes</h2>
        <div id="section_courbe_poids">
-       <img id="courbe_poids">
+       <img id="courbe_poids" src="" alt="">
 
        <div id="courbe_dl_poids" class="icon_button">
-               <img src="static/icons/export.png">
+               <img src="static/icons/export.png" alt="Exporter la courbe de poids">
                <span class="icon_legend">Télécharger la courbe de poids</span>
        </div>
        </div>
 
        <div id="section_courbe_taille">
-       <img id="courbe_taille">
+       <img id="courbe_taille" src="" alt="">
        
        <div id="courbe_dl_taille" class="icon_button">
-               <img src="static/icons/export.png">
+               <img src="static/icons/export.png" alt="Exporter la courbe de taille">
                <span class="icon_legend">Télécharger la courbe de taille</span>
        </div>
        </div>
        <p>Vous pouvez télécharger les données afin de ne pas avoir à les re-saisir la prochaine fois.</p>
 
        <div id="export_dl" class="icon_button">
-               <img src="static/icons/export.png">
+               <img src="static/icons/export.png" alt="Exporter les données">
                <span class="icon_legend">Télécharger les données</span>
        </div>
-       <p>Si vous n'arrivez pas à télécharger les données, <a href='#export' onclick="affiche_export()">cliquez ici</a> pour les voir en texte clair&nbsp: il vous suffira de les copier/coller dans un fichier texte.</p>
+       <p>Si vous n'arrivez pas à télécharger les données, <a href='#export' onclick="affiche_export()">cliquez ici</a> pour les voir en texte clair&nbsp;: il vous suffira de les copier/coller dans un fichier texte.</p>
        <div id="export">
        <textarea readonly id="export_texte">
        </textarea>
index c39f2657b9c15217cd5cc167407b4639ca7e3ca0..e29359f2e99ff00bef5cb4d663fc3903134a45b5 100644 (file)
@@ -6,6 +6,7 @@ import gestion_unites as u
 from gestion_donnees import calcule_max_graphique, convertit_jours_vers_python
 from gestion_erreurs import debug, erreur, warning
 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
+import datetime
 
 from numpy import arange
 
@@ -227,7 +228,11 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err, e
                     # On va prendre les extrapolations de la dernière donnée jusqu'à l fin du graphe
                     debut_extr = int(l_jours[-conf["non_sauve"]["nbextradata"]])
                     i_debut_extr = dates_extrapole.index(debut_extr)
-                    i_fin_extr = dates_extrapole.index(jour_maxi)
+                    if jour_maxi >= dates_extrapole[-1]:
+                        i_fin_extr = len(dates_extrapole) -1
+                    else:
+                        i_fin_extr = dates_extrapole.index(jour_maxi)
+                    print("bla", i_debut_extr, i_fin_extr)
                     # Voilà ce qu'on veut tracer
                     dates_extrapole_trace = dates_extrapole[i_debut_extr:i_fin_extr+1]
                     donnees_extrapole_trace = donnees_extrapole[i_debut_extr:i_fin_extr+1]                
@@ -248,11 +253,11 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err, e
                     else:
                         message=formate_interpole()
                     
-                    texte = formate_resultat_donnee(conf["non_sauve"]["calculextradata_age"], r, typedonnee, message, liste_err)
+                    texte = formate_resultat_donnee(conf["non_sauve"]["calculextradata_age"], conf["non_sauve"]["calculextradata_date"], r, typedonnee, message, liste_err)
                     debug("calcul de la donnée extrapolée : "+texte, liste_err)
                     if texte!="":
                         liste_extracalculs.append(texte)
-                        print(liste_extracalculs)
+                        #print(liste_extracalculs)
                         # Ajouter le trait ?
                         if conf["non_sauve"]["calculextradata_trace"] == "oui":
                             dessine_guides(conf["non_sauve"]["calculextradata_age"], r, conf["couleurs"]["cadretxt"], unite, ax, liste_err)
@@ -261,14 +266,23 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err, e
                 if conf["non_sauve"]["calculextratemps_type"] == typedonnee:
                     # interpolation
                     r = interpole_lineaire_ordonnee(l_jours,l_poids,conf["non_sauve"]["calculextratemps_val"], liste_err)
+                    if type(conf["naissance"]) == datetime.date:
+                        rdate = conf["naissance"] + datetime.timedelta(days=r)
+                    else:
+                        rdate = None
+                    
                     if r==-1:
                         # ça sera donc une extrapolation
-                        r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], liste_err)          
+                        r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], liste_err)
+                        if type(conf["naissance"]) == datetime.date:
+                            rdate = conf["naissance"] + datetime.timedelta(days=round(r))
+                        else:
+                            rdate = None
                         message=formate_extrapole(conf["non_sauve"]["nbextradata"])
                     else:
                         message=formate_interpole()
-                    
-                    texte = formate_resultat_age(r, conf["non_sauve"]["calculextratemps_val"], typedonnee, message, liste_err)
+                    print(r, rdate)
+                    texte = formate_resultat_age(r, rdate, conf["non_sauve"]["calculextratemps_val"], typedonnee, message, liste_err)
                     
                     #r = calcule_age_extrapole(dates_extrapole, donnees_extrapole, conf["non_sauve"]["calculextratemps_val"], typedonnee, liste_err)
                     if texte!="":
@@ -318,7 +332,10 @@ def cree_figure(conf,l_jours,l_poids,typedonnee,liste_extracalculs, liste_err, e
             agec = u.convertitunite(rep["donnee"], unite, liste_err)
             # Tracé de la ligne verticale
             ax.vlines(agec, poids_min, poids_max, linestyles="dashed", color=conf["couleurs"]["cadretxt"])
-            # Tracé éventuel du texte
+            # date à afficher ?
+            if rep["affichedate"] == "oui" and rep["date"] != "":
+                ax.text(agec, poids_min,rep["date"]+" ", rotation=90, verticalalignment='top', horizontalalignment='center', color=conf["couleurs"]["cadretxt"], fontstyle="italic")
+            # Si y'a un texte à afficher
             if rep["texte"] != "":
                 ax.text(agec, poids_min, " "+rep["texte"], rotation=90, verticalalignment='bottom', horizontalalignment='right', color=conf["couleurs"]["cadretxt"])