Skip to content

Venir de jsPsych : correspondance des concepts et tâches jsPsych dans Potato

Fait correspondre les timelines, conditions, plugins et redirections Prolific de jsPsych aux clés de configuration de Potato, et montre comment exécuter une timeline jsPsych comme une page d'une étude Potato.

jsPsych est une bibliothèque JavaScript pour les expériences comportementales qui s'exécutent dans un navigateur web, et Potato est un serveur pour les études d'annotation et de questionnaire. La plupart des concepts de jsPsych ont une clé de configuration Potato, et depuis Potato 2.12.0, une étude qui a besoin d'un contrôle au niveau des essais peut exécuter sa timeline jsPsych comme une page d'une étude Potato.

Une expérience jsPsych est une timeline d'essais. Chaque essai est un objet pris en charge par un plugin, comme html-keyboard-response pour un stimulus et une pression de touche, et la timeline s'exécute dans le navigateur du participant. jsPsych n'héberge rien ; une étude jsPsych a donc aussi besoin d'un serveur pour servir la page et stocker les données, couramment JATOS, Pavlovia ou Cognition.run. Une étude Potato est une suite de pages de phase, comme le consentement, un questionnaire de sélection, des consignes, une formation, l'annotation et un débriefing, définies dans une configuration YAML, et Potato est le serveur. En termes Potato, une timeline devient phases, l'arrêt anticipé de l'expérience devient exit_when, et l'affectation aux conditions qu'une étude jsPsych obtient de son hébergeur devient conditions.

Choisir entre jsPsych et Potato

jsPsych convient aux études dans lesquelles le chronométrage des stimuli et les temps de réaction sont les données. Les paradigmes de temps de réaction comme le Stroop, la tâche de flanker, le test d'association implicite et la recherche visuelle exigent de contrôler ce qui est à l'écran et à quel moment, et jsPsych donne ce contrôle à du code qui s'exécute à chaque essai. jsPsych couvre aussi l'oculométrie par son extension WebGazer, l'audio avec des débuts programmés et le dessin personnalisé sur canvas.

Potato convient quand l'étude consiste surtout en jugements sur des items, comme des étiquettes, des notes, des classements, des segments marqués dans un texte, des comparaisons par paires et des questionnaires. Il attribue les items aux participants, les forme et les sélectionne, rapporte l'accord inter-annotateurs (fidélité inter-juges), et gère l'arrivée depuis Prolific ou un vivier de participants SONA ainsi que le retour vers eux. Les pages qui entourent une tâche, comme le consentement, les questionnaires de sélection, les consignes, l'entraînement avec retour et un questionnaire post-étude, sont des entrées de configuration et non du code.

Une étude a besoin des deux quand elle combine une tâche chronométrée avec des notations ou des questionnaires, par exemple un bloc de Stroop suivi de notations de valence de mots. Placez la timeline jsPsych sur une page type: jspsych et laissez Potato gérer le reste. Les données d'essais sont stockées par participant à côté des notations, et le participant reçoit un seul code de complétion à la fin.

Correspondance des concepts de jsPsych vers Potato

Le tableau associe chaque concept de jsPsych à la clé Potato qui remplit le même rôle. La plupart des lignes correspondent à une clé de configuration, et les notes signalent les correspondances partielles.

