diff options
author | Denise sur Lya <sekhmet@lya> | 2020-06-16 00:32:10 +0200 |
---|---|---|
committer | Denise sur Lya <sekhmet@lya> | 2020-06-16 00:32:10 +0200 |
commit | 66a3e38cc085dc000776d3e2ad3acd7ef57068a3 (patch) | |
tree | 1cfb7b1953596c6bd3e01706a20bb6e7e10d3bca | |
parent | 9cb3c31c54b868e0c3a335ef3a4b4cdc81e479fb (diff) | |
download | oms-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.txt | 18 | ||||
-rw-r--r-- | app.py | 31 | ||||
-rw-r--r-- | faq.py | 51 | ||||
-rw-r--r-- | gestion_donnees.py | 8 | ||||
-rw-r--r-- | static/requetes.js | 46 | ||||
-rw-r--r-- | static/style.css | 4 | ||||
-rw-r--r-- | templates/base.html | 1 | ||||
-rw-r--r-- | templates/faq.html | 30 | ||||
-rw-r--r-- | templates/index.html | 8 |
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> | ||
6 | Si 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à." | ||
@@ -8,6 +8,8 @@ from gestion_erreurs import * | |||
8 | from gestion_donnees import * | 8 | from gestion_donnees import * |
9 | from gestion_unites import * | 9 | from gestion_unites import * |
10 | from trace_courbe import * | 10 | from trace_courbe import * |
11 | from faq import * | ||
12 | |||
11 | import matplotlib.pyplot as plt | 13 | import matplotlib.pyplot as plt |
12 | 14 | ||
13 | import base64 | 15 | import 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 | # Ré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") | ||
88 | def 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 | |||
75 | if __name__ == "__main__": | 96 | if __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 |
@@ -0,0 +1,51 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | # -*- coding: utf-8 -*- | ||
3 | ### Les fonctions et données pour la FAQ | ||
4 | |||
5 | import csv | ||
6 | fichier_FAQ = "FAQ_data.txt" | ||
7 | |||
8 | # Les questions seront dans une database sous la forme (categorie,question,reponse) | ||
9 | |||
10 | def 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 | |||
27 | def 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 | |||
36 | def 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 | |||
19 | function 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 sé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> |