(4) Responses and Feedback¶
Here, we learn how to add a feedback stimulus indicating a correct or false response.
Installing sweetbean¶
!pip install sweetbean
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/ Requirement already satisfied: sweetbean in /usr/local/lib/python3.8/dist-packages (0.0.19)
Now, we are looking to incorporate responses from the participant and response feedback to the experiment. Specifically, we would like the participant to press the key f
using their left index finger when the ink color of the color word is red. Similarly, we would like the participant to press the key j
with their right index finger when the color is green.
You can practice your SweetBean skills by implementing these instructions in a block (if you feel comfortable creating text stimuli you can skip this part and use the instructions block in the solution):
# Enter your code here:
Solution¶
# imports
from sweetbean.stimulus import Text
from sweetbean import Block
# Creating the Instructions
welcome = Text(text="Welcome to our experiment.<br>Here, you will have to react to the ink color of a color word.<br>Press SPACE to continue", choices=[' '])
instruction_red = Text(text="If the ink color is <b>red<b>,<br>press <b>F<b> with your left index finger as fast as possible.<br>Press F to continue", choices=['f'])
instruction_green = Text(text="If the ink color is <b>green<b>,<br>press <b>J<b> with your right index finger as fast as possible.<br>Press J to continue", choices=['j'])
instructions_end = Text(text="The experiment will start now.<br>React as fast an as accurate as possible.<br>Remember:<br>React to the ink color not the meaning of the word.<br>Ress SPACE to continus", choices=[' '])
# Creating the stimulus sequence
instructions_sequence = [welcome, instruction_red, instruction_green, instructions_end]
# Creating the block
instructions_block = Block(instructions_sequence)
Here, you will have to react to the ink color of a color word.
Press SPACE to continue", choices=[' ']) instruction_red = Text(text="If the ink color is red,
press F with your left index finger as fast as possible.
Press F to continue", choices=['f']) instruction_green = Text(text="If the ink color is green,
press J with your right index finger as fast as possible.
Press J to continue", choices=['j']) instructions_end = Text(text="The experiment will start now.
React as fast an as accurate as possible.
Remember:
React to the ink color not the meaning of the word.
Ress SPACE to continus", choices=[' ']) # Creating the stimulus sequence instructions_sequence = [welcome, instruction_red, instruction_green, instructions_end] # Creating the block instructions_block = Block(instructions_sequence)
Creating a timeline¶
timeline = [
{'color': 'red', 'word': 'RED'},
{'color': 'green', 'word': 'GREEN'},
{'color': 'green', 'word': 'RED'},
{'color': 'red', 'word': 'GREEN'},
]
Declare TimelineVariables¶
Do you remember how to declare the timeline variables(if you feel comfortable creating timeline variables, you can skip this part and use the solution)?
# Enter your code here:
Solution¶
# import the functionality from sweetbean
from sweetbean.variable import TimelineVariable
## declare the timeline variables
# color: The name has to be color (it is the name in the timeline), and it has the levels red and green
color = TimelineVariable(name="color")
# word: The name has to be word (it is the name in the timeline), and it has the levels RED and GREEN
word = TimelineVariable(name="word")
Creating function variables¶
In SweetBean, in addition to static parameters and timeline parameters, we can also use function parameters. These are parameters, that derive from other features of the trial. Here, we want to derive the correct key from the ink color of the stimulus. Remember: f
for red color words and j
for green color words.
Defining the functions¶
We can first create a function that returns the correct key for a given color:
# defining the predicate for the f-level of the "correct response" parameter
def correct_key_fct(cl):
return 'f' if cl == 'red' else 'j'
Some people might have trouble understanding the code above. A equivalent writing with an if and else statement is:
def correct_key_fct(color):
if color == 'red':
return 'f'
else:
return 'j'
Optional: Python is whitespace sensitive!
In contrast to many other programming languages, Python is whitespace sensitive. Whitespaces in Python do matter and are used to block the code, for example to define functions, in loops or blocks of if-else statements. In that sense they are equivalent to the curly brackets '{}' in Java, JavaScript, C++ and many other programming languages.Creating the function variable levels¶
With the predicates defined, we can now define the function variable. We need to pass in a name, the function and the arguments that we want to pass into the function. In this case, we want to pass in the color of the stimulus.
# importing the functionality
from sweetbean.variable import FunctionVariable
# declare the variable
correct_key = FunctionVariable('correct_key', correct_key_fct, [color])
Create the stimulus¶
The function variable can be used in the creation of the stimulus just as a static or a timeline parameter. Here, we introduce another feature of the text stimulus: We can provide a correct_key parameter. This correct_key parameter can be used for data analysis later, but it can also be used to provide feedback (we will see how this is used later in this tutorial)
# imports
from sweetbean.stimulus import Text
# declaring the stimulus
stroop = Text(duration=2500, text=word, color=color, choices=['j', 'f'], correct_key=correct_key)
This is a stimulus that shows a color word in the color and with the word provided by the timeline. The stimulus is shown for 2500ms or till a response is given. The user can press either j
or f
.
Comprehension question: Can you think of another way to get the correct_key parameter that doesnt' depend on a function variable?
Here, we used the derived paramter to demonstrate how it is used. But we could also simply add the keys to the timeline and use a timeline varibale insted. Often times, there are multiple ways of implementing a desired experiment.Adding feedback¶
To add feedback, we introduce yet another type of variable: the data variable. At the end of each stimulus, data for this stimulus is stored in a container. This data contains stimulus features like color, word and duration, but also user input like key presses. With the data variable, we can access this container to create adaptive stimuli like feedback.
Creating the data variable¶
We create a data variable for the correct-data of a trial. This is a special data point, that can be accessed in stimuli that have the correct_key parameter. A data variable also uses a window argument that specifies how far back in time the data should be accessed. In this case, we want to access the data of the stimulus that came before the current stimulus. So we use a window of 1.
# import
from sweetbean.variable import DataVariable
# declare the data variable
correct = DataVariable('correct', 1)
Defining the function¶
Again, we want to create an adaptive text based on weather the response was correct or notIn the same way we can access timeline variables in predicate functions, we can also access data variables.
# define the function
def get_feedback(was_correct):
if was_correct:
return 'That was correct!'
return 'That was incorrect!'
Creating the function variable¶
Now, we create the function variable. Instead of passing a timeline variable, we pass the data variable.
feedback_text = FunctionVariable('feedback_text', get_feedback, [correct])
Comprehension question: Can you think of another way to get the feeback word parameter that doesnt' depend on a derived paramter?
Here, we can not use a timeline, since this is an adaptive parameter. We have to use the derived parameter and the data variable since we have use information derived from user input.Create a parameter for the color of the feedback.¶
Maybe we also want to change the color of the feedback (green for positive and red for negative feedback). Can you create the derived parameter?
# Enter your code:
# ...
feedback_color = None
Solution¶
# create the levels
def get_feedback_color(was_correct):
return 'green' if was_correct else 'red'
feedback_color = FunctionVariable('feedback_color', get_feedback_color, [correct])
Creating the feedback stimulus¶
feedback = Text(duration=1000, text=feedback_text,color=feedback_color)
Adding a fixation cross, creating the block, creating the experiment and exporting the html¶
You can practice your SweetBean skills by adding a fixation cross and completing experiment. Remember there are two blocks now. If you feel comfortable creating blocks and experiments you can skip this part and use the code in the solution:
# Enter your code:
Solution¶
# import the functionality from sweetbean to create experiments
from sweetbean import Block, Experiment
# fixation stimulus
fixation = Text(800, '+')
# create a stimulus sequence
stimulus_sequence = [fixation, stroop, feedback]
# create the trial block
trial_block = Block(stimulus_sequence, timeline)
# create the experiment from the two blocks
experiment = Experiment([instructions_block, trial_block])
# export to the html file
experiment.to_html('index.html')