Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mzettersten committed Jan 21, 2025
1 parent 61204ef commit 05ef250
Show file tree
Hide file tree
Showing 82 changed files with 1,269 additions and 1 deletion.
1 change: 1 addition & 0 deletions TODO.html
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
<ul class="nav bd-sidenav">
<li class="toctree-l1"><a class="reference external" href="https://cogs219.github.io/knitted_Rmd/intro_to_tidyverse.html">Introduction to Tidyverse</a></li>
<li class="toctree-l1"><a class="reference internal" href="notebooks/python_basics.html">Python basics</a></li>
<li class="toctree-l1"><a class="reference internal" href="notebooks/psychopy_intro.html">Intro to PsychoPy</a></li>
</ul>

</div>
Expand Down
390 changes: 390 additions & 0 deletions _sources/notebooks/psychopy_intro.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,390 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Intro to PsychoPy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Fork the repository for [Intro to Psychopy](https://github.com/COGS219/activities/).\n",
"\n",
"Once you fork or clone the repository, you'll see a file with the starter code. This is the file you will edit and add to as we work through the walkthrough. For reference, the code is reproduced below.\n",
"\n",
"The starter code will show a blue circle for two seconds (2000 ms), then an orange circle for two seconds, and then exit out of the program."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"remove-output"
]
},
"outputs": [],
"source": [
"from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough\n",
"\n",
"#open a window\n",
"win = visual.Window([600,600],color=\"grey\", units='pix', checkTiming=False) \n",
"\n",
"#create a blue circle\n",
"blue_circle = visual.Circle(win,lineColor=\"grey\",fillColor=\"blue\",size=[100,100])\n",
"\n",
"#show the blue circle\n",
"#first, draw the blue circle to the back buffer of the window\n",
"#this means that the blue circle won't be displayed right away\n",
"blue_circle.draw()\n",
"#then \"flip\" the window to show what you just drew\n",
"win.flip()\n",
"\n",
"#wait 2 seconds\n",
"core.wait(2.0)\n",
"\n",
"win.close() #close the window\n",
"core.quit() #quit out of the program"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Intro\n",
"\n",
"**Let's first go through each line of the code above and understand what each line does.**\n",
"\n",
"In the code, we:\n",
"* create a new window to display stimuli in using psychopy's [`Window`](https://psychopy.org/api/visual/window.html#psychopy.visual.Window) function\n",
"* create a (blue) circle stimulus using one of psychopy's [many](https://psychopy.org/api/visual/index.html) visual stimuli classes\n",
"* display that stimulus by executing the core display strategy in Psychopy\n",
" * draw the stimulus to the \"back\" window buffer\n",
" * flip the window to show what was just drawn\n",
"* pause for 2 seconds using psychopy's [`core`](https://psychopy.org/api/core.html) functions for controlling timing\n",
"\n",
"** Drawing and Flipping Visual Stimuli **\n",
"\n",
"When you first use `.draw()` to draw a stimulus to the window, it is not displayed right away. Instead, psychopy allows us to draw as many visual stimuli to a particular display as we like, but does not update what is shown to participants until we use `win.flip()` to flip or refresh the window. This might seem overly complicated at first, but it turns out to be a really useful feature because it gives us a lot of precise control over when exactly a particular visual stimulus is shown (basically, drawing is \"slow\", flipping is quick and can be timed to other things).\n",
"\n",
"One way to visualize this is to imagine that the window has two layers, a front and a back. The front is what the participants see. When we use `.draw()` to draw a stimulus, we \"paint\" that stimulus to the back of the window, so it is not visible to participants. Then once we've drawn to our heart's content, we flip the window over so the back is visible to participants.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Show an orange circle after the blue circle\n",
"\n",
"Next, let's add a second trial where we show an orange circle.\n",
"\n",
" ```{tip}\n",
" Test yourself: Which property of `visual.Circle()` controls the color of the circle?\n",
" ```\n",
"\n",
"\n",
" ```{note}\n",
" The key codes for right and left arrows in PsychoPy are simply 'right' and 'left'\n",
" ```\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Collect a Keyboard Response\n",
"\n",
"Next, let's collect a keyboard response from participants. We want participants to press the key \"b\" if they see a blue circle, and \"o\" if they see an orange circle.\n",
"\n",
" ````{tip}\n",
" The key functions to accept keyboard input are event.getKeys() and event.waitKeys(). Look at how these functions are defined at the [psychopy API web page](https://psychopy.org/api/event.html) or by typing `help(function name)`, e.g., `help(event.getKeys)` after importing `event`\n",
" ```{note}\n",
" getKeys checks if a certain key has been entered since the last call to getKeys, e.g., if an 's' was pressed, `event.getKeys(['s'])` will become True. event.waitKeys() waits until a certain key (or any key) was pressed. \n",
" ```\n",
" ````\n",
"\n",
"Below, we use `event.waitKeys()` to pause everything until a participant presses either 'b' or 'o'. WE'll use this code to replace the `core.wait(2)` line after each of our stimuli are shown. Then "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#wait until the participant presses one of the keys from the key list\n",
"key_pressed = event.waitKeys(keyList=['b','o'])\n",
"#once they press one of those keys, print it out and flip the window (why?)\n",
"if key_pressed:\n",
" print(key_pressed)\n",
" win.flip()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The full code now looks like this:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough\n",
"\n",
"#open a window\n",
"win = visual.Window([600,600],color=\"grey\", units='pix', checkTiming=False) \n",
"\n",
"#create a blue circle\n",
"blue_circle = visual.Circle(win,lineColor=\"grey\",fillColor=\"blue\",size=[100,100])\n",
"\n",
"#show the blue circle\n",
"#first, draw the blue circle to the back buffer of the window\n",
"#this means that the blue circle won't be displayed right away\n",
"blue_circle.draw()\n",
"#then \"flip\" the window to show what you just drew\n",
"win.flip()\n",
"\n",
"#wait until the participant presses one of the keys from the key list\n",
"key_pressed = event.waitKeys(keyList=['b','o'])\n",
"#once they press one of those keys, print it out and flip the window (why?)\n",
"if key_pressed:\n",
" print(key_pressed)\n",
" win.flip()\n",
"\n",
"#wait one second after the response\n",
"core.wait(1)\n",
"\n",
"#show the orange circle\n",
"#first, draw the blue circle to the back buffer of the window\n",
"#this means that the blue circle won't be displayed right away\n",
"orange_circle.draw()\n",
"#then \"flip\" the window to show what you just drew\n",
"win.flip()\n",
"\n",
"#wait until the participant presses one of the keys from the key list\n",
"key_pressed = event.waitKeys(keyList=['b','o'])\n",
"#once they press one of those keys, print it out and flip the window (why?)\n",
"if key_pressed:\n",
" print(key_pressed)\n",
" win.flip()\n",
"\n",
"win.close() #close the window\n",
"core.quit() #quit out of the program"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Changing properties of stimuli\n",
"\n",
"Once we have created a stimulus, we can update its properties very flexibly. \n",
"\n",
"For example, for our circle stimuli, we can update the color of the object very easily."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#update the color of the blue_circle to purple, then re-draw and flip\n",
"blue_circle.color = \"purple\"\n",
"blue_circle.draw() #not a blue circle anymore!\n",
"win.flip()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using for-loops to present trial lists\n",
"\n",
"Currently our code is kind of cumbersome: we have a lot of repetitive elements. Especially if we want to show a lot of trials, copy-pasting the same thing many times seems like a suboptimal strategy for creating our full experiment.\n",
"\n",
"Instead, we can use a for-loop in which we cycle through each trial we want to display to make our experiment much more compact."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough\n",
"\n",
"#open a window\n",
"win = visual.Window([600,600],color=\"grey\", units='pix', checkTiming=False) \n",
"\n",
"#create a general circle\n",
"circle = visual.Circle(win,lineColor=\"grey\",fillColor=\"blue\",size=[100,100])\n",
"\n",
"# trial list\n",
"color_trials = [\"blue\",\"orange\"]\n",
"\n",
"#loop through the trial list\n",
"for current_color in color_trials:\n",
" #update the current color\n",
" circle.color = current_color\n",
" #draw the circle\n",
" circle.draw()\n",
" #flip the window\n",
" win.flip()\n",
"\n",
" #wait until the participant presses one of the keys from the key list\n",
" key_pressed = event.waitKeys(keyList=['b','o'])\n",
" #once they press one of those keys, print it out and flip the window (why?)\n",
" if key_pressed:\n",
" print(key_pressed)\n",
" win.flip()\n",
"\n",
" #wait one second after the response\n",
" core.wait(1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Add an instruction\n",
"\n",
"To add one more element, let's add an instruction for each trial.\n",
"\n",
"Below each circle, we want to show the following instruction:\n",
"\"Press b if the circle is blue and o if the circle is orange.\"\n",
"\n",
"We can ccomplish this using the [visual.TextStim()](https://psychopy.org/api/visual/textstim.html#psychopy.visual.TextStim) class in psychopy.\n",
"\n",
"```{tip}\n",
" Notice in the code below that we can draw multiple stimuli to the screen. In fact, we can draw as many as we like! This is really useful for creating layered/ more complex visual displays. Just bear in mind that items are drawn in order (so sometimes an item can obscure another item!).\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#create the instruction text\n",
"instruction_text = \"Press b if the circle is blue and o if the circle is orange.\"\n",
"instruction = visual.TextStim(win, text = instruction_text, pos = (-100,0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's add it to the code so far, making sure to draw it on each trial."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough\n",
"\n",
"#open a window\n",
"win = visual.Window([600,600],color=\"grey\", units='pix', checkTiming=False) \n",
"\n",
"#create a general circle\n",
"circle = visual.Circle(win,lineColor=\"grey\",fillColor=\"blue\",size=[100,100])\n",
"\n",
"#create the instruction text\n",
"instruction_text = \"Press b if the circle is blue and o if the circle is orange.\"\n",
"instruction = visual.TextStim(win, text = instruction_text,color=\"black\", pos = (0,-100))\n",
"\n",
"# trial list\n",
"color_trials = [\"blue\",\"orange\"]\n",
"\n",
"#loop through the trial list\n",
"for current_color in color_trials:\n",
" #update the current color\n",
" circle.color = current_color\n",
" #draw the circle\n",
" circle.draw()\n",
" #draw the instruction\n",
" instruction.draw()\n",
" #flip the window\n",
" win.flip()\n",
"\n",
" #wait until the participant presses one of the keys from the key list\n",
" key_pressed = event.waitKeys(keyList=['b','o'])\n",
" #once they press one of those keys, print it out and flip the window (why?)\n",
" if key_pressed:\n",
" print(key_pressed)\n",
" win.flip()\n",
"\n",
" #wait one second after the response\n",
" core.wait(1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Explore on your own!\n",
"\n",
"```{tip}\n",
" Each time you make a change, re-run your code to see if it worked! The more changes you make before testing, the more chances there are for an error to slip in, and then it can get harder to figure out why something isn't working. Running your code frequently after small changes is a good way to get comfortable editing code as you start to get familiar with the concepts and syntax.\n",
"```\n",
"\n",
"1. Change the color(s) of the circles.\n",
"\n",
"2. Change the size of the circles.\n",
"\n",
"3. Change which keyboard keys can be used to respond.\n",
"\n",
"4. Change how long the stimuli are shown on the screen.\n",
"\n",
"5. Can you figure out how to provide contingent feedback to people's responses? Provide contingent feedback to participants after each trial: \n",
"\n",
"* If they respond correctly (e.g., “b” for blue), present text reading: “That was correct!”\n",
"* If they respond incorrectly (e.g., “o” for blue), present text reading: “Sorry, that was incorrect!”\n",
"\n",
"6. The repository includes some Pokemon images. Can you figure out how to display them?\n",
"\n",
"```{tip}\n",
" Check out the [`visual.ImageStim()`](https://psychopy.org/api/visual/imagestim.html#psychopy.visual.ImageStim) class\n",
"```\n"
]
}
],
"metadata": {
"celltoolbar": "Edit Metadata",
"kernelspec": {
"display_name": "Python 3.8.13 ('psych750')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
},
"vscode": {
"interpreter": {
"hash": "57beecaf6908bae4f97de5e2dc8e8d0311fae5bc989593c172c307d13e31f6e4"
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading

0 comments on commit 05ef250

Please sign in to comment.