From ca61f310d80e05ea43efc148787f214a567743f0 Mon Sep 17 00:00:00 2001
From: Denise sur Lya
Date: Tue, 29 Jun 2021 23:04:02 +0200
Subject: [PATCH] =?utf8?q?nouveaut=C3=A9=20:=20courbes=20multiples?=
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit
---
app.py | 26 +++-
configuration.py | 8 ++
data/changelog_data.txt | 8 ++
gestion_donnees.py | 286 ++++++++++++++++++++++------------------
gestion_erreurs.py | 4 +-
static/outilspage.js | 19 +++
static/requetes.js | 4 +-
static/style.css | 6 +-
templates/index.html | 45 +++++--
trace_courbe.py | 47 +++++--
10 files changed, 298 insertions(+), 155 deletions(-)
diff --git a/app.py b/app.py
index c4dfc93..a803d90 100644
--- a/app.py
+++ b/app.py
@@ -8,7 +8,7 @@ import base64
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from configuration import config_init,CONFIG
-from gestion_erreurs import initialise_erreurs, debug, niveau_debug
+from gestion_erreurs import initialise_erreurs, debug, niveau_debug, warning
import gestion_donnees as donnees
from trace_courbe import cree_figure
import faq as f
@@ -55,7 +55,27 @@ def apropos():
def courbe_image(ext):
liste_err = initialise_erreurs()
data = flask.request.form
-
+ enfants_add = [] # Enfants additionnels
+ for i in range(2, 11):
+ if 'fichier_donnees_'+str(i) in flask.request.files: # UUn enfant à ajouter
+ fichier = flask.request.files["fichier_donnees_"+str(i)]
+ chaine = fichier.read() # On récupère la chaîne
+ if len(chaine)>=5: # Si elle a une longueur à peu près raisonnable
+ debug("Un fichier de données additionnel trouvé", liste_err)
+ formulaire_2 = donnees.fichier_json_vers_configdonnees(chaine, liste_err)
+ if formulaire_2 =={}:
+ warning("Le fichier de données additionnel est vide ou mal formaté", liste_err)
+ else:
+ #debug("Form 2 : "+str(formulaire_2), liste_err)
+ # Récupérer sous forme python
+ conf2, ljours2, listes_donnees2 = donnees.web_vers_python(formulaire_2,liste_err, court=True)
+ # Et le symbole
+ symb2 = donnees.gere_symbole(data.get("symbole_donnees_"+str(i)))
+
+ enfant2 = donnees.eclate_donnees_additionnelles(conf2, ljours2, listes_donnees2, symb2)
+ enfants_add.append(enfant2)
+
+
# 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)
@@ -75,7 +95,7 @@ def courbe_image(ext):
for typed in CONFIG["liste_typedonnees"]:
if config["tracevide"] == "oui" or listes_jours[typed] != []:
debug("On trace la courbe de "+typed,liste_err)
- fig = cree_figure(config,listes_jours[typed],listes_donnees[typed],typed,liste_extracalculs, liste_err)
+ fig = cree_figure(config,listes_jours[typed],listes_donnees[typed],typed,liste_extracalculs, liste_err, enfants_add)
output = io.BytesIO()
FigureCanvas(fig).print_png(output)
plt.close(fig)
diff --git a/configuration.py b/configuration.py
index 2a0cb28..75088fe 100644
--- a/configuration.py
+++ b/configuration.py
@@ -14,6 +14,11 @@ CONFIG["arrondis_typedonnees"] = {"poids": 0.01, "taille": 1}
# Liste des calculs additionnels
CONFIG["extradata"] = ["calculextradata", "calculextratemps"]
+# Liste des symboles autorisés pour les enfants (matplotlib).
+# Sous forme "item: description"
+CONFIG["liste_symboles"] = {"o": "●", "^": "▲", "v": "▼", "<": "◀", ">": "▶", "s": "■", "p": "⬟", "P": "➕", "x": "×", "D": "◆" }
+
+
# fichiers
CONFIG["chemin_oms"] = "data_OMS/"
@@ -109,6 +114,9 @@ DEFAUT["couleurs"]["fond"]= "#FFFFFF" # blanc
DEFAUT["couleurs"]["cadretxt"] = "#000000" # noir
DEFAUT["couleurs"]["grille"] = "#7f7f7f" # gris
+DEFAUT["symbole"] = "o" # Symbole par défaut
+
+
# Remplissage du formulaire, autres
DEFAUT["age_0"]= "0j"
DEFAUT["legende"] = "oui"
diff --git a/data/changelog_data.txt b/data/changelog_data.txt
index 25f7791..5726bce 100644
--- a/data/changelog_data.txt
+++ b/data/changelog_data.txt
@@ -1,3 +1,11 @@
+"Version 2.4","29/06/2021","Plus de courbes !
+
+- Les données et la configuration sont celles de l'enfant qu'on a saisi en ""principal""
+- Pour les enfants en plus, il faut déjà avoir le fichier de données déjà généré.
+- On peut choisir ses symboles pour la courbe ""principale"" ainsi que les autres.
+
+
"
+
"Version 2.31","28/04/2021","Les calculs de données sont améliorés :
- Si l'âge demandé (ou la donnée) est entre les données saisies, c'est une simple interpolation linéaire entre les données existantes,
diff --git a/gestion_donnees.py b/gestion_donnees.py
index 7c22997..8fee99c 100644
--- a/gestion_donnees.py
+++ b/gestion_donnees.py
@@ -101,9 +101,13 @@ def simplifie_nom(chaine):
def convertit_donnee_vers_python(chaine,typedonnee,liste_err):
""" convertit une chaine vers un float qui est le type donnee voulu.
La virgule peut être . ou , et on vire d'éventuels espaces.
- Taille invalide : on renvoie 0 avec un warning."""
+ Taille invalide : on renvoie 0 avec un warning.
+ Si la chaine est en fait déjà au format float, on laisse tel quel"""
+ if type(chaine) == float:
+ return chaine
chaine2 = chaine.replace(",",".")
chaine2 = chaine2.replace(" ","")
+
try:
donnee = float(chaine2)
@@ -162,12 +166,14 @@ def delta_date(date1,datenaissance):
################### On regroupe tout ce qui gère les données en une fonction
-def web_vers_python(data,liste_err):
+def web_vers_python(data,liste_err, court=False):
""" prend en argument le dictionnaire de requête et renvoie la config, et les
- tableaux de donnée"""
+ tableaux de donnée
+ court : si True est précisé, on ne met que le nom dans la config (enfant
+ additionnel)"""
# Régler la configuration
- config = gere_configuration(data,liste_err)
+ config = gere_configuration(data,liste_err, court)
# récupérer les données
listes_jours = {}
@@ -178,7 +184,7 @@ def web_vers_python(data,liste_err):
# Si on veut extrapoler au-delà du jour maxi, on adapte
# Si on a choisi la même échelle de données
- if config["memechelle"] == "oui":
+ if config.get("memechelle") == "oui":
config["non_sauve"]["maxi"] = calcule_max_graphique([j for lj in listes_jours.values() for j in lj])
# En cas d'extrapolation, on prend le maxi
if config["non_sauve"]["calculextradata_type"] !="" and config["non_sauve"]["calculextradata_age"]>config["non_sauve"]["maxi"]:
@@ -199,10 +205,20 @@ def gere_checkbox(chaine):
else:
return ""
-def gere_configuration(data,liste_err):
+def gere_symbole(chaine):
+ """ prend en arg une chaîne genre "o", ">" et vérifie si c'est un symbole valide.
+ Renvoie ce symbole-là ou le défaut"""
+ if chaine in CONFIG["liste_symboles"]:
+ return chaine
+ else:
+ return DEFAUT["symbole"]
+
+def gere_configuration(data,liste_err, court=False):
""" prend en argument le dictionnaire de requête (configuration imparfaite), et
construit le dictionnaire de configuration qui va bien.
- Vérifie que chaque entrée est cohérente évidemment."""
+ Vérifie que chaque entrée est cohérente évidemment.
+ court : si mis à True, on ne met que le nom dans la configuraion,
+ ainsi que la date de naissance et le sexe"""
# Initialisation
configuration = {"non_sauve": {}}
@@ -210,137 +226,141 @@ def gere_configuration(data,liste_err):
nom = data.get("nom","")
# Par contre s'il est trop long on le tronque
configuration["nom"] = nom[:CONFIG["longueur_max_nom_bebe"]]
-
- sexe = data.get("sexe","")
- if not (sexe in ["F","M","N"]):
- warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
- sexe = "N"
- configuration["sexe"] = sexe
-
+
naissance = data.get("naissance","")
if naissance !="":
naissance = convertit_date_vers_python(naissance,liste_err)
configuration["naissance"] = naissance
- prematurite = data.get("prematurite","")
- j = convertit_jours_vers_python(prematurite,liste_err)
- configuration["prematurite"] = convertit_age_vers_texte(j)
-
- configuration["agecorrige"] = gere_checkbox(data.get("agecorrige",""))
-
- # Type de courbe. Au pire on met P
- tyc = data.get("typecourbe","")
- if not (tyc in ["P","Z"]):
- tyc = "P"
- configuration["typecourbe"] = tyc
-
- # unité
- unite = data.get("unite","")
- if not (unite in CONFIG["liste_unites"]):
- unite = ""
- #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
- configuration["unite"] = unite
-
- # grille
- configuration["grille"] = gere_checkbox(data.get("grille",""))
-
- # tracer ou non les courbes vides
- configuration["tracevide"] = gere_checkbox(data.get("tracevide",""))
+ sexe = data.get("sexe","")
+ if not (sexe in ["F","M","N"]):
+ warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
+ sexe = "N"
+ configuration["sexe"] = sexe
+
+ if not(court):
+
+ prematurite = data.get("prematurite","")
+ j = convertit_jours_vers_python(prematurite,liste_err)
+ configuration["prematurite"] = convertit_age_vers_texte(j)
- # Même échelle sur tous les graphiques
- configuration["memechelle"] = gere_checkbox(data.get("memechelle",""))
-
-
- # maxi. 0 signifie qu'on veut pas de maxi
- maxi = data.get("maxi","")
- if maxi == "":
- configuration["maxi"] = 0
- else:
- configuration["maxi"] = int(convertit_jours_vers_python(maxi,liste_err))
+ configuration["agecorrige"] = gere_checkbox(data.get("agecorrige",""))
+
+ # Type de courbe. Au pire on met P
+ tyc = data.get("typecourbe","")
+ if not (tyc in ["P","Z"]):
+ tyc = "P"
+ configuration["typecourbe"] = tyc
+
+ # unité
+ unite = data.get("unite","")
+ if not (unite in CONFIG["liste_unites"]):
+ unite = ""
+ #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
+ configuration["unite"] = unite
+
+ # grille
+ configuration["grille"] = gere_checkbox(data.get("grille",""))
+
+ # tracer ou non les courbes vides
+ configuration["tracevide"] = gere_checkbox(data.get("tracevide",""))
+
+ # Même échelle sur tous les graphiques
+ configuration["memechelle"] = gere_checkbox(data.get("memechelle",""))
- # dimensions du graphique
- largeur = data.get("largeur","")
- if largeur == "":
- largeur = DEFAUT["largeur_graphique"]
- else:
- try:
- largeur = int(largeur)
- except:
- warning("La largeur "+largeur+"est invalide !",liste_err)
+
+ # maxi. 0 signifie qu'on veut pas de maxi
+ maxi = data.get("maxi","")
+ if maxi == "":
+ configuration["maxi"] = 0
+ else:
+ configuration["maxi"] = int(convertit_jours_vers_python(maxi,liste_err))
+
+ # dimensions du graphique
+ largeur = data.get("largeur","")
+ if largeur == "":
largeur = DEFAUT["largeur_graphique"]
- if largeur > CONFIG["largeur_graphique_max"]:
- largeur = CONFIG["largeur_graphique_max"]
- warning("Largeur du graphique trop grande !",liste_err)
- elif largeur < CONFIG["largeur_graphique_min"]:
- largeur = CONFIG["largeur_graphique_min"]
- warning("Largeur du graphique trop petite !",liste_err)
- configuration["largeur"] = largeur
-
- hauteur = data.get("hauteur","")
- if hauteur == "":
- hauteur = DEFAUT["hauteur_graphique"]
- else:
- try:
- hauteur = int(hauteur)
- except:
- warning("La hauteur "+hauteur+"est invalide !",liste_err)
+ else:
+ try:
+ largeur = int(largeur)
+ except:
+ warning("La largeur "+largeur+"est invalide !",liste_err)
+ largeur = DEFAUT["largeur_graphique"]
+ if largeur > CONFIG["largeur_graphique_max"]:
+ largeur = CONFIG["largeur_graphique_max"]
+ warning("Largeur du graphique trop grande !",liste_err)
+ elif largeur < CONFIG["largeur_graphique_min"]:
+ largeur = CONFIG["largeur_graphique_min"]
+ warning("Largeur du graphique trop petite !",liste_err)
+ configuration["largeur"] = largeur
+
+ hauteur = data.get("hauteur","")
+ if hauteur == "":
hauteur = DEFAUT["hauteur_graphique"]
- if hauteur > CONFIG["hauteur_graphique_max"]:
- hauteur = CONFIG["hauteur_graphique_max"]
- warning("Hauteur du graphique trop grande !",liste_err)
- elif hauteur < CONFIG["hauteur_graphique_min"]:
- hauteur = CONFIG["hauteur_graphique_min"]
- warning("Hauteur du graphique trop petite !",liste_err)
- configuration["hauteur"] = hauteur
-
- # existence et position de la légende
- configuration["legende"] = gere_checkbox(data.get("legende",""))
-
- positionlegende = data.get("positionlegende","")
- if not(positionlegende in ['upper left','upper right','lower left','lower right']):
- positionlegende = "upper left"
- configuration["positionlegende"] = positionlegende
+ else:
+ try:
+ hauteur = int(hauteur)
+ except:
+ warning("La hauteur "+hauteur+"est invalide !",liste_err)
+ hauteur = DEFAUT["hauteur_graphique"]
+ if hauteur > CONFIG["hauteur_graphique_max"]:
+ hauteur = CONFIG["hauteur_graphique_max"]
+ warning("Hauteur du graphique trop grande !",liste_err)
+ elif hauteur < CONFIG["hauteur_graphique_min"]:
+ hauteur = CONFIG["hauteur_graphique_min"]
+ warning("Hauteur du graphique trop petite !",liste_err)
+ configuration["hauteur"] = hauteur
+
+ # existence et position de la légende
+ configuration["legende"] = gere_checkbox(data.get("legende",""))
+
+ positionlegende = data.get("positionlegende","")
+ if not(positionlegende in ['upper left','upper right','lower left','lower right']):
+ positionlegende = "upper left"
+ configuration["positionlegende"] = positionlegende
+
+ configuration["couleurs"] = {}
+ # gérer les couleurs
+ for clecouleur in DEFAUT["couleurs"]:
+ coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err)
+ configuration["couleurs"][clecouleur] = coul
+
+ # symbole
+ configuration["symbole"] = gere_symbole( data.get("symbole", ""))
- configuration["couleurs"] = {}
- # gérer les couleurs
- for clecouleur in DEFAUT["couleurs"]:
- coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err)
- configuration["couleurs"][clecouleur] = coul
-
-
- configuration["non_sauve"]["grilleamelio"] = gere_checkbox(data.get("grilleamelio",""))
-
-
- #### La partie extrapolation n'a pas besoin d'être sauvée
- configuration["non_sauve"]["prolongercourbes"] = gere_checkbox(data.get("prolongercourbes",""))
-
- # Valeur par défaut : 1
- debug(data.get("nbextradata", "aaargh"), liste_err)
- nbextradata = data.get("nbextradata",1)
- try:
- nbextradata = int(nbextradata)
- except:
- warning("Le nombre de données sur lequel on extrapole est invalide : "+nbextradata, liste_err)
- nbextradata = 1
- configuration["non_sauve"]["nbextradata"] = nbextradata
+ configuration["non_sauve"]["grilleamelio"] = gere_checkbox(data.get("grilleamelio",""))
- if data.get("calculextradata_type","") in CONFIG["liste_typedonnees"]:
- 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)
- else:
- configuration["non_sauve"]["calculextradata_type"] = ""
- # On ne met rien dans l'âge, pas la peine
- ctyped = data.get("calculextratemps_type","")
- if ctyped in CONFIG["liste_typedonnees"]:
- configuration["non_sauve"]["calculextratemps_type"] = ctyped
- configuration["non_sauve"]["calculextratemps_val"] = convertit_donnee_vers_python(data.get("calculextratemps_val",""), ctyped, liste_err)
- else:
- configuration["non_sauve"]["calculextratemps_type"] = ""
+ #### La partie extrapolation n'a pas besoin d'être sauvée
+ configuration["non_sauve"]["prolongercourbes"] = gere_checkbox(data.get("prolongercourbes",""))
- # Tracer les calculs sur la grille
- configuration["non_sauve"]["calculextradata_trace"] = gere_checkbox(data.get("calculextradata_trace"))
- configuration["non_sauve"]["calculextratemps_trace"] = gere_checkbox(data.get("calculextratemps_trace"))
+ # Valeur par défaut : 1
+ debug(data.get("nbextradata", "aaargh"), liste_err)
+ nbextradata = data.get("nbextradata",1)
+ try:
+ nbextradata = int(nbextradata)
+ except:
+ warning("Le nombre de données sur lequel on extrapole est invalide : "+nbextradata, liste_err)
+ nbextradata = 1
+ configuration["non_sauve"]["nbextradata"] = nbextradata
+
+ if data.get("calculextradata_type","") in CONFIG["liste_typedonnees"]:
+ 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)
+ else:
+ configuration["non_sauve"]["calculextradata_type"] = ""
+ # On ne met rien dans l'âge, pas la peine
+
+ ctyped = data.get("calculextratemps_type","")
+ if ctyped in CONFIG["liste_typedonnees"]:
+ configuration["non_sauve"]["calculextratemps_type"] = ctyped
+ configuration["non_sauve"]["calculextratemps_val"] = convertit_donnee_vers_python(data.get("calculextratemps_val",""), ctyped, liste_err)
+ else:
+ configuration["non_sauve"]["calculextratemps_type"] = ""
+
+ # Tracer les calculs sur la grille
+ configuration["non_sauve"]["calculextradata_trace"] = gere_checkbox(data.get("calculextradata_trace"))
+ configuration["non_sauve"]["calculextratemps_trace"] = gere_checkbox(data.get("calculextratemps_trace"))
return configuration
@@ -492,4 +512,18 @@ def fichier_json_vers_configdonnees(chaine,liste_err):
return valform
-
\ No newline at end of file
+
+#### Pour l'insertion d'une 2e (ou plus) courbe sur le graphique, ue fonction qui sépare tout ça
+def eclate_donnees_additionnelles(conf, ljours, ldonnees, symb):
+ """ conf est la config (on ne garde que le nom) pour un enfant additionnel,
+ ljours et ldonnees les dictionnaires de listes contenant les données.
+ symb est le symbole choisi pour cette courbe additionnelle (déjà vérifié)
+ On fabrique un joli dictionnaire typed -> (conf lj, ldonnee) avec le nom de l'enfant,
+ et les données pour chaque typed"""
+
+ retour = {}
+ conf["symbole"] = symb # On ajoute le symbole additionnel
+ for typed in CONFIG["liste_typedonnees"]:
+ retour[typed] = (conf, ljours[typed], ldonnees[typed])
+
+ return retour
\ No newline at end of file
diff --git a/gestion_erreurs.py b/gestion_erreurs.py
index 910aabd..0e75dd3 100644
--- a/gestion_erreurs.py
+++ b/gestion_erreurs.py
@@ -21,7 +21,9 @@ def erreur(message,listeerreurs):
def warning(message,listeerreurs):
""" En cas d'avertissement mais on peut quand même continuer """
print("** Warning : "+message)
- listeerreurs[1].append("Alerte : "+message)
+ message = "Alerte : "+message
+ if message not in listeerreurs[1]:
+ listeerreurs[1].append(message)
def debug(message,listeerreurs):
global niveau_debug
diff --git a/static/outilspage.js b/static/outilspage.js
index 9491495..9b3f51d 100644
--- a/static/outilspage.js
+++ b/static/outilspage.js
@@ -141,3 +141,22 @@ function change_mode_dates(mode)
elem.innerHTML = "Cliquez ici pour saisir les dates comme du texte."
}
}
+
+function revele_enfants()
+{
+ // révèle tous les champs pour enfants additionnels
+ var listelt = document.getElementsByClassName("enfants_cache_def") ;
+ for(i=0; i
Importer un fichier
-
+
@@ -51,7 +51,7 @@
Saisir les données
Afficher la saisie des tailles.
Syntaxe pour l'âge : utiliser j, s, m, a comme des "unités" (jours, semaines, mois, années). Vous pouvez mixer les unités, par exemple "3a2m5j" pour 3 ans, 2 mois et 5 jours. Les espaces sont ignorées, et il faut saisir des nombres entiers.
-Saisir le poids en kilogrammes (par exemple "2.62" ou "2,62" pour 2 kilogrammes et 620 grammes), ou en grammes (2620 par exemple).
+Saisir le poids en kilogrammes (par exemple "2.62" ou "2,62" pour 2 kilogrammes et 620 grammes), ou en grammes ("2620" par exemple).
Saisir la taille en centimètres. Note : il y a généralement un centimètre de moins quand on mesure l'enfant debout par rapport à allongé. On peut voir sur la courbe de référence une "cassure" à deux ans qui correspond au changement du type de mesure.
Il faut saisir la date ou l'âge. Si les deux sont saisis, seul l'âge comptera.
@@ -73,8 +73,7 @@
Cliquer ici pour ajouter des lignes
-
-
+
Préférences du graphique
Afficher
@@ -109,16 +108,23 @@
- Couleur courbe du bas | Couleur courbe du milieu | Couleur courbe du haut
- Couleur du fond | Couleur de la grille | Couleur des axes, texte et courbe
+ - Symbole pour les points de la courbe :
+
+
-
Extrapolation
Afficher
-