jsPsychPotatoNotes
Timelinephases.orderPlusieurs pages par type de phase
EssaiUne page de phase, ou un item d'annotationLes items proviennent de data_files, pas de la configuration
Variables de timelineChamps du fichier de donnéesinstance_display choisit les champs que voit le participant
conditional_functionshow_when de pageMême grammaire de règles que le display_logic au niveau des questions
Question conditionnelledisplay_logicVoir Flux de travail multi-phases
jsPsych.abortExperiment()exit_when de pageAffiche un message, ou renvoie le résultat d'exclusion de la plateforme
loop_functiontraining.failure_action: repeat_trainingSeule la phase de formation se répète
randomize_order, sampleassignment_strategy: random, randomize_questionsL'ordre des items est tiré avec une graine propre au participant
Options de réponse mélangéesrandomize_order sur un schémaLe randomize_order de Potato mélange les options d'un schéma, et l'ordre affiché est enregistré
Affectation inter-sujets, par l'hébergeur (par exemple une session de lot JATOS)conditionsAffectation équilibrée, aléatoire ou à tour de rôle des participants aux cellules
Ordre des blocs contrebalancéphases.counterbalance avec method: latin_squareCarrés latins équilibrés (de Williams)
survey-likert, survey-multi-choice, survey-multi-select, survey-textlikert, radio, multiselect, textPlus 55 instruments publiés appelés par leur nom
html-slider-responseslider, vas
maxdiffbwsÉchelle best-worst, avec calcul des scores
free-sortcard_sortTri de cartes, fermé ou ouvert
clozeclozeLe corrigé reste sur le serveur
same-different-htmlpairwisePas de présentation séquentielle chronométrée
html-keyboard-response avec trial_durationtrial_timingFixation, durée du stimulus, délai, temps de réaction avec association touche-étiquette
instructions, external-htmlPages de consignes, fichiers HTML
Données d'interaction (perte de focus, focus)authenticitySorties de page, copies, collages externes
Extension de suivi de la sourisextensions: [mouse-tracking] sur une page jsPsychÉchantillons x/y par essai. Sur les items propres de Potato, authenticity.track_pointer ne conserve que des totaux de pointeur
Lecture auto-rythmée et labyrinthe de jspsych-contribtrial_timing.presentationLecture auto-rythmée et labyrinthe, avec des temps de lecture par région
Évaluations de qualité audio, tests de casqueSchéma listening_test, page type: headphone_checkTests d'écoute et test de casque, notés sur le serveur
(aucun plugin)keystroke_loggingChronométrage des frappes dans les champs de texte libre, sans les caractères
Paramètres d'URL Prolific, redirection de complétionlogin.type: url_direct et completion_code, ou crowdsourcing.provider: prolificVoir Mener une étude en crowdsourcing
SONAcrowdsourcing.provider: sonaCrédits accordés depuis le serveur
jsPsych.data.get().csv()python -m potato.export60 formats, dont CSV, JSONL, Parquet, Psych-DS et un Frictionless Data Package
JATOS, Pavlovia, Cognition.runPotato lui-mêmeExécutez-le sur votre propre serveur ou dans un Space Hugging Face
Mode de simulationpython -m potato.simulatorParticipants simulés face à un serveur en cours d'exécution

Les paradigmes qui exigent une timeline jsPsych

Certains paradigmes exigent votre propre code d'essai, et les pages d'items de Potato ne l'exécutent pas. Gardez-les dans une timeline jsPsych :

  • Présentation calée sur les images. Stimuli dessinés sur un canvas, masques synchronisés sur une image et audio programmé avec la Web Audio API.
  • Trajectoires de souris. Le bloc authenticity de Potato compte les déplacements et la distance du pointeur par item et ne conserve aucune position. Une page jsPsych avec extensions: [mouse-tracking] enregistre des échantillons x/y à chaque essai qui active l'extension.
  • Plein écran d'un essai à l'autre. Chaque item Potato est un chargement de page, et les navigateurs quittent le plein écran quand la page change. Une page jsPsych maintient le plein écran pendant toute sa timeline.
  • Boucles et branchements à l'intérieur d'un bloc d'essais. Potato fait des branchements par page (show_when), par question (display_logic) et par tentative de formation ; un bloc qui se ramifie selon la réponse précédente relève donc de jsPsych.

Les items propres de Potato peuvent aussi exécuter des jugements rapides. trial_timing transforme chaque item d'annotation en un essai chronométré avec une croix de fixation, une durée de stimulus, un délai de réponse et des touches associées aux étiquettes, et il mesure le temps de réaction dans le navigateur à partir de l'image sur laquelle le stimulus est apparu. trial_timing convient à la décision lexicale ou aux jugements rapides de grammaticalité sur une liste d'items. L'apparition est connue à l'image près (environ 17 ms à 60 Hz).

L'oculométrie et l'enregistrement par webcam sortent du cadre des deux types de page. Potato ne fournit pas l'extension WebGazer de jsPsych ni ses plugins de calibration, car WebGazer a besoin de 'unsafe-eval' et la Content-Security-Policy de la page jsPsych ne l'autorise pas. Une étude d'oculométrie s'exécute sur un hébergeur jsPsych comme JATOS ou Pavlovia, ou dans Gorilla.

Une étude Potato avec une tâche jsPsych

La configuration ci-dessous constitue le cœur de l'exemple Stroop livré avec Potato. Les participants sont affectés à l'une de deux conditions de retour, répondent à un questionnaire de sélection qui met fin à l'étude pour quiconque déclare avoir du mal à distinguer les couleurs, font une tâche de Stroop dans jsPsych, notent des mots, et terminent par un questionnaire de débriefing dont les questions apparaissent dans un ordre aléatoire pour chaque participant, la zone de commentaire venant en dernier. Le bloc est partiel. La version complète, avec le fichier de données, les fichiers de questionnaire et la timeline, se trouve dans examples/advanced/jspsych-stroop/.

yaml
conditions:
  factors:
    feedback: [none, immediate]
  assignment: balanced          # each arrival goes to the cell with the fewest participants
 
