Nayoun Kim nayoun@skku.edu
Assistant Professor, Sungkyunkwan University Department of English Language and Literature
Syntax, Experimental Syntax, Psycholinguistics
June Choe yjchoe@sas.upenn.edu
Ph.D. Student, University of Pennsylvania Department of Linguistics
Psycholinguistics, Acquisition, Computational Linguistics
IBEX
(I)nternet-(B)ased (EX)periments developed by Alex Drummond.
Refers to both the framework for scripting experiments and the platform for hosting experiments.
IBEX the platform "IBEXfarm" has been discontinued in late 2021, but the IBEX framework survives and is supported by extensions and spinoffs.
IBEX
(I)nternet-(B)ased (EX)periments developed by Alex Drummond.
Refers to both the framework for scripting experiments and the platform for hosting experiments.
IBEX the platform "IBEXfarm" has been discontinued in late 2021, but the IBEX framework survives and is supported by extensions and spinoffs.
PCIbex
PennController for IBEX developed by Jeremy Zehr and Florian Schwarz at the University of Pennsylvania.
A platform for hosting experiments that supports and extends IBEX
Also introduces its own, alternative framework for scripting experiments.
Go to the PCIbex farm https://farm.pcibex.net
Sign up with an email (or Log in)
Once logged in, click Empty project under Start a new project
Change the name of the project at the top to something unique (e.g., "SICOL2022")
Your new project will appear on the main page
Resources
Scripts
Aesthetics
Modules
Resources
Scripts
Aesthetics
Modules
When scripting with IBEX, we often only need one file: main.js
At creation, the default file looks like this:
To demonstrate the IBEX scripting framework, we use our own template file.
The following IBEX code just works thanks to PCIbex's backward compatibility.
Parts of the main.js
Script
Settings:
Sequence:
Body:
Body
Forms
Trials
Stimuli for the experiment
practice trials
critical trials
filler trials
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Prediction: Lower acceptability ratings in the transitive-biased condition (gp.trans) than in the intransitive-biased condition (gp.intrans).
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Prediction: Lower acceptability ratings in the transitive-biased condition (gp.trans) than in the intransitive-biased condition (gp.intrans).
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
This is a list (array) of three elements (clearer with spacing):
[
\(\quad\)
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
[
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
This is a list (array) of three elements (clearer with spacing):
[
\(\quad\)
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
[
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
We have one big list (bracket) which contains three elements:
Another list, consisting of the name of the condition and item set number
A string specifying the type of task (also called Controllers or Elements)
A curly bracket (braces), which has "s" and the sentence separated by a colon
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
This can be put into a single line:
[["gp.trans",1], "AcceptabilityJudgment", {s: "While Anna trained the kitten paid attention."}]
Example 2:
For the gp.intrans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna dressed the kitten paid attention".
[
\(\quad\)
[ "gp.intrans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna dressed the kitten paid attention."}
]
This can be put into a single line:
[["gp.intrans",1], "AcceptabilityJudgment", {s: "While Anna dressed the kitten paid attention."}]
Item set #2:
(transitive) - "Since Dave improved the department was satisfied."
(intransitive) - "Since Dave worried the counselor devised a plan."
[["gp.trans",2], "AcceptabilityJudgment", {s: "Since Dave improved the department was satisfied."}][["gp.intrans",2], "AcceptabilityJudgment", {s: "Since Dave worried the counselor devised a plan."}]
Wrap in var items = [ ... ]
and separate each item by a comma:
Practice Trials:
Filler Trials:
Practice Trials:
Filler Trials:
We want both practice and filler trials to be invariant across conditions
To do that, we don't specify Item Set # for give practice and filler trials, as that gets used for counterbalancing (more later):
Practice Trials:
Filler Trials:
We want both practice and filler trials to be invariant across conditions
To do that, we don't specify Item Set # for give practice and filler trials, as that gets used for counterbalancing (more later):
Practice #1: "The car drove like a dream"
["practice-1", "AcceptabilityJudgment", {s: "The car drove like a dream."}]
Good Filler #1: "When Harry fell, the audience was shocked."
["filler-good-01", "AcceptabilityJudgment", {s: "When Harry fell, the audience was shocked."}]
Bad Filler #1: "When Tyler sneezed the driver, he passed a tissue."
["filler-bad-01", "AcceptabilityJudgment", {s: "When Tyler sneezed the driver, he passed a tissue."}]
Catch Filler #1: "Please select 4 for this sentence."
["filler-catch-01", "AcceptabilityJudgment", {s: "Please select 4 for this sentence."}]
Pull out the names of each trial:
"practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01"
Wrap them in seq()
:
seq( "practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
Assign to shuffleSequence
:
var shuffleSequence = seq( "practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
The shuffleSequence
variable handles the order of presentation of the experiment materials that are stored inside the items
variable.
Problems
var shuffleSequence = seq("practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
Problems
var shuffleSequence = seq( "practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
A lot of typing ("-02", "-03", ...)
Presentation order of some trials should be random
Problems
var shuffleSequence = seq( "practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
A lot of typing ("-02", "-03", ...)
Presentation order of some trials should be random
How do we counterbalance critical trials?
To save us from writing repetitive code, we use startsWith()
var shuffleSequence = seq("practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
var shuffleSequence = seq(startsWith("practice"),startsWith("gp")startsWith("filler"))
The function startsWith()
matches all names that starts with the given string.
To mix critical and filler trials in random order, we use rshuffle()
var shuffleSequence = seq( startsWith("practice"),startsWith("gp")startsWith("filler"))
var shuffleSequence = seq( startsWith("practice"),rshuffle( startsWith("gp"), startsWith("filler") ))
By wrapping both the critical trials (gp...) and the filler trials (filler...) in rshuffle()
, they are mixed together and presented in random order.
To mix critical and filler trials in random order, we use rshuffle()
var shuffleSequence = seq( startsWith("practice"),startsWith("gp")startsWith("filler"))
var shuffleSequence = seq( startsWith("practice"),rshuffle( startsWith("gp"), startsWith("filler") ))
By wrapping both the critical trials (gp...) and the filler trials (filler...) in rshuffle()
, they are mixed together and presented in random order.
We can also write this out more compactly:
var shuffleSequence = seq( startsWith("practice"),rshuffle(startsWith("gp"), startsWith("filler")))
The set number in our critical trials are automatically used for counterbalancing:
The set number in our critical trials are automatically used for counterbalancing:
To alternate items between participants, we use a special counter "trial":
["setcounter", "__SetCounter__", { }]
The counter must be defined in items
and added to shuffleSequence
:
var items = [ ... ["setcounter", "__SetCounter__", { }], // The counter is defined ...]var shuffleSequence = seq( "setcounter", // The counter is incremented at the start ...)
The counter must be defined in items
and added to shuffleSequence
:
var items = [ ... ["setcounter", "__SetCounter__", { }], // The counter is defined ...]var shuffleSequence = seq( "setcounter", // The counter is incremented at the start ...)
Sometimes you want to increment counter in the middle of the experiment:
var shuffleSequence = seq( "intro" "consent", "setcounter", ...)
Consist of miscellaneous options that we can put at the top of the script.
For example, using the defaults
variable, we can specify parameters for the design of the tasks that we use in the experiment, like Acceptability Judgment.
defaults
variableSome options for Acceptability Judgment:
var defaults = [ "AcceptabilityJudgment", { as: ["1", "2", "3", "4", "5", "6", "7"], presentAsScale: true, instructions: "Use number keys or click boxes to answer.", leftComment: "(Bad)", rightComment: "(Good)" }]
defaults
exampleSuppose you'd like to show participants multiple sentences but have them only rate the acceptability of one of the sentences.
var defaults = [ "AcceptabilityJudgment", { ... instructions: "Rate how natural Speaker B's response sounds." }]
[["ConditionA", 1], "AcceptabilityJudgment",{s: ["div", ["p", "Speaker A: Who left this sandwich on the table?"] ["p", "Speaker B: Fred did."] ]}]
We can print lines of text using html tags (more later)
You can also change other options, such as showing a message at the end:
var completionMessage
// A message to show to participants at completionvar completionMessage = "Thank you for your participation!"
And whether to show a progress bar:
var showProgressBar
// Show a progress bar at the top? (true/false)var showProgressBar = false
You can learn more about these various elements in the Miscellaneous options section of the IBEX documentation.
We now have a minimally working experiment!
What we've covered:
We have a templatic syntax for creating stimuli
We store all the materials for our experiment inside items
We specify the order of presentation inside shuffleSequence
We can tweak various aspects of the experiment, like defaults
for the task design.
What we've covered:
We have a templatic syntax for creating stimuli
We store all the materials for our experiment inside items
We specify the order of presentation inside shuffleSequence
We can tweak various aspects of the experiment, like defaults
for the task design.
A few more things we want to know:
How can we show messages and text to participants?
How can we extend this workflow for other experimental designs?
The "Message" controller shows text on a new page.
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
Condition name is used to reference the trial in sequencing
"Message" is a type of task that just shows text on a screen
Inside of the curly braces {} we can add text in the html parameter:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
Condition name is used to reference the trial in sequencing
"Message" is a type of task that just shows text on a screen
Inside of the curly braces {} we can add text in the html parameter:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
Notes on html:
The code ["p", "<your text here>"]
prints a paragraph of text.
The "p" is an HTML tag and there are many others (most common: "div", "strong", "em"). They don't usually get too complicated.
A message composed of a single paragraph:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
A message composed of multiple paragraphs must be combined inside a "div":
["intro", "Message", {html: ["div", ["p", "Welcome to the experiment!"], ["p", "Here's another paragraph."], ["p", "These paragraphs are all wrapped inside \"div\"."] ]}]
Note: You can escape special characters like quotes "
with a backslash \
Ask for consent with a set of consent...
parameters
["consent", "Message", { html: ["p", "Do you consent?"], consentRequired: true, consentMessage: "I consent."}]
Use the transfer
argument to specify how the participant can move on.
Setting transfer
to "keypress"
removes the default "Click here to continue." message and allows participants to proceed with the press of any key.
["move_on", "Message", { html: ["div", ["p", "The option for \"transfer\" is \"keypress\""], ["em", "Press any key to continue."] ], transfer: "keypress"}]
You might want to insert a page that separates the trials:
["sep", "Message", { html: ["em", "Press any key to continue."], transfer: "keypress"}]
You can do so using sepWith()
in shuffleSequence
:
var shuffleSequence = seq( "practice", sepWith("sep", rshuffle(startsWith("gp"), startsWith("filler"))))
We now have a complete experiment with several Message controllers added.
So we have a new script, but how do we host the experiment?
Go to the PCIbex farm website and log in.
Click into (or create) your experiment and edit the main.js
file.
Click Share in the menu bar to the right and copy the Demonstration link (for testing and development) or Data-collection link (available after publishing)
Demo: https://farm.pcibex.net/r/YBYAwi
Published: https://farm.pcibex.net/p/HCRZqI
Suppose that after a pilot experiment, we find acceptability judgments to be inappropriate for answering our research question.
We want a finer-grained measure of recovery difficulty, so we'd like to change the experiment to self-paced reading and look at differences in reading time.
Suppose that after a pilot experiment, we find acceptability judgments to be inappropriate for answering our research question.
We want a finer-grained measure of recovery difficulty, so we'd like to change the experiment to self-paced reading and look at differences in reading time.
Given our existing template, we take the following steps:
Go to the documentation and find a Controller for self-paced reading.
Specify the design of that controller in the defaults
variable.
Change our trials in items
from "acceptabilityJudgment" to that Controller.
Make changes to the text of the "Messages" items (e.g., directions).
The "DashedSentence" Controller creates self-paced reading trials.
The "DashedSentence" Controller creates self-paced reading trials.
We can simply replace "acceptabilityJudgment" with "DashedSentence" in items
:
var items = [ ... [["gp.trans",1], "DashedSentence", {s: "While Anna trained the kitten paid attention."}], [["gp.intrans",1], "DashedSentence", {s: "While Anna dressed the kitten paid attention."}], [["gp.trans",2], "DashedSentence", {s: "Since Dave improved the department was satisfied."}], [["gp.intrans",2], "DashedSentence", {s: "Since Dave worried the counselor devised a plan."}], ...]
The "DashedSentence" Controller creates self-paced reading trials.
We can simply replace "acceptabilityJudgment" with "DashedSentence" in items
:
var items = [ ... [["gp.trans",1], "DashedSentence", {s: "While Anna trained the kitten paid attention."}], [["gp.intrans",1], "DashedSentence", {s: "While Anna dressed the kitten paid attention."}], [["gp.trans",2], "DashedSentence", {s: "Since Dave improved the department was satisfied."}], [["gp.intrans",2], "DashedSentence", {s: "Since Dave worried the counselor devised a plan."}], ...]
And specify appropriate settings for "DashedSentence" in defaults
:
var defaults = [ "DashedSentence", { mode: "self-paced reading", display: "dashed" }]
Finally, after re-writing some of the "Message" items, we have a new experiment!
You can use the Question controller to ask Yes/No comprehension questions:
[["YesNo_example",1],"Question",{q: "Was the kitten trained?", as: ["Yes", "No"]}]
The as parameter sets the answer choices presented to participants.
[["FC1_example",1], "Question", { instructions: "Choose the more natural sentence.", as: ["Who did you see that ate bread?", "What did you see the girl who ate?"]}]
You can ask for continuations by modifying the q parameter.
[["FC2_example",1], "Question", { q: "While Anna dressed the baby ______", instructions: "Choose the more natural continuation.", as: ["started to cry.", "he started to cry."]}]
Use Form controller with the "textarea" HTML tag to collect a free response:
[["FR_example",1], "Form", {html: ["div", ["em", "Fill out a continuation for the sentence fragment:"], ["p", "While Anna dressed the baby ______"], ["textarea"]]}]
The data collected in the experiment can be found on the experiment page, in the Results tab to the right side of the dashboard.
It gives you a preview of the results and options to download or delete the data that's been collected so far.
If you download the data, you get back a csv file called results.csv
, meaning that each line contains a set of values that are separated by a comma.
Lines that start with a pound symbol "#" are comments that include metadata.
The ones that start with numbers tell us what variable the columns correspond to.
All IBEX experiments return these 7 variables:
Time ("Results reception time")
Participant ID ("MD5 hash of participant's IP address")
Controller ("Controller name")
Item number ("Order number of item")
Inner element number ("Inner element number")
Condition ("Label")
Item set ("Latin Square Group")
In our case, we only care about 4 of these:
Time
Participant ID: A unique ID for each participant
Controller: The type of task/trial (e.g., AcceptabilityJudgment)
Item number
Inner element number
Condition: The condition label for the trial (practice-1, gp-trans, ...).
Item set: The item set number (1,2,3,...).
In our case, we only care about 4 of these:
Time
Participant ID: A unique ID for each participant
Controller: The type of task/trial (e.g., AcceptabilityJudgment)
Item number
Inner element number
Condition: The condition label for the trial (practice-1, gp-trans, ...).
Item set: The item set number (1,2,3,...).
The last two variables uniquely identify the stimuli defined in items
:
[["Condition", Item set], "Controller", {s: "Sentence"}]
[["gp.trans", 1], "DashedSentence", {s: "..."}]
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
These are also outlined in the documentation for "DashedSentence", so you know what variables to expect beforehand.
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
These are also outlined in the documentation for "DashedSentence", so you know what variables to expect beforehand.
For an actual analysis of the results, we need the results to be imported somewhere as a data frame, preferrably in a rectangular table format where rows are observations and columns are variables.
Steps for importing the data into Excel:
Copy the text of the results file from IBEX
Paste into the first column of an Excel spreadsheet
Highlight that column and click Data tab -> Filter
Click on the dropdown arrow that appears at the top cell
Click Text Filters -> Begins With... and type in "#"
Go to Home tab -> Find & Select, check "Visible cells only", and click OK
Right click on any part of the sheet and select Delete Row
Click the first column again and go to Data tab -> Text to Columns
Check "Delimited", "Comma", then "General" for each prompt
Add an empty row at the top and manually type in the column names from the comments of the original results file
Some Controllers return multiple lines of results, with differing number of columns
For example, each AcceptabilityJudgment trial is a combination of Message and Question controllers under the hood, so it logs two lines of data:
In more complex cases like these, using a script (R/Python) is recommended
Steps for importing into R:
Download the results.csv
file from PCIbex
Open it with the read_pcibex()
function from the read_pcibex.R script
source("read_pcibex.R")results <- read_pcibex("SPR_results.txt")
# A tibble: 6 × 5 Controller_name Label Word_number Word Reading_time <chr> <chr> <dbl> <chr> <dbl> 1 DashedSentence practice-1 1 The 132 2 DashedSentence practice-1 2 car 115 3 DashedSentence practice-1 3 drove 110 4 DashedSentence practice-1 4 like 112 5 DashedSentence practice-1 5 a 118 6 DashedSentence practice-1 6 dream. 117
source("read_pcibex.R")results <- read_pcibex("Acceptability_results.txt")
# A tibble: 6 × 4 Label Latin_Square_Group Sentence_or_sentence_MD5 Answer <chr> <chr> <chr> <dbl> 1 practice-1 NULL The car drove like a drea… NA 2 practice-1 NULL <NA> 5 3 gp.intrans 2 Since Dave worried the co… NA 4 gp.intrans 2 <NA> 6 5 gp.trans 1 While Anna trained the ki… NA 6 gp.trans 1 <NA> 5
The experiment script incomplete.js has some missing pieces.
Directions:
Download incomplete.js
Create a new experiment on your PCIbex account called "WorkshopExercise" and replace the contents of main.js with incomplete.js.
Follow the directions in the script to fill in the blanks.
Complete as many of tasks as possible (8 total).
If you finish, save the edits, refresh, and preview the experiment in the bottom panel or click Open in new tab. Check to see that your experiment looks similar to the complete version - https://farm.pcibex.net/p/ZvbOXD.
Make sure to reference the IBEX documentation!
https://github.com/addrummond/ibex/blob/master/docs/manual.md
For several of the standard experimental paradigms in linguistics, the PCIbex framework directly ports controllers from IBEX. So for tasks like self-paced reading, you get the same experiment from a different style of code.
You can clone the PCIbex version of the workshop's SPR experiment here - https://farm.pcibex.net/r/nYsovX
PCIbex has great support for experiments involving multimedia (audio, video, etc.). The PCIbex documentation is a good place to get started - https://doc.pcibex.net
IBEX is always good to know due to the sheer amount of linguistics experiments already written in IBEX.
PCIBex is not difficult to pick up after IBEX, should you choose to learn it.
Many thanks to...
Brian Dillon (UMass Amherst) for permission to use materials from the LSA Minicourse "Doing Experiments for Linguists" (Brian Dillon & Rodica Ivan)
Jon Sprouse (UConn) for permission to use materials from LSA 2016, Experimental Syntax Workshop
Florian Schwarz and Jeremy Zehr for permissions to use materials from their PCIbex workshops.
Attendees of the 2021 BK Winter School Workshop on Experimental Linguistics/Syntax at Sungkyunkwan University for valuable feedback on the workshop materials.
Nayoun Kim nayoun@skku.edu
Assistant Professor, Sungkyunkwan University Department of English Language and Literature
Syntax, Experimental Syntax, Psycholinguistics
June Choe yjchoe@sas.upenn.edu
Ph.D. Student, University of Pennsylvania Department of Linguistics
Psycholinguistics, Acquisition, Computational Linguistics
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
o | Tile View: Overview of Slides |
Esc | Back to slideshow |
Nayoun Kim nayoun@skku.edu
Assistant Professor, Sungkyunkwan University Department of English Language and Literature
Syntax, Experimental Syntax, Psycholinguistics
June Choe yjchoe@sas.upenn.edu
Ph.D. Student, University of Pennsylvania Department of Linguistics
Psycholinguistics, Acquisition, Computational Linguistics
IBEX
(I)nternet-(B)ased (EX)periments developed by Alex Drummond.
Refers to both the framework for scripting experiments and the platform for hosting experiments.
IBEX the platform "IBEXfarm" has been discontinued in late 2021, but the IBEX framework survives and is supported by extensions and spinoffs.
IBEX
(I)nternet-(B)ased (EX)periments developed by Alex Drummond.
Refers to both the framework for scripting experiments and the platform for hosting experiments.
IBEX the platform "IBEXfarm" has been discontinued in late 2021, but the IBEX framework survives and is supported by extensions and spinoffs.
PCIbex
PennController for IBEX developed by Jeremy Zehr and Florian Schwarz at the University of Pennsylvania.
A platform for hosting experiments that supports and extends IBEX
Also introduces its own, alternative framework for scripting experiments.
Go to the PCIbex farm https://farm.pcibex.net
Sign up with an email (or Log in)
Once logged in, click Empty project under Start a new project
Change the name of the project at the top to something unique (e.g., "SICOL2022")
Your new project will appear on the main page
Resources
Scripts
Aesthetics
Modules
Resources
Scripts
Aesthetics
Modules
When scripting with IBEX, we often only need one file: main.js
At creation, the default file looks like this:
To demonstrate the IBEX scripting framework, we use our own template file.
The following IBEX code just works thanks to PCIbex's backward compatibility.
Parts of the main.js
Script
Settings:
Sequence:
Body:
Body
Forms
Trials
Stimuli for the experiment
practice trials
critical trials
filler trials
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Prediction: Lower acceptability ratings in the transitive-biased condition (gp.trans) than in the intransitive-biased condition (gp.intrans).
Study: We are interested in how people recover from garden-path sentences.
"While Anna dressed the kitten paid attention."
... *[VP dressed the kitten], ...
... ✓[VP dressed], the kitten ...
Hypothesis: Verbs that are frequently transitive make recovery (reanalysis) more difficult, compared to verbs that are frequently intransitive.
(transitive-biased) - "While Anna trained the kitten paid attention."
(intransitive-biased) - "While Anna dressed the kitten paid attention."
Prediction: Lower acceptability ratings in the transitive-biased condition (gp.trans) than in the intransitive-biased condition (gp.intrans).
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
This is a list (array) of three elements (clearer with spacing):
[
\(\quad\)
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
[
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
For each trial in our acceptability judgment experiment, we write this code:
[["Condition name", Item Set #], "Task Type", {s: "Sentence"}]
This is a list (array) of three elements (clearer with spacing):
[
\(\quad\)
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
[
["Condition name", Item Set # ],
\(\quad\)
"Task Type",
\(\quad\)
{s: "Sentence"}
]
We have one big list (bracket) which contains three elements:
Another list, consisting of the name of the condition and item set number
A string specifying the type of task (also called Controllers or Elements)
A curly bracket (braces), which has "s" and the sentence separated by a colon
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
Example 1:
In the gp.trans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna trained the kitten paid attention".
[
\(\quad\)
[ "gp.trans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna trained the kitten paid attention."}
]
This can be put into a single line:
[["gp.trans",1], "AcceptabilityJudgment", {s: "While Anna trained the kitten paid attention."}]
Example 2:
For the gp.intrans condition, the first stimuli in our acceptability judgment experiment is the sentence "While Anna dressed the kitten paid attention".
[
\(\quad\)
[ "gp.intrans", 1 ],
\(\quad\)
"AcceptabilityJudgment",
\(\quad\)
{s: "While Anna dressed the kitten paid attention."}
]
This can be put into a single line:
[["gp.intrans",1], "AcceptabilityJudgment", {s: "While Anna dressed the kitten paid attention."}]
Item set #2:
(transitive) - "Since Dave improved the department was satisfied."
(intransitive) - "Since Dave worried the counselor devised a plan."
[["gp.trans",2], "AcceptabilityJudgment", {s: "Since Dave improved the department was satisfied."}][["gp.intrans",2], "AcceptabilityJudgment", {s: "Since Dave worried the counselor devised a plan."}]
Wrap in var items = [ ... ]
and separate each item by a comma:
Practice Trials:
Filler Trials:
Practice Trials:
Filler Trials:
We want both practice and filler trials to be invariant across conditions
To do that, we don't specify Item Set # for give practice and filler trials, as that gets used for counterbalancing (more later):
Practice Trials:
Filler Trials:
We want both practice and filler trials to be invariant across conditions
To do that, we don't specify Item Set # for give practice and filler trials, as that gets used for counterbalancing (more later):
Practice #1: "The car drove like a dream"
["practice-1", "AcceptabilityJudgment", {s: "The car drove like a dream."}]
Good Filler #1: "When Harry fell, the audience was shocked."
["filler-good-01", "AcceptabilityJudgment", {s: "When Harry fell, the audience was shocked."}]
Bad Filler #1: "When Tyler sneezed the driver, he passed a tissue."
["filler-bad-01", "AcceptabilityJudgment", {s: "When Tyler sneezed the driver, he passed a tissue."}]
Catch Filler #1: "Please select 4 for this sentence."
["filler-catch-01", "AcceptabilityJudgment", {s: "Please select 4 for this sentence."}]
Pull out the names of each trial:
"practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01"
Wrap them in seq()
:
seq( "practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
Assign to shuffleSequence
:
var shuffleSequence = seq( "practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
The shuffleSequence
variable handles the order of presentation of the experiment materials that are stored inside the items
variable.
Problems
var shuffleSequence = seq("practice-1", "gp.trans", "gp.intrans", "gp.trans", "gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
Problems
var shuffleSequence = seq( "practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
A lot of typing ("-02", "-03", ...)
Presentation order of some trials should be random
Problems
var shuffleSequence = seq( "practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans", "filler-good-01", "filler-bad-01", "filler-catch-01")
A lot of typing ("-02", "-03", ...)
Presentation order of some trials should be random
How do we counterbalance critical trials?
To save us from writing repetitive code, we use startsWith()
var shuffleSequence = seq("practice-1","gp.trans","gp.intrans","gp.trans","gp.intrans","filler-good-01","filler-bad-01","filler-catch-01")
var shuffleSequence = seq(startsWith("practice"),startsWith("gp")startsWith("filler"))
The function startsWith()
matches all names that starts with the given string.
To mix critical and filler trials in random order, we use rshuffle()
var shuffleSequence = seq( startsWith("practice"),startsWith("gp")startsWith("filler"))
var shuffleSequence = seq( startsWith("practice"),rshuffle( startsWith("gp"), startsWith("filler") ))
By wrapping both the critical trials (gp...) and the filler trials (filler...) in rshuffle()
, they are mixed together and presented in random order.
To mix critical and filler trials in random order, we use rshuffle()
var shuffleSequence = seq( startsWith("practice"),startsWith("gp")startsWith("filler"))
var shuffleSequence = seq( startsWith("practice"),rshuffle( startsWith("gp"), startsWith("filler") ))
By wrapping both the critical trials (gp...) and the filler trials (filler...) in rshuffle()
, they are mixed together and presented in random order.
We can also write this out more compactly:
var shuffleSequence = seq( startsWith("practice"),rshuffle(startsWith("gp"), startsWith("filler")))
The set number in our critical trials are automatically used for counterbalancing:
The set number in our critical trials are automatically used for counterbalancing:
To alternate items between participants, we use a special counter "trial":
["setcounter", "__SetCounter__", { }]
The counter must be defined in items
and added to shuffleSequence
:
var items = [ ... ["setcounter", "__SetCounter__", { }], // The counter is defined ...]var shuffleSequence = seq( "setcounter", // The counter is incremented at the start ...)
The counter must be defined in items
and added to shuffleSequence
:
var items = [ ... ["setcounter", "__SetCounter__", { }], // The counter is defined ...]var shuffleSequence = seq( "setcounter", // The counter is incremented at the start ...)
Sometimes you want to increment counter in the middle of the experiment:
var shuffleSequence = seq( "intro" "consent", "setcounter", ...)
Consist of miscellaneous options that we can put at the top of the script.
For example, using the defaults
variable, we can specify parameters for the design of the tasks that we use in the experiment, like Acceptability Judgment.
defaults
variableSome options for Acceptability Judgment:
var defaults = [ "AcceptabilityJudgment", { as: ["1", "2", "3", "4", "5", "6", "7"], presentAsScale: true, instructions: "Use number keys or click boxes to answer.", leftComment: "(Bad)", rightComment: "(Good)" }]
defaults
exampleSuppose you'd like to show participants multiple sentences but have them only rate the acceptability of one of the sentences.
var defaults = [ "AcceptabilityJudgment", { ... instructions: "Rate how natural Speaker B's response sounds." }]
[["ConditionA", 1], "AcceptabilityJudgment",{s: ["div", ["p", "Speaker A: Who left this sandwich on the table?"] ["p", "Speaker B: Fred did."] ]}]
We can print lines of text using html tags (more later)
You can also change other options, such as showing a message at the end:
var completionMessage
// A message to show to participants at completionvar completionMessage = "Thank you for your participation!"
And whether to show a progress bar:
var showProgressBar
// Show a progress bar at the top? (true/false)var showProgressBar = false
You can learn more about these various elements in the Miscellaneous options section of the IBEX documentation.
We now have a minimally working experiment!
What we've covered:
We have a templatic syntax for creating stimuli
We store all the materials for our experiment inside items
We specify the order of presentation inside shuffleSequence
We can tweak various aspects of the experiment, like defaults
for the task design.
What we've covered:
We have a templatic syntax for creating stimuli
We store all the materials for our experiment inside items
We specify the order of presentation inside shuffleSequence
We can tweak various aspects of the experiment, like defaults
for the task design.
A few more things we want to know:
How can we show messages and text to participants?
How can we extend this workflow for other experimental designs?
The "Message" controller shows text on a new page.
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
Condition name is used to reference the trial in sequencing
"Message" is a type of task that just shows text on a screen
Inside of the curly braces {} we can add text in the html parameter:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
The "Message" controller shows text on a new page.
It is a list of 3 elements, similar to the "AcceptabilityJudgement" items:
["Condition name", "Message", {html: text}]
Condition name is used to reference the trial in sequencing
"Message" is a type of task that just shows text on a screen
Inside of the curly braces {} we can add text in the html parameter:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
Notes on html:
The code ["p", "<your text here>"]
prints a paragraph of text.
The "p" is an HTML tag and there are many others (most common: "div", "strong", "em"). They don't usually get too complicated.
A message composed of a single paragraph:
["intro", "Message", {html: ["p", "Welcome to the experiment!"]}]
A message composed of multiple paragraphs must be combined inside a "div":
["intro", "Message", {html: ["div", ["p", "Welcome to the experiment!"], ["p", "Here's another paragraph."], ["p", "These paragraphs are all wrapped inside \"div\"."] ]}]
Note: You can escape special characters like quotes "
with a backslash \
Ask for consent with a set of consent...
parameters
["consent", "Message", { html: ["p", "Do you consent?"], consentRequired: true, consentMessage: "I consent."}]
Use the transfer
argument to specify how the participant can move on.
Setting transfer
to "keypress"
removes the default "Click here to continue." message and allows participants to proceed with the press of any key.
["move_on", "Message", { html: ["div", ["p", "The option for \"transfer\" is \"keypress\""], ["em", "Press any key to continue."] ], transfer: "keypress"}]
You might want to insert a page that separates the trials:
["sep", "Message", { html: ["em", "Press any key to continue."], transfer: "keypress"}]
You can do so using sepWith()
in shuffleSequence
:
var shuffleSequence = seq( "practice", sepWith("sep", rshuffle(startsWith("gp"), startsWith("filler"))))
We now have a complete experiment with several Message controllers added.
So we have a new script, but how do we host the experiment?
Go to the PCIbex farm website and log in.
Click into (or create) your experiment and edit the main.js
file.
Click Share in the menu bar to the right and copy the Demonstration link (for testing and development) or Data-collection link (available after publishing)
Demo: https://farm.pcibex.net/r/YBYAwi
Published: https://farm.pcibex.net/p/HCRZqI
Suppose that after a pilot experiment, we find acceptability judgments to be inappropriate for answering our research question.
We want a finer-grained measure of recovery difficulty, so we'd like to change the experiment to self-paced reading and look at differences in reading time.
Suppose that after a pilot experiment, we find acceptability judgments to be inappropriate for answering our research question.
We want a finer-grained measure of recovery difficulty, so we'd like to change the experiment to self-paced reading and look at differences in reading time.
Given our existing template, we take the following steps:
Go to the documentation and find a Controller for self-paced reading.
Specify the design of that controller in the defaults
variable.
Change our trials in items
from "acceptabilityJudgment" to that Controller.
Make changes to the text of the "Messages" items (e.g., directions).
The "DashedSentence" Controller creates self-paced reading trials.
The "DashedSentence" Controller creates self-paced reading trials.
We can simply replace "acceptabilityJudgment" with "DashedSentence" in items
:
var items = [ ... [["gp.trans",1], "DashedSentence", {s: "While Anna trained the kitten paid attention."}], [["gp.intrans",1], "DashedSentence", {s: "While Anna dressed the kitten paid attention."}], [["gp.trans",2], "DashedSentence", {s: "Since Dave improved the department was satisfied."}], [["gp.intrans",2], "DashedSentence", {s: "Since Dave worried the counselor devised a plan."}], ...]
The "DashedSentence" Controller creates self-paced reading trials.
We can simply replace "acceptabilityJudgment" with "DashedSentence" in items
:
var items = [ ... [["gp.trans",1], "DashedSentence", {s: "While Anna trained the kitten paid attention."}], [["gp.intrans",1], "DashedSentence", {s: "While Anna dressed the kitten paid attention."}], [["gp.trans",2], "DashedSentence", {s: "Since Dave improved the department was satisfied."}], [["gp.intrans",2], "DashedSentence", {s: "Since Dave worried the counselor devised a plan."}], ...]
And specify appropriate settings for "DashedSentence" in defaults
:
var defaults = [ "DashedSentence", { mode: "self-paced reading", display: "dashed" }]
Finally, after re-writing some of the "Message" items, we have a new experiment!
You can use the Question controller to ask Yes/No comprehension questions:
[["YesNo_example",1],"Question",{q: "Was the kitten trained?", as: ["Yes", "No"]}]
The as parameter sets the answer choices presented to participants.
[["FC1_example",1], "Question", { instructions: "Choose the more natural sentence.", as: ["Who did you see that ate bread?", "What did you see the girl who ate?"]}]
You can ask for continuations by modifying the q parameter.
[["FC2_example",1], "Question", { q: "While Anna dressed the baby ______", instructions: "Choose the more natural continuation.", as: ["started to cry.", "he started to cry."]}]
Use Form controller with the "textarea" HTML tag to collect a free response:
[["FR_example",1], "Form", {html: ["div", ["em", "Fill out a continuation for the sentence fragment:"], ["p", "While Anna dressed the baby ______"], ["textarea"]]}]
The data collected in the experiment can be found on the experiment page, in the Results tab to the right side of the dashboard.
It gives you a preview of the results and options to download or delete the data that's been collected so far.
If you download the data, you get back a csv file called results.csv
, meaning that each line contains a set of values that are separated by a comma.
Lines that start with a pound symbol "#" are comments that include metadata.
The ones that start with numbers tell us what variable the columns correspond to.
All IBEX experiments return these 7 variables:
Time ("Results reception time")
Participant ID ("MD5 hash of participant's IP address")
Controller ("Controller name")
Item number ("Order number of item")
Inner element number ("Inner element number")
Condition ("Label")
Item set ("Latin Square Group")
In our case, we only care about 4 of these:
Time
Participant ID: A unique ID for each participant
Controller: The type of task/trial (e.g., AcceptabilityJudgment)
Item number
Inner element number
Condition: The condition label for the trial (practice-1, gp-trans, ...).
Item set: The item set number (1,2,3,...).
In our case, we only care about 4 of these:
Time
Participant ID: A unique ID for each participant
Controller: The type of task/trial (e.g., AcceptabilityJudgment)
Item number
Inner element number
Condition: The condition label for the trial (practice-1, gp-trans, ...).
Item set: The item set number (1,2,3,...).
The last two variables uniquely identify the stimuli defined in items
:
[["Condition", Item set], "Controller", {s: "Sentence"}]
[["gp.trans", 1], "DashedSentence", {s: "..."}]
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
These are also outlined in the documentation for "DashedSentence", so you know what variables to expect beforehand.
You also get other variables depending on the Controller
For self-paced reading with "DashedSentence", we get 5 more variables:
Word number - The index of the word in the sentence.
Word - The text of that word.
Reading time - Reading time for that word.
Newline? - 0 or 1 indicating whether there was a line break.
Sentence - The text of the sentence.
These are also outlined in the documentation for "DashedSentence", so you know what variables to expect beforehand.
For an actual analysis of the results, we need the results to be imported somewhere as a data frame, preferrably in a rectangular table format where rows are observations and columns are variables.
Steps for importing the data into Excel:
Copy the text of the results file from IBEX
Paste into the first column of an Excel spreadsheet
Highlight that column and click Data tab -> Filter
Click on the dropdown arrow that appears at the top cell
Click Text Filters -> Begins With... and type in "#"
Go to Home tab -> Find & Select, check "Visible cells only", and click OK
Right click on any part of the sheet and select Delete Row
Click the first column again and go to Data tab -> Text to Columns
Check "Delimited", "Comma", then "General" for each prompt
Add an empty row at the top and manually type in the column names from the comments of the original results file
Some Controllers return multiple lines of results, with differing number of columns
For example, each AcceptabilityJudgment trial is a combination of Message and Question controllers under the hood, so it logs two lines of data:
In more complex cases like these, using a script (R/Python) is recommended
Steps for importing into R:
Download the results.csv
file from PCIbex
Open it with the read_pcibex()
function from the read_pcibex.R script
source("read_pcibex.R")results <- read_pcibex("SPR_results.txt")
# A tibble: 6 × 5 Controller_name Label Word_number Word Reading_time <chr> <chr> <dbl> <chr> <dbl> 1 DashedSentence practice-1 1 The 132 2 DashedSentence practice-1 2 car 115 3 DashedSentence practice-1 3 drove 110 4 DashedSentence practice-1 4 like 112 5 DashedSentence practice-1 5 a 118 6 DashedSentence practice-1 6 dream. 117
source("read_pcibex.R")results <- read_pcibex("Acceptability_results.txt")
# A tibble: 6 × 4 Label Latin_Square_Group Sentence_or_sentence_MD5 Answer <chr> <chr> <chr> <dbl> 1 practice-1 NULL The car drove like a drea… NA 2 practice-1 NULL <NA> 5 3 gp.intrans 2 Since Dave worried the co… NA 4 gp.intrans 2 <NA> 6 5 gp.trans 1 While Anna trained the ki… NA 6 gp.trans 1 <NA> 5
The experiment script incomplete.js has some missing pieces.
Directions:
Download incomplete.js
Create a new experiment on your PCIbex account called "WorkshopExercise" and replace the contents of main.js with incomplete.js.
Follow the directions in the script to fill in the blanks.
Complete as many of tasks as possible (8 total).
If you finish, save the edits, refresh, and preview the experiment in the bottom panel or click Open in new tab. Check to see that your experiment looks similar to the complete version - https://farm.pcibex.net/p/ZvbOXD.
Make sure to reference the IBEX documentation!
https://github.com/addrummond/ibex/blob/master/docs/manual.md
For several of the standard experimental paradigms in linguistics, the PCIbex framework directly ports controllers from IBEX. So for tasks like self-paced reading, you get the same experiment from a different style of code.
You can clone the PCIbex version of the workshop's SPR experiment here - https://farm.pcibex.net/r/nYsovX
PCIbex has great support for experiments involving multimedia (audio, video, etc.). The PCIbex documentation is a good place to get started - https://doc.pcibex.net
IBEX is always good to know due to the sheer amount of linguistics experiments already written in IBEX.
PCIBex is not difficult to pick up after IBEX, should you choose to learn it.
Many thanks to...
Brian Dillon (UMass Amherst) for permission to use materials from the LSA Minicourse "Doing Experiments for Linguists" (Brian Dillon & Rodica Ivan)
Jon Sprouse (UConn) for permission to use materials from LSA 2016, Experimental Syntax Workshop
Florian Schwarz and Jeremy Zehr for permissions to use materials from their PCIbex workshops.
Attendees of the 2021 BK Winter School Workshop on Experimental Linguistics/Syntax at Sungkyunkwan University for valuable feedback on the workshop materials.