summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenise sur Lya <sekhmet@lya>2020-06-16 00:32:10 +0200
committerDenise sur Lya <sekhmet@lya>2020-06-16 00:32:10 +0200
commit66a3e38cc085dc000776d3e2ad3acd7ef57068a3 (patch)
tree1cfb7b1953596c6bd3e01706a20bb6e7e10d3bca
parent9cb3c31c54b868e0c3a335ef3a4b4cdc81e479fb (diff)
downloadoms-66a3e38cc085dc000776d3e2ad3acd7ef57068a3.tar.gz
oms-66a3e38cc085dc000776d3e2ad3acd7ef57068a3.tar.zst
oms-66a3e38cc085dc000776d3e2ad3acd7ef57068a3.zip
Ajout de la FAQ, correction de bugs. Meilleure requête de courbe.
-rw-r--r--FAQ_data.txt18
-rw-r--r--app.py31
-rw-r--r--faq.py51
-rw-r--r--gestion_donnees.py8
-rw-r--r--static/requetes.js46
-rw-r--r--static/style.css4
-rw-r--r--templates/base.html1
-rw-r--r--templates/faq.html30
-rw-r--r--templates/index.html8
9 files changed, 167 insertions, 30 deletions
diff --git a/FAQ_data.txt b/FAQ_data.txt
new file mode 100644
index 0000000..cce0a2d
--- /dev/null
+++ b/FAQ_data.txt
@@ -0,0 +1,18 @@
1"Utilisation","Comment tracer la courbe ?","Remplissez le formulaire (vous pouvez laisser par défaut tous les champs qui ne vous « parlent » pas), puis cliquez sur ""Je veux la courbe !"". La courbe s'affiche plus bas. Si vous modifiez les données du formulaire, vous pouvez re-cliquer sur ce bouton pour la mettre à jour. Et c'est tout !"
2
3"Utilisation","Comment sauvegarder mes données pour une prochaine fois ?","L'outil ne propose pas de sauvegarde en ligne, car il ne garde aucune donnée personnelle. Quand vous demandez à tracer la courbe, il s'affiche en bas un champ de texte. Si vous copiez-collez ce contenu et le gardez dans un fichier, vous n'aurez pas à re-saisir les données. Utilisez la partie ""Importer le fichier de données"" puis ""Charger les données"" : les champs seront alors pré-remplis et vous pourrez les modifier ou ajouter des données (par exemple une pesée récente)."
4
5"Utilisation","Je ne comprends pas comment saisir les données âge/poids !","Pour chaque pesée, vous avez le choix entre donner son âge, ou donner la date de la pesée. Pour la date de la pesée, il faut que vous ayiez rempli la date de naissance (sinon l'outil ne peut pas calculer l'âge !). Pour l'âge, vous pouvez indiquer en années, mois, semaines, jours, et mélanger plusieurs unités. Par exemple 2m3j pour « 2 mois 3 jours ». Ne remplissez qu'un des deux champs : âge ou date. Puis saisissez le poids en kilogrammes dans la colonne de droite. <br>
6Si vous manquez de lignes, vous pouvez cliquer sur ""Ajouter des lignes"" pour avoir plus de champs de données. Il n'y a pas de problème à laisser des champs vides, ils seront simplement ignorés."
7
8"Courbe","À quoi sert ce site ?","Il sert à tracer la courbe de poids des bébés et jeunes enfants en fonction de leur âge, comme sur le carnet de santé, et la compare aux courbes de références de l'Organisation Mondiale de la Santé."
9
10"Courbe","Pourquoi des courbes OMS et pas des courbes françaises ?","Les particularités de ces données sont les suivantes : bébés et enfants choisis dans différents pays du monde (et non dans un seul pays), dans des familles raisonnablement aisées (pour éviter les problèmes liés à la malnutrition), et des bébés allaités. Plus d'infos <a href=""https://www.who.int/childgrowth/standards/technical_report/en/"">ici</a> (en anglais). L'idée générale était de donner une « référence » de croissance de l'enfant de l'espèce humaine. Cela ne veut pas dire que les courbes du carnet de santé français sont mauvaises (si vous avez celles datant d'avant 2018, elles sont un peu anciennes par contre), de fait, elles sont très peu différentes. Pour les autres pays je ne sais pas, je n'ai pas comparé."
11
12"Courbe","Mon enfant doit-il être dans la moyenne ?","Il y a des petits bébés, des gros bébés, des bébés moyens. En général, un bébé en bonne santé ""suit"" un couloir de courbe, que ce soit la courbe des « bébés crevettes » ou des « bébés dodus ». Un changement de couloir (poids en baisse le plus souvent) peut éventuellement être signe d'un problème. Ou pas. Dans tous les cas, référez vous à des professionnels de santé et/ou de la petite enfance."
13
14"Divers","Pourquoi cet outil ?","Tout a commencé sur le <a href=""https://forum.lllfrance.org/"">forum de La Leche League</a>, où de nombreuses mamans (et parfois quelques papas) viennent poser des questions sur l'allaitement. Souvent, se pose la question de la prise de poids du bébé, qui est un bon indicateur de si le bébé reçoit assez de lait. Le poids dans l'absolu étant peu pertinent, il est utile de « tracer » la courbe de poids. Il n'existe actuellement que peu d'outils qui permettent de le faire (l'OMS en fournit un qui ne fonctionne que sous windows), en voici un."
15
16"Divers","Mais qui es tu donc ?","Je suis une de ces nombreuses mamans qui s'est posée un jour (et un autre jour aussi) la question de la prise de poids de son enfant. Adepte de solutions libres et multi-plateforme, je n'ai rien trouvée qui me permette de tracer cette courbe, que ce soit pour mon enfant ou celui des autres. Je suis par ailleurs férue de programmation (et je l'enseigne d'ailleurs), et donc... voilà."
17
18"Technique","Quelle est la technologie utilisée derrière ?","Il s'agit de <a href=""https://flask.palletsprojects.com/en/1.1.x/"">flask</a>, un petit framework de développement web en <a href=""https://www.python.org/"">python</a>. Il y a une petite dose de <a href=""https://developer.mozilla.org/fr/docs/Web/JavaScript"">JavaScript</a> pour assaisonner le tout, et voilà."
diff --git a/app.py b/app.py
index 7348472..4f330d9 100644
--- a/app.py
+++ b/app.py
@@ -8,6 +8,8 @@ from gestion_erreurs import *
8from gestion_donnees import * 8from gestion_donnees import *
9from gestion_unites import * 9from gestion_unites import *
10from trace_courbe import * 10from trace_courbe import *
11from faq import *
12
11import matplotlib.pyplot as plt 13import matplotlib.pyplot as plt
12 14
13import base64 15import base64
@@ -40,17 +42,27 @@ def courbe_image(ext):
40 liste_err = initialise_erreurs() 42 liste_err = initialise_erreurs()
41 data = flask.request.form 43 data = flask.request.form
42 44
43 config = gere_configuration(data,liste_err) 45 # gler la configuration et les données
44 46 config = gere_configuration(data,liste_err)
45 l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err) 47 l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err)
48
49 # préparer l'export
50 texte = configuration_vers_texte(config)
51 texte += donnees_poids_vers_texte(l_jours,l_poids)
52
53 # créer la figure
46 fig = cree_figure(config,l_jours,l_poids,liste_err) 54 fig = cree_figure(config,l_jours,l_poids,liste_err)
47
48 output = io.BytesIO() 55 output = io.BytesIO()
49 FigureCanvas(fig).print_png(output) 56 FigureCanvas(fig).print_png(output)
50
51 plt.close(fig) 57 plt.close(fig)
58
52 if ext == "b64": 59 if ext == "b64":
53 return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain') 60 reponse = flask.jsonify({ "result":"success",
61 "messages": liste_err[1],
62 "image": base64.b64encode(output.getvalue()).decode("ascii"),
63 "export_txt": texte})
64 return reponse
65 #return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain')
54 elif ext == "png": 66 elif ext == "png":
55 return flask.Response(output.getvalue(), mimetype='image/png') 67 return flask.Response(output.getvalue(), mimetype='image/png')
56 else: 68 else:
@@ -72,5 +84,14 @@ def export_donnees():
72 84
73 return flask.Response(texte,mimetype="text/plain") 85 return flask.Response(texte,mimetype="text/plain")
74 86
87@app.route("/faq")
88def faq():
89
90 table_faq = lire_fichier_csv_simple(fichier_FAQ)
91 l_categ,table_qr = extraire_tables_par_cat(table_faq)
92
93 return flask.render_template("faq.html",lcateg=l_categ,tableqr=table_qr,err=[])
94
95
75if __name__ == "__main__": 96if __name__ == "__main__":
76 app.run(host='0.0.0.0',debug=True) \ No newline at end of file 97 app.run(host='0.0.0.0',debug=True) \ No newline at end of file
diff --git a/faq.py b/faq.py
new file mode 100644
index 0000000..4ee8bfa
--- /dev/null
+++ b/faq.py
@@ -0,0 +1,51 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3### Les fonctions et données pour la FAQ
4
5import csv
6fichier_FAQ = "FAQ_data.txt"
7
8# Les questions seront dans une database sous la forme (categorie,question,reponse)
9
10def lire_fichier_csv_simple(fichier):
11 """ lire un fichier csv et le renvoyer en table"""
12 table=[]
13 with open(fichier, "r") as fichier_csv:
14 reader_notes = csv.reader(fichier_csv,delimiter=",",dialect="unix")
15 for ligne in reader_notes:
16 if ligne != []:
17 table.append(ligne)
18 return table
19
20
21
22
23
24# On trie par catégorie
25#table_faq.sort(key=(lambda x: x[0]))
26
27def extraire_categories(table):
28 """ extrait les catégories (1ere colonne du tableau de tableau)
29 renvoie sous forme de liste"""
30 liste_cat = []
31 for ligne in table:
32 if not (ligne[0] in liste_cat):
33 liste_cat.append(ligne[0])
34 return liste_cat
35
36def extraire_tables_par_cat(table):
37 """ construit deux tables : une de catégories, une de tables de (q,r)
38 categ[i] va correspondre à tableqr[i] en terme de catégorie"""
39 categ = extraire_categories(table)
40 tableqr = [ [] for i in range(len(categ)) ]
41
42 for ligne in table:
43 try:
44 cat = ligne[0]
45 (q,r) = [ligne[1],ligne[2]]
46 ind = categ.index(cat)
47 tableqr[ind].append((q,r))
48 except:
49 print("Impossible de lire la ligne : "+str(ligne))
50
51 return (categ,tableqr)
diff --git a/gestion_donnees.py b/gestion_donnees.py
index 82491ca..9584386 100644
--- a/gestion_donnees.py
+++ b/gestion_donnees.py
@@ -73,12 +73,12 @@ def convertit_poids_vers_python(chaine,liste_err):
73 chaine2 = chaine2.replace(" ","") 73 chaine2 = chaine2.replace(" ","")
74 74
75 try: 75 try:
76 poids = float(chaine) 76 poids = float(chaine2)
77 except: 77 except:
78 warning("Poids impossible à lire : "+chaine,liste_err) 78 warning("Poids impossible à lire : "+chaine,liste_err)
79 poids = 0 79 poids = 0
80 if not( 0<poids<poids_maxi): 80 if not( 0<=poids<poids_maxi):
81 warning("Poids incohérent : "+poids) 81 warning("Poids incohérent : "+str(poids),liste_err)
82 poids = 0 82 poids = 0
83 return poids 83 return poids
84 84
@@ -321,4 +321,4 @@ def fichier_texte_vers_configdonnees(fichier,liste_err):
321 #le nb max du formulaire 321 #le nb max du formulaire
322 valform["nb_data"] = indice_formulaire +2 322 valform["nb_data"] = indice_formulaire +2
323 323
324 return valform \ No newline at end of file 324 return valform
diff --git a/static/requetes.js b/static/requetes.js
index 41fd850..9da579c 100644
--- a/static/requetes.js
+++ b/static/requetes.js
@@ -5,31 +5,39 @@ function appelle_image()
5 var formData = new FormData( document.getElementById("donnees_enfant") ); 5 var formData = new FormData( document.getElementById("donnees_enfant") );
6 6
7 var requete = new XMLHttpRequest(); 7 var requete = new XMLHttpRequest();
8 requete.responseType = "json";
8 requete.onreadystatechange = function() 9 requete.onreadystatechange = function()
9 { 10 {
10 if (this.readyState == 4 && this.status == 200) { 11 if (this.readyState == 4 && this.status == 200) {
11 document.getElementById('courbe').src = 'data:image/png;base64,'+(this.response); 12 // on récupère les différents champs de la réponse
13 var image = this.response.image ;
14 var liste_warnings = this.response.messages
15 var texte = this.response.export_txt;
16 // On affiche l'image
17 document.getElementById('courbe').src = 'data:image/png;base64,'+(image);
12 document.getElementById('sectioncourbe').style.display = "block"; 18 document.getElementById('sectioncourbe').style.display = "block";
19
20 // on affiche l'export des données
21 document.getElementById('export').innerHTML = texte;
22 document.getElementById('sectionexport').style.display = "block";
23
24 // Si y'a eu des warnings, faut les afficher
25 if(liste_warnings.length != 0)
26 {
27 // afficher la liste des warnings
28 var elem_div = document.getElementById('courbe_warnings') ;
29 elem_div.style.display = "block" ;
30 var ul = elem_div.children[1] ;
31 for(i=0; i<liste_warnings.length; i++) {
32 var li = document.createElement("li");
33 li.appendChild(document.createTextNode(liste_warnings[i]));
34 ul.appendChild(li);
35 }
36
37
38 }
13 } 39 }
14 } 40 }
15 requete.open("POST","courbe/b64",true) 41 requete.open("POST","courbe/b64",true)
16 requete.send(formData) 42 requete.send(formData)
17} 43}
18
19function exporte_donnees()
20{
21 var formData = new FormData( document.getElementById("donnees_enfant") );
22
23 var requete = new XMLHttpRequest();
24 requete.onreadystatechange = function()
25 {
26 if (this.readyState == 4 && this.status == 200) {
27 document.getElementById('export').innerHTML = this.responseText;
28 document.getElementById('sectionexport').style.display = "block";
29 }
30 }
31 requete.open("POST","export_donnees",true)
32 requete.send(formData)
33
34
35}
diff --git a/static/style.css b/static/style.css
index 58ddc3b..3216d34 100644
--- a/static/style.css
+++ b/static/style.css
@@ -14,3 +14,7 @@ body {
14 width: 25em; 14 width: 25em;
15 height: 20em; 15 height: 20em;
16} 16}
17
18#courbe_warnings {
19 display: none;
20}
diff --git a/templates/base.html b/templates/base.html
index 571292f..20e1dd5 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -33,6 +33,7 @@
33 33
34 <nav><a href="/">Accueil et saisie des données</a> | 34 <nav><a href="/">Accueil et saisie des données</a> |
35 <a href="/apropos">À propos</a> | 35 <a href="/apropos">À propos</a> |
36 <a href="faq">Foire Aux Questions</a>
36 </nav> 37 </nav>
37 38
38 </body> 39 </body>
diff --git a/templates/faq.html b/templates/faq.html
new file mode 100644
index 0000000..301f5d7
--- /dev/null
+++ b/templates/faq.html
@@ -0,0 +1,30 @@
1{% extends "base.html" %}
2{% block contenu %}
3<h2>Foire Aux Questions</h2>
4
5<div id="sommaire">
6<ul>{% for cat in lcateg %}
7<li><a href="#{{ cat }}">{{ cat }}</a></li>
8{% endfor %}
9</ul>
10</div>
11
12<div id="questionsreponses">
13{% for i in range(lcateg|length) %}
14{% set qr = tableqr[i] %}
15
16<h3 id="{{ lcateg[i] }}">{{ lcateg[i] }}</h3>
17<ul>
18 {% for (q,r) in qr %}
19 <li><p><strong>Q : </strong>{{ q|safe }}</p>
20 <p><strong>R : </strong>{{ r|safe }}</p>
21 </li>
22 {% endfor %}
23</ul>
24
25
26{% endfor %}
27</div>
28
29
30{% endblock %}
diff --git a/templates/index.html b/templates/index.html
index f9de4a5..3d81e3e 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -55,7 +55,7 @@ Position : <select name="positionlegende">
55 55
56<h3>Données de poids</h3> 56<h3>Données de poids</h3>
57<p>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.</p> 57<p>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.</p>
58<p>Saisir le poids en kilogrammes (le point et la virgule comptent comme le parateur virgule).</p> 58<p>Saisir le poids en kilogrammes (par exemple "2.62" ou "2,62" pour 2 kilogrammes et 620 grammes).</p>
59<p>Il faut saisir la date ou l'âge. Si les deux sont saisis, seul l'âge comptera.</p> 59<p>Il faut saisir la date ou l'âge. Si les deux sont saisis, seul l'âge comptera.</p>
60 60
61<p>Si le tableau est laissé vide, cela génère une courbe "vide" de référence.</p> 61<p>Si le tableau est laissé vide, cela génère une courbe "vide" de référence.</p>
@@ -77,7 +77,7 @@ Position : <select name="positionlegende">
77 77
78<hr> 78<hr>
79 79
80<button onclick="appelle_image(); exporte_donnees()">Je veux la courbe !</button> 80<button onclick="appelle_image()">Je veux la courbe !</button>
81 81
82 82
83<div id="sectioncourbe"> 83<div id="sectioncourbe">
@@ -85,6 +85,10 @@ Position : <select name="positionlegende">
85<h2>Courbe</h2> 85<h2>Courbe</h2>
86<img id="courbe"> 86<img id="courbe">
87</div> 87</div>
88<div id="courbe_warnings">
89<p><strong>Alerte :</strong> la courbe a eu quelques soucis à se générer. Voici la liste des erreurs.</p>
90<ul></ul>
91</div>
88 92
89<div id="sectionexport"> 93<div id="sectionexport">
90<h2>Export des données</h2> 94<h2>Export des données</h2>