phases:
  order: [screener, stroop, annotation, debrief]
  screener:
    type: prestudy
    file: surveys/screener.json
    exit_when:
      show_when:
        - {schema: colour_vision, operator: equals, value: "Yes"}
      message: This study needs you to tell red, green and blue apart quickly, so we cannot include you.
  stroop:
    type: jspsych
    timeline: tasks/stroop.js
    plugins: [instructions, html-keyboard-response]
  debrief:
    type: poststudy
    file: surveys/debrief.json
    randomize_questions:
      pin_last: [comments]      # the open comment box stays last

L'affectation équilibrée maintient les deux conditions de retour à un participant d'écart au plus à mesure que les gens arrivent. Ajouter balance_on: completed fait que seuls les participants qui terminent sans être exclus comptent pour une condition ; un abandon est ainsi remplacé par l'arrivant suivant.

Le fichier de timeline affecte une fonction à window.potatoTimeline. Potato crée l'instance jsPsych, appelle la fonction avec cette instance et un objet potato, et enregistre les données à la fin de la timeline. La fonction renvoie les essais, et elle peut lire la condition du participant pour décider lesquels inclure :

javascript
window.potatoTimeline = function (jsPsych, potato) {
    var trial = {
        type: jsPsychHtmlKeyboardResponse,
        stimulus: '<p style="font-size:48px;color:#c62828">GREEN</p>',
        choices: ['r', 'g', 'b']
    };
    var feedback = {
        type: jsPsychHtmlKeyboardResponse,
        stimulus: '<p>Correct key: R</p>',
        trial_duration: 800
    };
    return potato.conditions.feedback === 'immediate' ? [trial, feedback] : [trial];
};

La timeline n'appelle pas initJsPsych et ne définit pas de on_finish au niveau de l'expérience, car Potato fait les deux. Le on_finish au niveau des essais et le reste de l'API jsPsych fonctionnent comme d'habitude. potato.participant contient l'identifiant Prolific ou SONA, potato.asset(path) renvoie l'URL d'un stimulus dans l'assets_dir de la page, et expose_answers transmet les réponses des pages de questionnaire antérieures dans potato.answers.

Potato embarque jsPsych 8.3.0 et 15 de ses plugins, dont les plugins clavier, bouton, curseur, audio, vidéo, questionnaire, preload et fullscreen. Une étude qui n'utilise que ces plugins ne charge rien depuis un CDN ; elle fonctionne donc sur un serveur sans accès à Internet. Les autres plugins, y compris ceux de jspsych-contrib, se chargent par extra_scripts sous forme de builds pour navigateur. Lancez l'exemple depuis la racine du dépôt Potato :

bash
python potato/flask_server.py start examples/advanced/jspsych-stroop/config.yaml -p 8000

Données d'essais et export depuis une page jsPsych

Chaque exécution de la timeline est stockée dans la base de données du projet (table runtime_runs) avec le participant, la page, le numéro de tentative et les conditions du participant, et chaque ligne d'essai reçoit potato_user, potato_run_id, potato_attempt et une colonne condition_<factor> par facteur. Le format d'export jspsych écrit un CSV des exécutions, un CSV des essais avec chaque colonne enregistrée par jsPsych, les événements de perte de focus et de plein écran de jsPsych, et le JSON brut de chaque exécution :

bash
python -m potato.export --config config.yaml --format jspsych --output ./export/

Avec save: incremental, chaque essai est stocké dès qu'il se termine, et un participant qui ferme l'onglet laisse quand même les essais qu'il a effectués. Un rechargement relance la timeline depuis le début, car jsPsych ne peut pas reprendre une timeline en cours de route. Une exécution qui avait déjà envoyé des données reste enregistrée comme incomplète, et l'exécution suivante porte un potato_attempt plus élevé ; une analyse peut donc exclure les deuxièmes tentatives ou les garder.

L'export CSV de la même étude écrit participants.csv, une ligne par participant avec sa condition, ses ordres de pages, les pages sautées et une éventuelle exclusion. Potato appelle cela l'enregistrement du déroulement, et il se joint aux données d'essais par l'identifiant du participant. Les exécutions jsPsych sont stockées dans le project.sqlite du répertoire de la tâche, quel que soit le backend de stockage utilisé par le serveur.

Le chronométrage propre à jsPsych s'applique sur la page, car Potato n'y exécute rien d'autre. La documentation de jsPsych sur la précision temporelle indique que les temps de réaction mesurés en JavaScript sont de 10 à 40 ms plus longs que dans les logiciels de laboratoire standard, avec une variance comparable. Comparez les temps de réaction au sein des participants, ou modélisez-les avec un terme participant, car les claviers et les écrans ajoutent une latence qui varie d'une machine à l'autre.

Pour aller plus loin