Tutoriel : analyser ses propres données QST en autonomie
SlakeBoard / QuantiSlakeTest - guide pas-à-pas pour un·e nouveau/nouvelle chercheur·se
Table of Contents
- 1. Objectif de ce tutoriel
- 2. Pré-requis
- 3. Étape 0 - Déposer ses données brutes
- 4. Étape 1 - Session R propre
- 5. Étape 2 - Charger les fonctions du labo (le "toolbox")
- 6. Étape 3 - Installer les packages nécessaires (une seule fois)
- 7. Étape 4 - Résoudre les conflits entre packages
- 8. Étape 5 - Importer et fusionner ses données brutes
- 9. Étape 6 (optionnel) - Fichier de bugs global au format Excel
- 10. Étape 7 (optionnel) - Fichier d'informations des parcelles
- 11. Étape 8 - Vérifications de cohérence
- 12. Étape 9 - Nettoyage des données
- 13. Étape 10 - Charger les essais dans un data.frame
- 14. Étape 11 - Vérifier que toutes les courbes se chargent bien
- 15. Étape 12 - Calculer les indicateurs
- 16. Étape 13 - Produire les figures
- 17. Étape 14 - Comparer les indicateurs entre modalités (boxplots)
- 18. Étape 15 - Où trouver ses résultats
- 19. Squelette minimal prêt à copier-coller
- 20. Dépannage
1. Objectif de ce tutoriel
Ce document explique, étape par étape, comment traiter ses propres
données QST (tests de slaking réalisés avec le banc pySlake / QuantiSlakeTest)
dans ce dépôt slaking-lab-plm, sans devoir demander à Fred de le faire pour vous.
Il reprend exactement la même séquence que les notebooks des autres
campagnes (voir report/qst-elisa-2026.org, report/qst-sophie-henry-2025.org,
report/qst-greenotec-2025.org) mais avec les explications en français.
Principe général : chaque essai QST est identifié par 4 informations :
- project (
prj) : le nom du projet (ex :"QST_pole_sol_2025","AET","Greenotec_BRF") - campaign (
cpgn) : le nom de la campagne au sein du projet (ex :"SYCBIO","2025") - parcel : la parcelle
- sample : l'échantillon
Ce sont ces 4 champs que vous avez renseignés au moment de faire tourner
le banc QST (pySlake), et ce sont eux qui structurent toute l'arborescence
./containers/<prj>/<cpgn>/.
2. Pré-requis
- avoir cloné/mis à jour ce dépôt
slaking-lab-plm; - avoir R (et idéalement Emacs+ESS, ou RStudio) ;
- avoir récupéré le(s) dossier(s) de données bruts produits par pySlake
(le dossier qui contient un sous-dossier
containers/) — c'est ce que le banc QST a écrit sur l'ordinateur utilisé pendant la campagne.
3. Étape 0 - Déposer ses données brutes
pySlake écrit ses données dans un dossier local du type :
Geek zone
mon-export-pyslake/ `-- containers/ `-- <prj>/ `-- <cpgn>/ `-- data-raw/ |-- 20_log.txt |-- 21_data_parcels.csv |-- 22_data_samples.csv |-- 23_info_parcels.csv |-- 24_info_samples.csv |-- 25_bugs_report.csv |-- 26_log_book.csv `-- data-slake/ (les courbes brutes, un fichier par essai)
Copiez ce dossier tel quel dans ./data-raw/ de ce dépôt, en le
renommant avec un nom qui vous identifie clairement, par exemple :
pyslake-project-VotrePrenom(ordinateur du labo)pyslake-project-VotrePrenom_2(si vous avez utilisé un 2e ordinateur/balance)
Voyez les dossiers déjà présents pour vous inspirer :
Geek zone
ls ./data-raw/ | grep pyslake
Astuce : si plusieurs balances/ordinateurs ont servi pour la même campagne, copiez chaque export dans un dossier séparé (même préfixe, suffixe différent) : la fusion des données (étape 3) sait recombiner plusieurs sources.
4. Étape 1 - Session R propre
Geek zone
rm(list=ls())
5. Étape 2 - Charger les fonctions du labo (le "toolbox")
Depuis la racine du dépôt slaking-lab-plm :
Geek zone
source("./R/fredtoolbox_base.R") source("./R/fredtoolbox_shiny.R") source("./R/slakeboard-get.R") source("./R/slakeboard-graphs.R") source("./R/slakeboard-load.R") source("./R/slakeboard-merge.R") source("./R/slakeboard-read.R") source("./R/slakeboard-test.R") source("./R/slakeboard-indics.R") source("./R/slakeboard-sugar.R")
6. Étape 3 - Installer les packages nécessaires (une seule fois)
Geek zone
deps <- c( "dplyr", "tidyr", "conflicted", "readxl", "viridis", "readr", "testthat", "ggplot2" ) using(deps)
7. Étape 4 - Résoudre les conflits entre packages
Geek zone
conflict_prefer("select", "dplyr") conflict_prefer("filter", "dplyr") conflict_prefer("mutate", "dplyr") conflict_prefer("arrange", "dplyr") conflict_prefer("summarize", "dplyr") conflict_prefer("aes", "ggplot2") conflict_prefer("theme_classic", "ggplot2") conflict_prefer("theme_minimal", "ggplot2") conflict_prefer("theme_bw", "ggplot2") conflict_prefer("geom_point", "ggplot2") conflicts_prefer(readr::edition_get) conflicts_prefer(stats::lag) conflicts_prefer(testthat::local_edition) conflicts_prefer(testthat::matches) ok.fred()
8. Étape 5 - Importer et fusionner ses données brutes
C'est l'étape la plus importante à bien comprendre. Quatre fonctions s'enchaînent :
f.get.src(pattern): cherche dans./data-raw/tous les dossiers dont le nom contientpattern. C'est le nom que vous avez donné à votre export pySlake à l'étape 0.f.get.prj(src): liste les noms de projets trouvés dans<src>/containers/(les dossiers "test" sont ignorés automatiquement).f.get.cpgn(src, prj): liste les noms de campagnes trouvées dans<src>/containers/<prj>/.f.merge.src(src, prj, cpgn): fusionne, pour un projet et une (ou plusieurs) campagne(s), toutes les données brutes de toutes les sources trouvées, et les copie dans./containers/<prj>/<cpgn>/. Attention :prjdoit être une valeur unique (un seul projet à la fois) ;cpgnpeut par contre être un vecteur de plusieurs campagnes.
Geek zone
## Remplacez "pyslake-project-VotrePrenom" par le pattern choisi à l'étape 0 qtslk.src <- f.get.src("pyslake-project-VotrePrenom") qtslk.prj <- f.get.prj(qtslk.src) qtslk.cpgn <- f.get.cpgn(qtslk.src, qtslk.prj) ## Vérifiez ce que ça donne avant de continuer : qtslk.src qtslk.prj qtslk.cpgn
Regardez le résultat de qtslk.prj et qtslk.cpgn. S'il n'y a qu'un
seul projet, vous pouvez enchaîner directement. S'il y en a plusieurs
(par ex. parce que le dossier contient aussi d'anciens essais), fixez
prj à la main :
Geek zone
## prj <- "MonProjet2026" ## si besoin, décommentez et adaptez ## cpgn <- "MaCampagne" ## idem, peut être un vecteur c("C1","C2") l.qtslk.logs <- f.merge.src( qtslk.src, qtslk.prj, qtslk.cpgn )
Ce que fait f.merge.src concrètement :
- il (re)crée l'arborescence
./containers/<prj>/<cpgn>/(avecdata-raw/,data-clean/,data-output/,fig/,report/) ; - il copie les courbes brutes (
data-slake/) ; - il fusionne les fichiers de log (20 à 26) de toutes les sources ;
- il construit/actualise
./containers/data-raw/01_db_slake_global_<prj>.csv, la liste globale de tous les essais du projet.
9. Étape 6 (optionnel) - Fichier de bugs global au format Excel
Si un fichier Excel de suivi des bugs commun à plusieurs
projets/campagnes existe (par ex. ./data-raw/25_bugs_report_complet_QST_2026.xlsx),
vous pouvez l'importer ; il redistribue les lignes dans chaque
./containers/<prj>/<cpgn>/data-raw/25_bugs_report.csv :
Geek zone
f.bugs.from.xlsx("./data-raw/25_bugs_report_complet_QST_2026.xlsx")
Si vous n'avez pas encore de fichier de bugs corrigé et que vous voulez simplement démarrer (considérer que tous les essais sont a priori "ok"), vous pouvez dupliquer le log book en guise de rapport de bugs vide :
Geek zone
file.copy( paste0("./containers/", qtslk.prj, "/", qtslk.cpgn, "/data-raw/26_log_book.csv"), paste0("./containers/", qtslk.prj, "/", qtslk.cpgn, "/data-raw/25_bugs_report.csv"), overwrite = TRUE )
10. Étape 7 (optionnel) - Fichier d'informations des parcelles
Si vous avez des métadonnées par parcelle (précédent cultural, bloc, traitement, etc.) à associer à vos essais :
Geek zone
## 1) Générer un fichier vierge à compléter à la main f.build.blank.info.parcels(qtslk.prj, qtslk.cpgn) ## -> crée ./containers/<prj>/<cpgn>/data-raw/23_info_parcels_blank.csv ## à compléter puis renommer/copier en 23_info_parcels.csv ## 2) Ou importer un fichier déjà prêt depuis ./data-raw/ f.import.raw.file( "23_info_parcels_MonFichier.csv", fileto = "23_info_parcels.csv", prj = qtslk.prj, cpgn = qtslk.cpgn, erase_old_fileto = TRUE )
11. Étape 8 - Vérifications de cohérence
Ces tests vérifient qu'il n'y a pas de doublons (même parcelle + échantillon enregistré deux fois) :
Geek zone
test.prj(qtslk.prj) test.cpgn(qtslk.prj, qtslk.cpgn)
Si un test échoue, le message liste les lignes en double : il faut alors retourner corriger les données brutes (ou signaler le souci) avant de continuer.
12. Étape 9 - Nettoyage des données
Si vous avez des courbes corrigées manuellement, placées dans
./containers/<prj>/<cpgn>/data-clean/, cette étape les recopie
par-dessus les courbes brutes correspondantes :
Geek zone
clean.data.slake(qtslk.prj, qtslk.cpgn)
Si vous n'avez pas de courbes à corriger, cette étape ne fait rien de problématique : lancez-la quand même, elle est sans risque.
13. Étape 10 - Charger les essais dans un data.frame
Geek zone
df.slakes <- loadSlakes( qtslk.prj, qtslk.cpgn, TRUE, ## rm.fail.error : enlève les essais marqués "error" FALSE, ## rm.fail.warning : garde les essais marqués "warning" info.parcels = TRUE ## FALSE si vous n'avez pas fait l'étape 7 ) qst.object <- loadObject( qtslk.prj, qtslk.cpgn, TRUE, FALSE, from.disk = FALSE ) ok.fred()
14. Étape 11 - Vérifier que toutes les courbes se chargent bien
Cette boucle relit chaque courbe individuellement : c'est le moment de repérer les fichiers vides, corrompus ou mal formatés avant de calculer quoi que ce soit.
Geek zone
for (my.id in df.slakes$slake.id.global) { df.slake <- readSlake( my.id, qtslk.prj, qtslk.cpgn, qst.object, cooking = FALSE ) print(h(df.slake)) }
15. Étape 12 - Calculer les indicateurs
Geek zone
df.indic <- computeIndics( qtslk.prj, qtslk.cpgn, qst.object, slopes = TRUE, halflife = TRUE, auc = TRUE, save.to.file = TRUE ) ok.fred()
save.to.file = TRUE écrit le résultat dans
./containers/<prj>/<cpgn>/data-output/.
16. Étape 13 - Produire les figures
La fonction bulk.graphs() génère des PDF dans
./containers/<prj>/<cpgn>/fig/. Le paramètre l.types choisit quoi
tracer :
"raw": courbes brutes (masse ~ temps), sans traitement ;"slake": courbes après traitement ("cuisson" des données) ;"deriv": courbes dérivées ;"indic": courbes annotées avec les indicateurs calculés ;"by.plots": toutes les répétitions d'une même parcelle superposées, colorées par échantillon ;"all"équivaut àc("raw","slake").
Geek zone
bulk.graphs( df.slakes = df.slakes, prj = qtslk.prj, cpgn = qtslk.cpgn, qst.object = qst.object, vers = "all", l.types = "raw", max.time.raw = +Inf, max.time.indic = +Inf, max.time.compare = 15 )
Répétez l'appel en changeant l.types (et en fournissant df.indic
dès qu'on sort du simple raw) :
Geek zone
bulk.graphs( df.slakes = df.slakes, prj = qtslk.prj, cpgn = qtslk.cpgn, qst.object = qst.object, vers = "all", l.types = "slake", max.time.raw = +Inf, max.time.indic = +Inf, max.time.compare = 15, df.indic = df.indic )
Geek zone
bulk.graphs( df.slakes = df.slakes, prj = qtslk.prj, cpgn = qtslk.cpgn, qst.object = qst.object, vers = "all", l.types = "by.plots", max.time.raw = +Inf, max.time.indic = +Inf, max.time.compare = 15, df.indic = df.indic )
17. Étape 14 - Comparer les indicateurs entre modalités (boxplots)
boxplot.compare.indic() trace un boxplot de l'indicateur
comp.indic (par défaut "Wend") regroupé par la variable
comp.factor. Le nom de comp.factor doit correspondre à une colonne
présente dans votre fichier 23_info_parcels.csv (étape 7), par
exemple "parcel", "bloc", "treatment", "precedent"…
Geek zone
png( paste0("./containers/", qtslk.prj, "/", qtslk.cpgn, "/fig/comp_parcel.png"), width = 960, res = 60 ) boxplot.compare.indic( df.indic, comp.factor = "parcel" ) dev.off()
18. Étape 15 - Où trouver ses résultats
Tout est rangé sous ./containers/<prj>/<cpgn>/ :
data-raw/: données brutes fusionnées + courbes individuelles ;data-clean/: vos corrections manuelles éventuelles ;data-output/: le tableau d'indicateurs (.csv) et l'objet R sauvegardé (.rds) ;fig/: tous les PDF/PNG générés aux étapes 13-14 ;report/: dossier prévu pour vos propres notes/rapports.
19. Squelette minimal prêt à copier-coller
Pour démarrer rapidement une nouvelle analyse, copiez ce bloc dans un
nouveau fichier report/qst-<votrenom>-<annee>.org et adaptez les
lignes marquées ## <-- à adapter.
Geek zone
rm(list=ls()) source("./R/fredtoolbox_base.R") source("./R/fredtoolbox_shiny.R") source("./R/slakeboard-get.R") source("./R/slakeboard-graphs.R") source("./R/slakeboard-load.R") source("./R/slakeboard-merge.R") source("./R/slakeboard-read.R") source("./R/slakeboard-test.R") source("./R/slakeboard-indics.R") source("./R/slakeboard-sugar.R") qtslk.src <- f.get.src("pyslake-project-VotrePrenom") ## <-- à adapter qtslk.prj <- f.get.prj(qtslk.src) qtslk.cpgn <- f.get.cpgn(qtslk.src, qtslk.prj) l.qtslk.logs <- f.merge.src(qtslk.src, qtslk.prj, qtslk.cpgn) test.prj(qtslk.prj) test.cpgn(qtslk.prj, qtslk.cpgn) clean.data.slake(qtslk.prj, qtslk.cpgn) df.slakes <- loadSlakes(qtslk.prj, qtslk.cpgn, TRUE, FALSE, info.parcels = TRUE) qst.object <- loadObject(qtslk.prj, qtslk.cpgn, TRUE, FALSE, from.disk = FALSE) df.indic <- computeIndics( qtslk.prj, qtslk.cpgn, qst.object, slopes = TRUE, halflife = TRUE, auc = TRUE, save.to.file = TRUE ) bulk.graphs( df.slakes = df.slakes, prj = qtslk.prj, cpgn = qtslk.cpgn, qst.object = qst.object, vers = "all", l.types = "raw", max.time.raw = +Inf, max.time.indic = +Inf, max.time.compare = 15 )
20. Dépannage
- "Duplicated rows found" (étape 8) : deux lignes ont la même
combinaison projet/campagne/parcelle/échantillon. Corrigez le fichier
brut concerné dans votre export pySlake, puis recommencez depuis
l'étape 5 (
f.merge.srcefface et reconstruit./containers/<prj>/). - Erreur "file does not exist" sur
25_bugs_report.csvau chargement (étape 10) : ce fichier n'a pas été créé. Faites l'étape 6 (import Excel ou copie du log book en rapport de bugs vide). qtslk.prjcontient plusieurs projets inattendus : le pattern donné àf.get.src()est trop large, ou votre dossier contient d'anciens essais de test. Resserrez le pattern ou fixezprjà la main avantf.merge.src().- Une courbe ne se charge pas (étape 11,
dim(df.slake)[1] =0=) : le fichier brut correspondant dansdata-slake/est vide ou absent ; vérifiez le statut de cet essai dans25_bugs_report.csv. - Besoin d'aide : contactez Fred (f.vanwindekens@cra.wallonie.be) en indiquant à quelle étape vous êtes bloqué·e et le message d'erreur complet.