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

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 zonemon-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 zonels ./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 zonerm(list=ls())

5. Étape 2 - Charger les fonctions du labo (le "toolbox")

Depuis la racine du dépôt slaking-lab-plm :

Geek zonesource("./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 zonedeps <- c( "dplyr", "tidyr", "conflicted", "readxl", "viridis", "readr", "testthat", "ggplot2" ) using(deps)

7. Étape 4 - Résoudre les conflits entre packages

Geek zoneconflict_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 contient pattern. 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 : prj doit être une valeur unique (un seul projet à la fois) ; cpgn peut 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>/ (avec data-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 zonef.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 zonefile.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 zonetest.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 zoneclean.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 zonedf.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 zonefor (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 zonedf.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 zonebulk.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 zonebulk.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 zonebulk.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 zonepng( 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 zonerm(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.src efface et reconstruit ./containers/<prj>/).
  • Erreur "file does not exist" sur 25_bugs_report.csv au 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.prj contient 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 fixez prj à la main avant f.merge.src().
  • Une courbe ne se charge pas (étape 11, dim(df.slake)[1] = 0=) : le fichier brut correspondant dans data-slake/ est vide ou absent ; vérifiez le statut de cet essai dans 25_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.