├── .github
└── workflows
│ ├── deploy.yml
│ └── test.yml
├── .gitignore
├── CITATION.cff
├── LICENSE
├── README.md
├── build_book
├── intropy
├── _config.yml
├── _toc.yml
├── config
│ ├── cd_conditions.csv
│ ├── change_detection.psyexp
│ └── ppsaw2.md
├── getting_started
│ ├── about.md
│ ├── installation.md
│ └── jupyter.md
├── img
│ ├── feedback_screen_stroop.png
│ ├── logo.png
│ ├── logo_binder.svg
│ ├── logo_colab.png
│ ├── logo_jupyterhub.svg
│ ├── optimal_fix.png
│ ├── psychopy_book.jpg
│ └── trial_routine_emo_stroop.png
├── index.md
├── misc
│ ├── CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── bibliography.md
│ └── for_developers.md
├── nbgrader_config.py
├── references.bib
├── solutions
│ ├── week_1
│ │ ├── 0_introduction.ipynb
│ │ ├── 1_python_basics.ipynb
│ │ ├── 2_matplotlib.ipynb
│ │ ├── 3_pandas.ipynb
│ │ ├── 4_numpy.ipynb
│ │ ├── 5_extra_exercises.ipynb
│ │ ├── example_data.csv
│ │ ├── example_file.py
│ │ ├── example_module.py
│ │ ├── example_script.py
│ │ ├── rhr_by_gender.png
│ │ ├── rhr_stratified.png
│ │ ├── solution_sine_wave_plot.png
│ │ ├── tests.py
│ │ └── utils.py
│ └── week_2
│ │ ├── Builder
│ │ ├── conditions.xlsx
│ │ ├── stroop.psyexp
│ │ ├── stroop.py
│ │ ├── stroop_lastrun.py
│ │ └── thank_you.png
│ │ └── Coder
│ │ ├── angry.png
│ │ ├── emo_conditions.xlsx
│ │ ├── emo_stroop.py
│ │ └── happy.png
├── tutorials
│ ├── extra_exercises
│ │ ├── extra_exercises.ipynb
│ │ ├── rhr_by_gender.png
│ │ └── rhr_stratified.png
│ ├── week_1
│ │ ├── 0_introduction.ipynb
│ │ ├── 1_python_basics.ipynb
│ │ ├── 2_matplotlib.ipynb
│ │ ├── 3_pandas.ipynb
│ │ ├── 4_numpy.ipynb
│ │ ├── example_data.csv
│ │ ├── example_file.py
│ │ ├── example_module.py
│ │ ├── example_script.py
│ │ ├── solution_sine_wave_plot.png
│ │ ├── tests.py
│ │ └── utils.py
│ └── week_2
│ │ ├── Builder
│ │ └── thank_you.png
│ │ ├── Coder
│ │ ├── angry.png
│ │ └── happy.png
│ │ ├── Matlab.png
│ │ ├── Python.png
│ │ ├── R.png
│ │ ├── intropy_demo.psyexp
│ │ └── stimuli.csv
├── week_1
│ ├── gradebook.db
│ ├── python.md
│ └── python_how_to_continue.md
└── week_2
│ ├── builder_test.md
│ ├── coder_test.md
│ ├── intro_psychopy.md
│ ├── psychopy.md
│ ├── psychopy_builder_part1.md
│ ├── psychopy_builder_part2.md
│ ├── psychopy_coder_part1.md
│ ├── psychopy_coder_part2.md
│ └── psychopy_how_to_continue.md
├── psychopy-env.yml
├── psychopy_test.py
├── requirements.txt
└── test_material
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: deploy
2 |
3 | on:
4 | # Trigger the workflow on push to main branch
5 | push:
6 | branches:
7 | - master
8 |
9 | # This job installs dependencies, build the book, and pushes it to `gh-pages`
10 | jobs:
11 | build-and-deploy-book:
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | matrix:
15 | os: [ubuntu-latest]
16 | python-version: [3.9]
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | # Install dependencies
21 | - name: Set up Python ${{ matrix.python-version }}
22 | uses: actions/setup-python@v4
23 | with:
24 | python-version: ${{ matrix.python-version }}
25 | - name: Install dependencies
26 | run: |
27 | pip install -r requirements.txt
28 |
29 | # Build the book
30 | - name: Build the book
31 | run: |
32 | ./build_book
33 | # jupyter-book build intropy
34 |
35 | # Deploy the book's HTML to gh-pages branch
36 | - name: GitHub Pages action
37 | uses: peaceiris/actions-gh-pages@v3
38 | with:
39 | github_token: ${{ secrets.GITHUB_TOKEN }}
40 | publish_dir: intropy/_build/html
41 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | python-version: [3.8, 3.9, '3.10']
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Set up Python ${{ matrix.python-version }}
16 | uses: actions/setup-python@v4
17 | with:
18 | python-version: ${{ matrix.python-version }}
19 | - name: Install dependencies
20 | run: |
21 | python -m pip install --upgrade pip
22 | pip install -r requirements.txt
23 | - name: Test with pytest
24 | run: |
25 | ./test_material
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 | site/
131 |
132 | # Custom
133 | **/my_awesome_figure.*
134 | **/gradebook.db
135 | intropy/*/week_2/data
136 | intropy/*/week_2/intropy_demo*.py
137 | intropy/*/week_2/stroop*.*py*
138 | intropy/tutorials/week_2/conditions.xlsx
139 | intropy/solutions/week_2/stroop*.py
140 | intropy/*/assignment*
141 | intropy/_build/
142 | intropy/config/*.py
143 | **/.DS_Store
144 |
145 | intropy/autograded
146 | intropy/submitted
147 | intropy/feedback
148 | intropy/config/data
149 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: "Snoek"
5 | given-names: "Lukas"
6 | orcid: "https://orcid.org/0000-0001-8972-204X"
7 | title: "introPy"
8 | version: 0.2.0
9 | doi: 10.5281/zenodo.4392860
10 | date-released: 2021-11-09
11 | url: "https://github.com/lukassnoek/introPy"
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 |
3 | BSD License
4 |
5 | Copyright (c) 2020, Lukas Snoek
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without modification,
9 | are permitted provided that the following conditions are met:
10 |
11 | * Redistributions of source code must retain the above copyright notice, this
12 | list of conditions and the following disclaimer.
13 |
14 | * Redistributions in binary form must reproduce the above copyright notice, this
15 | list of conditions and the following disclaimer in the documentation and/or
16 | other materials provided with the distribution.
17 |
18 | * Neither the name of the copyright holder nor the names of its
19 | contributors may be used to endorse or promote products derived from this
20 | software without specific prior written permission.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 | OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # introPy
2 | 
3 | 
4 |
5 | Materials for a 2 week Python course taught at the Research Master Psychology (University of Amsterdam). Please go to [https://lukas-snoek.com/introPy](https://lukas-snoek.com/introPy) for more information.
6 |
7 | ## Buy me a coffee?
8 |
9 | Even though I have left academia, I keep maintaining this repository in my free time.
10 | If you appreciate these educational materials, you can say thanks by buying me a coffee! :smile:
11 |
12 | [](https://www.buymeacoffee.com/lukassnoeka)
13 |
--------------------------------------------------------------------------------
/build_book:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | # First, build book
5 | jupyter-book build intropy
6 |
7 | # Then, fix Jupyterhub path and Binder path
8 | if [[ "$OSTYPE" == "linux-gnu"* ]]; then
9 | OS=linux
10 | echo "Probably on GH actions!"
11 | nb_html=$(ls intropy/_build/html/solutions/week_1/*.html)
12 | else
13 | OS=mac
14 | echo "Working on Mac!"
15 | nb_html=$(ls intropy/_build/html/solutions/week_1/*.html)
16 | fi
17 |
18 | for nb in $nb_html; do
19 | echo "Fixing $nb ..."
20 | nb_name=$(basename $nb)
21 | nb_name=${nb_name/.html/}
22 | to_replace="https://neuroimaging.lukas-snoek.com/hub/user-redirect/git-pull?repo=https://github.com/lukassnoek/introPy&urlpath=lab/tree/introPy/intropy/solutions/week_1/${nb_name}.ipynb&branch=master"
23 |
24 | # Replace Jupyterhub url
25 | if [ $OS == linux ]; then
26 | sed -i "s+${to_replace}+https://neuroimaging.lukas-snoek.com+g" $nb
27 | sed -i "s+solutions/week_1+tutorials/week_1+g" $nb
28 | else
29 | sed -i '' "s+${to_replace}+https://neuroimaging.lukas-snoek.com+g" $nb
30 | sed -i '' "s+solutions/week_1+tutorials/week_1+g" $nb
31 | fi
32 |
33 | # Fix admonitions
34 | for ad in warning info success danger; do
35 | if [ $OS == linux ]; then
36 | sed -i "s+
+
+g" $nb
37 | sed -i 's+
+
+g' $nb
38 | else
39 | sed -i '' "s+
+
+g" $nb
40 | sed -i '' 's+
+
+g' $nb
41 | fi
42 | done
43 | # Note to self: if you want to run the above loop on Mac, change `sed -i "s+..."` to `sed -i '' "s+..."`
44 | done
45 |
46 | #python remove_solutions.py
--------------------------------------------------------------------------------
/intropy/_config.yml:
--------------------------------------------------------------------------------
1 | #######################################################################################
2 | # A default configuration that will be loaded for all jupyter books
3 | # See the documentation for help and more options:
4 | # https://jupyterbook.org/customize/config.html
5 |
6 | #######################################################################################
7 | # Book settings
8 | title : introPy # The title of the book. Will be placed in the left navbar.
9 | author : Lukas Snoek # The author of the book
10 | copyright : "2020" # Copyright year to be placed in the footer
11 | logo : img/logo.png # A path to the book logo
12 |
13 | # Global settings
14 | only_build_toc_files : false
15 | exclude_patterns : [_build, Thumbs.db, .DS_Store, "**.ipynb_checkpoints", "tutorials/*/*ipynb", "**.pytest_cache", "solutions/assignment*/*", "autograded", "submitted", "feedback"]
16 |
17 | execute:
18 | timeout : 120 # The maximum time (in seconds) each notebook cell is allowed to run.
19 |
20 | parse:
21 | myst_enable_extensions:
22 | - colon_fence
23 | - amsmath
24 | - dollarmath
25 | - linkify
26 | - substitution
27 | - tasklist
28 |
29 | # Online stuff
30 | repository:
31 | url : https://github.com/lukassnoek/introPy
32 | path_to_book : intropy
33 |
34 | launch_buttons:
35 | notebook_interface : jupyterlab
36 | binderhub_url : https://mybinder.org
37 | jupyterhub_url : https://neuroimaging.lukas-snoek.com
38 |
39 | html:
40 | use_repository_button: true
41 | use_issues_button: true
42 | use_edit_page_button: true
43 |
44 | bibtex_bibfiles:
45 | - references.bib
46 |
47 | sphinx:
48 | config:
49 | bibtex_reference_style: author_year
50 |
51 |
--------------------------------------------------------------------------------
/intropy/_toc.yml:
--------------------------------------------------------------------------------
1 | format: jb-book
2 | root: index
3 | parts:
4 | - caption: Getting started
5 | chapters:
6 | - file: getting_started/about
7 | - file: getting_started/installation
8 | - file: getting_started/jupyter
9 | - caption: Python (week 1)
10 | chapters:
11 | - file: week_1/python
12 | - file: solutions/week_1/0_introduction
13 | title: Introduction to Python (T)
14 | - file: solutions/week_1/1_python_basics
15 | title: Python basics (T)
16 | - file: solutions/week_1/2_matplotlib
17 | title: Introduction to Matplotlib (T)
18 | - file: solutions/week_1/3_pandas
19 | title: Introduction to Pandas (T)
20 | - file: solutions/week_1/4_numpy
21 | title: Introduction to Numpy (T)
22 | - file: solutions/week_1/5_extra_exercises
23 | title: Extra exercises (T)
24 | - file: week_1/python_how_to_continue
25 | - caption: PsychoPy (week 2)
26 | chapters:
27 | - file: week_2/psychopy
28 | - file: week_2/intro_psychopy
29 | title: Introduction to PsychoPy (T)
30 | - file: week_2/psychopy_builder_part1
31 | title: Introduction to the Builder (T)
32 | - file: week_2/psychopy_builder_part2
33 | title: A Builder experiment from scratch (T)
34 | - file: week_2/builder_test
35 | title: Test your Builder skills!
36 | - file: week_2/psychopy_coder_part1
37 | title: Introduction to the Coder (T)
38 | - file: week_2/psychopy_coder_part2
39 | title: A Coder experiment from scratch (T)
40 | - file: week_2/coder_test
41 | title: Test your Coder skills!
42 | - file: week_2/psychopy_how_to_continue
43 | - caption: Misc
44 | chapters:
45 | - file: misc/bibliography
46 | - file: misc/for_developers
47 | - file: misc/CONTRIBUTING
48 | - file: misc/CONDUCT
49 |
--------------------------------------------------------------------------------
/intropy/config/cd_conditions.csv:
--------------------------------------------------------------------------------
1 | first,second,changed,correct_resp
2 | 970615,970615,0,left
3 | 307371,307371,0,left
4 | 464185,464185,0,left
5 | 979865,979865,0,left
6 | 496351,496351,0,left
7 | 482482,482482,0,left
8 | 225622,225622,0,left
9 | 479150,479150,0,left
10 | 479480,479480,0,left
11 | 761960,761960,0,left
12 | 553150,553152,1,right
13 | 978003,978043,1,right
14 | 726968,726568,1,right
15 | 486268,416268,1,right
16 | 119197,419197,1,right
17 | 690810,690814,1,right
18 | 670218,670298,1,right
19 | 168194,168094,1,right
20 | 209113,207113,1,right
21 | 750151,730151,1,right
--------------------------------------------------------------------------------
/intropy/config/ppsaw2.md:
--------------------------------------------------------------------------------
1 | # Assignment week 2
2 | For this assignment, you have to program a *change detection* task to test participants' visual working memory. This should be programmed in the Coder interface of PsychoPy. This task consists of a set of trials in which the participant briefly sees a stimulus (usually a set of gratings, slanted lines, or shapes), which after a short delay reappears in the exact same configuration or slightly differently (e.g., one of the lines changed orientation). After the stimulus reappears, the participant then has to respond whether the stimulus changed or not. The idea, here, is that the participant needs to keep the stimulus in *visual working memory* to be able to perform the task. Often, the complexity of the stimulus, sometimes called *set size*, (e.g., the number of lines/shapes presented at each trial) is varied in order to manipulate the working memory load.
3 |
4 | *Please read this page carefully and from top to bottom before starting on your assignment.*
5 |
6 | ```{margin}
7 | For more information about the change detection paradigm, check out the article by [Rouder et al., (2011)](https://link.springer.com/article/10.3758%2Fs13423-011-0055-3)! {cite}`rouder2011measure`
8 | ```
9 |
10 | In this assignment, you will program a relatively simple version of the change detection task involving random strings of integers (e.g., `286931`). To give you an idea of how the experiment should look like, we created a "demo" Builder version of it, which is included in the materials. If you didn't download the materials already, please follow the instructions in the *Downloading the material* section on the [installation page](../getting_started/installation.md).
11 |
12 | In the unzipped folder (probably called *intropy*), there is another folder called *intropy*, which contains yet another folder called *config*. This folder contains a Builder experiment with the name `change_detection.psyexp` (so the full path is: `intropy/intropy/config/change_detection.psyexp`). In the same folder, there is a CSV file named `cd_conditions.csv`, which contains the trial attributes of the experiment.
13 |
14 | :::{admonition} ToDo
15 | :class: attention
16 | Open the `change_detection.psyexp` file in the PsychoPy Builder interface (*File* → *Open* → select the `change_detection.psyexp` file) and run the experiment.
17 | :::
18 |
19 | Essentially, for this assignment, you'll need to recreate the change detection Builder experiment in the Coder interface. Like the Builder version, your Coder experiment should contain the following elements:
20 |
21 | * **A dialog box asking for the participant number**
22 |
23 | Asking for a participant ID (a number).
24 |
25 | * **A welcome screen for 2 seconds**
26 |
27 | Use whatever text you like (as long as it's professional).
28 |
29 | * **An instruction screen (visible until participant pressed 'enter')**
30 |
31 | You may copy the text from the Builder experiment if you want. Make sure it is clear that the participant needs to press the left key when the stimulus was the same, and the right key when the stimulus changed.
32 |
33 | * **An initial fixation target (1 second)**
34 |
35 | You may use whatever fixation target you like.
36 |
37 | * **A trial loop consisting of both the trial itself and subsequent feedback**
38 |
39 | Make sure the trial is build up as indicated in the *Trial routine structure* below.
40 |
41 | * **An overview of the participant's performance (5 seconds)**
42 |
43 | Make sure it shows the accuracy (proportion of correct trials) in a `TextStim`.
44 |
45 | * **Saving the data**
46 |
47 | The data should be saved in the current directory with the filename `sub-xx_events.csv`. This file should contain (at least) the following columns:
48 |
49 | * `first_string` (the string presented the first time, e.g., "386291")
50 | * `second_string` (the string presented the second time, e.g., "386281")
51 | * `condition` (either "change" or "no_change")
52 | * `response` (either "left" or "right")
53 | * `reaction_time` (in seconds, e.g., "0.6292389").
54 |
55 | ## Trial/feedback routine structure
56 | Specifically, the trial + feedback part should be build up as follows:
57 |
58 | * Presentation of the stimulus (0.5 seconds);
59 | * A delay showing the fixation target (1.5 seconds);
60 | * Second presentation of the (identical or changed) stimulus (0.5 seconds)
61 | * Presentation of a fixation target during which the participant has to respond (1.5 seconds)
62 | * Presentation of colored feedback text ("Correct!" in green, "Wrong!" in red, or "Missed!" in white; 0.5 seconds)
63 | * Presentation of a fixation target (i.e., an inter-stimulus interval; 1 second)
64 |
65 | ### Stimuli
66 | We already created the stimuli for you, which we stored in the `cd_conditions.csv` file (located in the same directory as the `change_detection.psyexp` file).
67 |
68 | :::{admonition} ToDo
69 | :class: attention
70 | Open the `cd_conditions.csv` file in Excel/LibreOffice or a plain-text file editor (e.g., Notepad).
71 | :::
72 |
73 | The CSV file contains 20 rows for 20 trials, with the following attributes (column names):
74 |
75 | * `first`: the first stimulus (for the first presentation)
76 | * `second`: the second stimulus (for the second presentation)
77 | * `changed`: whether the stimulus is changed (`1`) or not (`0`)
78 | * `correct_resp`: the correct response for this trial (either "left" or "right" arrow key)
79 |
80 | We recommend you use this file (after reading it in using Pandas) in your experiment, but you don't have to! It's completely fine to generate the stimuli yourself using your own Python code. (In fact, if you want to complete the *Advanced Feature*, you *have to* create them yourself.) If you do so, please make sure the stimuli (i.e., digits) adhere to the following criteria:
81 |
82 | * There should be at least 20 unique stimuli (and thus at least 20 trials);
83 | * Of all stimuli, 50% should belong to the “change” condition (and the other 50% to the “no_change” condition);
84 | * For the stimuli in the “change” condition, each digit from the string should have the same chance of being changed;
85 | * For stimuli in the “change” condition, only a single digit should be changed
86 | * The changed digit (e.g., 4) should have an equal chance of being changed to any other digit (e.g., 0, 1, 2, 3, 5, 6, 7, 8, 9).
87 |
88 | ## Advanced version
89 | If you complete the experiment as described thus far, you'll score an 9 (out of 10). For the remaining point, you need to add one "advanced" feature to the experiment: the ability to change the length of the string of digits when running the experiment. To do this, add another field to the dialog box, `nr_of_digits` (with a default of 6), which determines the length of the random strings of digits used in the entire experiment (e.g., when filling in 9, stimuli have 9 digits). The minimum number of digits should be 4 and the maximum should be 12 (otherwise, make sure the experiment aborts).
90 |
91 | Depending on the value submitted to the `nr_of_digits` parameter in the dialog box, your experiment should generate the trials "on the fly" (make sure they adhere to the criteria listed in the previous section) and subsequently be presented as outlined previously. This means that you should *not* use an external conditions file (like the `cd_conditions.csv`) if you want to complete this advanced version. Also, in addition to the columns mentioned above, add a column `nr_of_digits` to the data file.
92 |
93 | We highly recommend that you first try to implement the regular experiment and only then try to implement this advanced feature if time permits.
94 |
95 | ## Grading key
96 | Your assignment will be graded on both qualitative criteria (5 points) and quantitative criteria (25 points), outlined below.
97 |
98 | :::{warning}
99 | This probably goes without saying, but if you hand in the compiled Builder script from the demo experiment, you will fail this assignment.
100 | :::
101 |
102 | ### Qualitative criteria (10 points)
103 | The qualitative criteria are related to the quality of the code as well as the experiment.
104 |
105 | * **Readability of code (comments where needed, consistently formatted, etc.)**
106 |
107 | If you would give this script to someone who doesn't know PsychoPy, would they understand how it worked? (5 points)
108 |
109 | * **Run without errors**
110 |
111 | Does the code run without errors? (5 points)
112 |
113 | ### Quantitative criteria (20 points)
114 | The following elements need to be incorporated as specified and work as expected:
115 |
116 | * An dialog box (1 point);
117 | * A welcome screen (1 point);
118 | * Instructions (2 points);
119 | * Trial/feedback routine:
120 | * Trial routine structure and timing (2 points);
121 | * Correct feedback routine (correct text/color; 3 points);
122 | * Overview routine:
123 | * Computing accuracy (1 point);
124 | * Screen with accuracy (1 point);
125 | * Response key and reaction time are stored inside trial loop (3 points);
126 | * Data is saved as a CSV file with proper name (and contains all specified columns; 3 points)
127 | * Advanced `nr_of_digits` feature (3 points)
128 |
129 | ## Tips & tricks
130 | You can find some tips and tricks for completing this assignment below (feel free to use or ignore as you like)!
131 |
132 | * Feel free to copy-paste stuff from the tutorials, *but make sure you are using the correct variable named in your experiment*;
133 | * Google is your friend; use it!;
134 | * It doesn't matter which timing method you use (the `wait` function/clock-based timing/frame-based timing);
135 | * When developing the experiment, set `fullscr=False` during initialization of your `Window` so you can abort it whenever you want;
136 | * Testing, testing, testing: make sure you test your experiment regularly!
137 |
138 | Finally, don't try to implement the entire experiment at once. Instead, implement the features step by step. I would recommend implement the features in the following order:
139 |
140 | 1. The dialog box
141 | 2. The welcome screen
142 | 3. The instruction screen
143 | 4. Reading in the conditions file (if you use this)
144 | 5. The trial loop, containing the first stimulus presentation, the delay, the second stimulus presentation, and the ISI *only*
145 | 6. Once the trial loop is working, add the feedback part
146 | 7. Once the feedback part is working, try storing the participant response and reaction time in a Pandas `DataFrame` (this may be the same `DataFrame` that contains the trial attributes)
147 | 8. Compute accuracy and show it
148 | 9. Make sure your `DataFrame` contains everything it needs and save it to disk
149 | 10. Work on the *advanced feature* if you still have time (you may want to do this in a separate file to not mess up your current version)
150 |
151 | ## Plagiarism
152 | Although this is an "open-book" assignment, you may not work together on this assignment. In case we find out that students worked together on this assignment, this will be reported as plagiarism to the exam committee.
153 |
154 | ## Handing in your assignment
155 | Hand in your experiment (a `.py` file) on Canvas: *Modules* → *Assignment 4 (PsychoPy)*. **If you use additional files (e.g., custom Python modules you wrote, a conditions Excel/CSV file, etc.), make sure to upload those files as well**.
156 |
157 | The deadline for handing in the assignment is 3 PM.
158 |
159 |
GOOD LUCK! You got this.
160 |
--------------------------------------------------------------------------------
/intropy/getting_started/about.md:
--------------------------------------------------------------------------------
1 | # About this course
2 | This two-week course was created for the Research Master Psychology at the University of Amsterdam. It is part of the four-week course "Programming in Psychological Science", which starts with two weeks of *R* programming, after which students can choose one of two topics for the remaining two weeks: advanced *R* or Python/PsychoPy (this course). As such, this Python/PsychoPy course assumes that students are familiar with *basic* programming concepts (such as conditionals, loops, and functions). In week 1 of this course, we will delve deeper into Python-specifics (at least, compared to *R*) topics such as object-oriented programming and the most important packages for data processing (including *pandas*, *numpy*, and *matplotlib*). In week 2, we will discuss how to use the software package PsychoPy to create experiments using both its graphical interface (the *Builder*) and its Python interface (the *Coder*).
3 |
4 | ## Tutorials
5 | This website contains information and tutorials about Python and PsychoPy. Each topic/tutorial has its own page. Tutorials are designed with a `(T)` in the menu on the left. The Python tutorials (week 1) were written in Jupyter notebooks, which are embedded as static HTML files on the website. You can, of course, just read through these pages, but Jupyter notebooks really shine when used *interactively*, which allows you to add, change, and run the Python code embedded in these notebooks. To use these notebooks interactively, you can click on the "rocket" button at the top right of the page (see below; note that this button doesn't do anything). This reveals two options: *Binder* and *JupyterHub*. Both allow you to run the notebooks interactively, but the latter is only available to students of the Research Master Psychology. JupyterHub and Jupyter notebooks are explained in more detail [here](jupyter.md).
6 |
7 |
9 |
10 | The tutorials from week 2 are about PsychoPy and are not written in Jupyter notebooks. Instead, they are simply embedded as (static) pages on this website, which contain explanations about the material *and* plenty of exercises!
11 |
12 | Note that we provide both the tutorials and the associated solutions. In the folder with course materials you downloaded, they are located in the folders *tutorials* and *solutions*, respectively. The solutions are exactly the same as the tutorial notebooks, except that they contain the solution embedded between `### BEGIN SOLUTION` and `### END SOLUTION` identifiers. The solutions for the week 2 tutorials are files that contain the full implementation of the tutorial experiments (in `psyexp` files for Builder experiments and regular Python files for Coder experiments).
13 |
14 | ## Availability of materials
15 | All material from this course (except for the assignments, see below) is open-source and available under the [BSD 3-clause license](https://github.com/lukassnoek/introPy/blob/master/LICENSE). This allows redistribution and use, with or without modification, as long as proper attribution is given (see below). We would love it when others would use this material!
16 |
17 | Although all tutorials are publicly available in the course's [Github repository](https://github.com/lukassnoek/introPy), we do not publish the course's assignments as this would enable students to start working on them before they are allowed to do so (and to share the answers). There are two assignments: one Jupyter notebook with several graded exercises testing the students' Python, Pandas, and Matplotlib skills (week 1) and one extensive description of a PsychoPy experiment students have to implement using the PsychoPy Coder interface (week 2).
18 |
19 | If you'd like to get access to these assignments, please send Lukas an email (his email address can be found on his [website](https://lukas-snoek.com/)).
20 |
21 | ## Mistakes, errors, bugs
22 | Although the course materials are tested regularly, they likely still contain mistakes, (spelling) errors, and bugs. You can raise an issue or suggest and edit by clicking on the Github button (see below) on the top of each page.
23 |
24 |
26 |
27 | For more information about contributing, check out [this page](../misc/CONTRIBUTING.md).
28 |
29 | ## Acknowledgements
30 | The course material was developed by Lukas Snoek with help from Emma Schreurs. The Python tutorials were adapted from the [*NI-edu* course](https://neuroimaging-uva.github.io/NI-edu/), also taught at the Research Master Psychology (by Lukas Snoek, H. Steven Scholte, Noor Seijdel, and Jessica Loke). The PsychoPy tutorials are in part based on the [PsychoPy workshop](https://nbviewer.jupyter.org/github/gestaltrevision/python_for_visres/blob/master/index.ipynb) from the [GestaltReVision group](http://gestaltrevision.be/en/) at KU Leuven and the materials from PsychoPy's own [3-day workshop](https://workshops.psychopy.org/3days/materials.html). If you ever use PsychoPy in your experiments, please give the PsychoPy developers credit by citing them {cite}`peirce2019psychopy2`.
31 |
32 | The exercises in Jupyter notebook tutorials were created using the [nbgrader](https://nbgrader.readthedocs.io/en/stable/) package {cite}`hamrick2016creating`. This website was created using the awesome [Jupyter book](https://jupyterbook.org/) package.
33 |
34 | ## Attribution
35 | Snoek, L. (2021). introPy (Version 0.2.0) [Computer software]. https://doi.org/10.5281/zenodo.4392860
36 |
--------------------------------------------------------------------------------
/intropy/getting_started/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 | This pages describes how to download and install the software and materials needed for this course.
3 |
4 | ## Python
5 | For this course, we need a working installation of Python. There are two options: you can download Python yourself (see below) or you can use an online environment preconfigured with a working Python installation.
6 |
7 | ### Online access to Python
8 | For students of the Research Master Psychology, we have set up an external server with Python (through [Jupyterhub](https://jupyter.org/hub), which is explained [here](jupyter.md)) which can be used to do the tutorials of week 1; so no need to download Python yourself. The course's Canvas page outlines how to access the server. Alternatively, you may use [Binder](https://mybinder.org/), which is a service that provides an online Python environment with the course's materials. Note that our own Jupyterhub instance is only accessible to students from the Research Master Psychology who are enrolled in the "Programming for Psychology" course. Note that you must be connected to UvA VPN to be able to access the UvA server.
9 |
10 | The tutorials of week 1 are embedded on this website as well (i.e., the pages on the left with the `(T)`), but these are not interactive, i.e., you cannot add, edit, or run the code. To start the tutorials as interactive notebooks, click on the "rocket" button on the top right and choose *JupyterHub* (UvA students only) or *Binder* (anyone). This will launch an online environment in which you can interactively run the material. Note that the "rocket" button is only available for actual tutorials.
11 |
12 | In the online environment, you'll see a lot of files. The course material is stored in the *tutorials* folder. The *solutions* folder contains the same material, but with solutions to the exercises in the tutorials. You can ignore the rest of the files (which have to do with configuration and the contents of this website).
13 |
14 | :::{warning}
15 | Note that Binder does not save your notebooks! After you quit Binder (or it times out after an hour of inactivity), all progress is lost (but you can download your notebooks/files). Our own Jupyterhub *does* save the files.
16 | :::
17 |
18 | More information on how to get started with the tutorials, go to the [week 1 page](../week_1/python.md).
19 |
20 | ### Installing Python on your own computer
21 | If you want to install Python on your own computer, we *highly* recommend you install Python through the [Anaconda distribution](https://www.anaconda.com/products/individual). In the box below, you can find detailed installation instructions (thanks to [the Netherlands eScience Center](https://escience-academy.github.io/2020-12-07-parallel-python/)) specific to your operating system (Mac, Windows, or Linux).
22 |
23 | ```{tabbed} Mac
24 |
25 | 1. Open the [Anaconda download page](https://www.anaconda.com/products/individual#download-section) with your web browser;
26 | 2. Download the Anaconda Installer with Python 3 for macOS (you can either use the Graphical or the Command Line Installer);
27 | 3. Install Python 3 by running the Anaconda Installer using all of the defaults for installation.
28 |
29 | For a more detailed instruction, check out the video below:
30 |
31 |
32 | ```
33 |
34 | ```{tabbed} Windows
35 |
36 | 1. Open the [Anaconda download page](https://www.anaconda.com/products/individual#download-section) with your web browser;
37 | 2. Download the Anaconda for Windows installer with Python 3. (If you are not sure which version to choose, you probably want the 64-bit Graphical Installer Anaconda3-...-Windows-x86_64.exe);
38 | 3. Install Python 3 by running the Anaconda Installer, using all of the defaults for installation except **make sure to check Add Anaconda to my PATH environment variable**.
39 |
40 | For a more detailed instruction, check out the video below:
41 |
42 |
43 |
44 | **Note**: the video tells you to use *git bash* to test your Python installation; you may ignore this. As explained below, Windows users should use the *Anaconda prompt* instead.
45 | ```
46 |
47 | After you have installed your own Python distribution, you can check whether it is working correctly by opening a terminal (on Mac/Linux) or Anaconda Prompt (on Windows) and running the following:
48 |
49 | ```
50 | python -c "import sys; print(sys.executable)"
51 | ```
52 |
53 | This command should print out the location where you installed Python, e.g., `/Users/your_name/anaconda3/bin/python` (on Mac) or `C:\Users\your_name\anaconda3\bin\python` (on Windows).
54 |
55 | ## PsychoPy
56 | In the second week of the course, we are going to use [PsychoPy](https://www.psychopy.org/), a Python-based software package, to create simple experiments. There are two ways of installing PsychoPy: installing the core Python package `psychopy` and installing the complete "standalone" PsychoPy software package. We highly recommend installing the "standalone" version (because it also includes the PsychoPy Builder interface), but we explain both approaches in turn.
57 |
58 | ### PsychoPy standalone version (recommended)
59 | Instead, we *highly* recommend installing the ["standalone" version of PsychoPy](https://www.psychopy.org/download.html). The standalone version does not only contain a working version of the `psychopy` package, but also a custom Python distribution specifically designed to work with PsychoPy, as well as a neat code editor and even a graphical interface (the PsychoPy *Builder* interface) to create experiments without programming. Students of the "Programming in Psychological Science" should install the standalone PsychoPy version.
60 |
61 | To download the standalone version, go to [this page](https://www.psychopy.org/download.html) and click on the big blue download button.
62 |
63 | :::{warning}
64 | For some (?) Windows users, the PsychoPy website states "To install PsychoPy on Windows we recommend installing PsychoPy through `pip`". Don't do this (because it doesn't include the Builder interface). Instead, click on the link [PsychoPy releases on github](https://github.com/psychopy/psychopy/releases) and download the latest `.exe` file (currently, `StandalonePsychoPy3-2020.2.10-win64.exe`).
65 | :::
66 |
67 | To test whether the standalone PsychoPy installation was successful and everything works as expected do the following:
68 |
69 | * Start PsychoPy (this should open three windows);
70 | * Make sure you are in the *PsychoPy Builder* window;
71 | * In the menu, click *Demos* → *Unpack demos*, and select a location to unpack the demo experiment files;
72 | * Click on *Demos* again and then on *stroop*, which should open `stroop.psyexp` in the PsychoPy Builder;
73 | * Click on the green "play" button (*run experiment*);
74 | * After a couple of seconds, you should see a pop-up prompting for a "session" and "participant number";
75 | * Fill in some number (e.g., 01) and click on *Ok* to start the experiment;
76 | * Your screen should turn black and start the experiment!
77 |
78 | ### PsychoPy Python package
79 | If you have a working version of Python already, you can also work with PsychoPy by installing the `psychopy` Python package. This is only recommended if you are experienced with managing Python environments and running things on the command line in general.
80 |
81 | The `psychopy` Python package contains all the functionality you need to run PsychoPy experiments in "script mode", i.e., writing your experiment as a Python script (e.g., `my_experiment.py`) and running it on the command line (e.g., `python my_experiment.py`). This means that this installation of PsychoPy does not include the Builder functionality nor the PsychoPy Code editor.
82 |
83 | There are several ways to install the `psychopy` package, but (assuming you installed Python through Anaconda) the easiest way is probably through `conda` (the Anaconda package manager). Assuming you have downloaded the material (check the section *Downloading the material* below), there should be a file with the name `psychopy-env.yml` in the root of the downloaded folder.
84 |
85 | Open a terminal (or Anaconda prompt if you are on Windows), navigate to the root of the materials folder, and run the following:
86 |
87 | ```
88 | conda env create -n psychopy -f psychopy-env.yml
89 | ```
90 |
91 | This will create a new Python environment (using Python version 3.10) with the `psychopy` package and all its dependencies. This may take 5 to 10 minutes or so. To activate this environment, run the following in your terminal:
92 |
93 | ```
94 | conda activate psychopy
95 | ```
96 |
97 | Make sure that whenever you want to run (or test) your PsychoPy experiments, the "psychopy" environement is activated in your terminal. To test whether the installation (and activating the environment) was successful, navigate to the root of the materials folder in your terminal (if you hadn't done so already) and run the following:
98 |
99 | ```
100 | python psychopy_test.py
101 | ```
102 |
103 | If your installation was successful, this should open a small, rectangular window showing some text. Press enter to close the window.
104 |
105 | :::{tip}
106 | If you're installing the `psychopy` Python package (instead of the standalone version), you still need a code editor to write your experiment. You may use any plain-text editor (e.g., Notepad++, Atom, or Sublimetext). Personally, we like [Visual Studio Code](https://code.visualstudio.com/).
107 | :::
108 |
109 | ## Downloading the material
110 | We use [Jupyter notebooks](https://jupyter.org/) for our tutorials. The materials are stored on [Github](https://github.com/lukassnoek/introPy) and can be downloaded as a zip-file by clicking on the link below:
111 |
112 | Download materials
113 |
114 | After downloading the materials, please unzip the folder. The resulting directory has the following structure and contents (the # symbols represent comments/information):
115 |
116 | ```
117 | intropy # Directory root
118 | │
119 | ├── LICENSE
120 | ├── README.md
121 | ├── build_book
122 | │
123 | ├── intropy # Directory with materials
124 | │ │
125 | │ ├── _build #
126 | │ ├── _config.yml #
127 | │ ├── _toc.yml #
128 | │ ├── config #
129 | │ ├── getting_started #
130 | │ ├── gradebook.db #
131 | │ ├── img #
132 | │ ├── index.md #
133 | │ ├── misc #
134 | │ ├── nbgrader_config.py #
135 | │ ├── references.bib #
136 | │ │
137 | │ ├── solutions # Tutorials WITH solutions
138 | │ │ ├── week_1 # Jupyter notebook tutorials
139 | │ │ └── week_2 # Files + solutions of PsychoPy tutorials
140 | │ │ ├── Builder
141 | │ │ └── Coder
142 | │ │
143 | │ ├── tutorials # Tutorials
144 | │ │ ├── week_1 # Jupyter notebook tutorials
145 | │ │ └── week_2 # Files needed for PsychoPy tutorials
146 | │ │ ├── Builder
147 | │ │ └── Coder
148 | │ │
149 | │ ├── week_1 # Website pages week 1 (can be ignored)
150 | │ └── week_2 # Website pages week 2 (can be ignored)
151 | │
152 | ├── requirements.txt # Required packages for week 1 (and book)
153 | └── test_material # Test Jupyter notebooks (for developers)
154 | ```
155 |
156 | The only revelant directories are the `intropy/intropy/solutions` and `intropy/intropy/tutorials` directories, which contain the tutorials with and without solutions included, respectively.
157 |
158 | Note that students from the Research Master course do *not* need the materials from week 1 (which are already on the server), only the materials from week 2 (because PsychoPy programs need to be run locally on your computer).
159 |
160 | :::{warning}
161 | If you work with your own Python installation, you need to install additional Python packages to make sure all material from week 1 works as expected. To do so, open a terminal (Mac/Linux) or Anaconda prompt (Windows)
162 | and navigate to the root directory of the downloaded materials (`cd path/to/downloaded/materials`) and run the following:
163 |
164 | pip install -r requirements.txt
165 |
166 | Note that this is not necessary if you use Binder (or the UvA JupyterHub) as your Python environment!
167 | :::
168 |
169 | Before you start working on the course materials, read the next page on the [Jupyter ecosystem](jupyter.md).
170 |
--------------------------------------------------------------------------------
/intropy/getting_started/jupyter.md:
--------------------------------------------------------------------------------
1 | # The Jupyter ecosystem
2 | In this course, we will use several tools from *project Jupyter* {cite}`kluyver2016jupyter`. This project includes several nifty tools to make programming a little easier!
3 |
4 | ## JupyterHub
5 | One tool that we use in this course is "JupyterHub". This piece of software allows you to easily create a preconfigured Python environment on an external server — no need to install Python on your own computer anymore! You just go to the website/public IP associated with the external server and you can start programming! We run JupyterHub on our own server at the University of Amsterdam, which Research Master students can use for this course. Others may use the aforementioned tool "Binder" to create a JupyterHub instance themselves, which can be used for this course as well!
6 |
7 | ## Jupyter interfaces: classic vs. JupyterLab
8 | The Jupyter environment offers two interfaces: the *classic* interface and the more extensive *JupyterLab* interface. On our own JupyterHub instance, we enabled the classic interface by default, because the [grading software](https://nbgrader.readthedocs.io/) we use only works with this interface. On Binder, the classic notebook is the default interface, as well.
9 |
10 | ::::{note}
11 | Both the classic interface and the JupyterLab interface are shipped with the Anaconda distribution, so no need to install them manually! If you, for whatever reason, *do* need to install them, you can do so using `pip`:
12 |
13 | ```
14 | pip install {package-name}
15 | ```
16 |
17 | Replace `{package-name}` with `jupyter` to install the classic notebook interface and with `jupyterlab` to (additionally) install the JupyterLab interface.
18 |
19 | Also, while on JupyterHub (including Binder) the Jupyter environment is always running, on your own computer you need to start it manually by running the following command in your terminal (or CMD prompt/Anaconda prompt/Powershell on Windows):
20 |
21 | ```
22 | jupyter notebook
23 | ```
24 |
25 | which opens the classic interface. To open the JupyterLab interface, run the following:
26 |
27 | ```
28 | jupyter lab
29 | ```
30 |
31 | These command will open a (new) tab in your default browser with the Jupyter interface. Note that, to stop the interface on your own computer, you need to stop the terminal process you started by typing Control (or Command) + C (or simply closing the terminal).
32 | ::::
33 |
34 | Both interfaces allow you to write, edit, and run code. Note that this is not limited to Python code! By installing different [kernels](https://jupyter.readthedocs.io/en/latest/projects/kernels.html), you can run programs written in many different programming languages, including R, [Julia](https://julialang.org/), and even Matlab. In fact, the name "Jupyter" is a reference to the three core programming languages supported by Jupyter: Julia, Python, and R.
35 |
36 | In the Jupyter environment, code can be written and executed in different ways, which can be roughly divided into "script-based" and "interactive" approaches. In the script-based approach, you write your Python code in plain-text Python files (i.e., files with the extension `.py`) and run them, as a whole, in the terminal. In the interactive approach, you can write and run code interactively in either a Python *console* (or *shell*) or in a *Jupyter notebook*. The Jupyter notebook is the most common format for interactive computing and we will use it heavily in week 1 of this course. The next sections explains Jupyter Notebooks in more detail.
37 |
38 | For now, if you want to quickly explore the Jupyter environment, you can click one of the two buttons below, which will access JupyterHub instance (with a classic interface) that includes the course materials. The UvA JupyterHub (orange button) is only accessible to Research Master Students enrolled in the "Programming for Psychology" course; instructions on how to log in onto the UvA JupyterHub can be found on Canvas. The Binder JupyterHub (blue button) can be used by anyone.
39 |
40 | [](https://neuroimaging.lukas-snoek.com)
41 | [](https://mybinder.org/v2/gh/lukassnoek/introPy/master?urlpath=lab)
42 |
43 | Note that, instead of using the classic interface, you can launch the JupyterLab interface by replacing the `/tree` snippet in the URL to `/lab`. To change it back to the classic interface again, click on *Help* → *Launch Classic Notebook* or change the `/lab` snippet back to `/tree` in the URL.
44 |
45 | ## Jupyter Notebooks
46 | As mentioned, we use "Jupyter Notebooks" a lot in this course. Jupyter notebooks are very similar to R Markdown files. Like R Markdown files, you can mix text, code, plots, and mathematical formulas within a single document (see gif below).
47 |
48 | 
49 | *Gif from Cornellius Yudha Wijaya on [towardsdatascience.com](https://towardsdatascience.com/elevate-your-jupyter-notebook-environment-experience-9bdd1101aa54)*
50 |
51 | Most of our tutorials are actually written in Jupyter notebooks. These notebooks are great for "interactive programming", in which it is easy to experiment, try out, and troubleshoot your code. Because this mode of programming is great for teaching, we will use Jupyter notebooks a lot in week 1. Interactive programing is not, however, the only way in which you use Python. In fact, a lot of people use Python in a non-interactive way by writing scripts. In this "script mode" (for lack of a better term), writing the code and running the code are done separately. The code interface of PsychoPy (discussed in week 2), for example, cannot be used interactively and only supports "script mode". We will dicuss both modes in this course.
52 |
53 | If you want to check out Jupyter notebooks already, open a Jupyter interface (using Binder, the UvA JupyterHub, or on your own computer) and, in the upper right corner, click on *New* → *Python 3* (in the classic interface) or click on the Python 3 tile in the launcher tab (in the JupyterLab interface).
54 |
55 | Now, you should be ready to start on the [course materials from week 1](../week_1/python.md).
--------------------------------------------------------------------------------
/intropy/img/feedback_screen_stroop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/feedback_screen_stroop.png
--------------------------------------------------------------------------------
/intropy/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/logo.png
--------------------------------------------------------------------------------
/intropy/img/logo_binder.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
--------------------------------------------------------------------------------
/intropy/img/logo_colab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/logo_colab.png
--------------------------------------------------------------------------------
/intropy/img/logo_jupyterhub.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/intropy/img/optimal_fix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/optimal_fix.png
--------------------------------------------------------------------------------
/intropy/img/psychopy_book.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/psychopy_book.jpg
--------------------------------------------------------------------------------
/intropy/img/trial_routine_emo_stroop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/img/trial_routine_emo_stroop.png
--------------------------------------------------------------------------------
/intropy/index.md:
--------------------------------------------------------------------------------
1 | Welcome to *introPy*
2 | ====================
3 |
4 | This website contains information about the two-week Python & PsychoPy course taught at the Research Master Psychology (University of Amsterdam).
5 |
6 | ## Prerequisites
7 | As this two-week Python course is preceded by a two-week *R* course in the Research Master Psychology, we assume that students are familiar with basic programming concepts (such as variables, conditionals, loops, and functions). Familiarity with Python is not necessary. Those that already have some experience with Python, however, may find the tutorials from this course (too) easy. To challenge those people, we included several more difficult (optional) sections and exercises in the tutorials!
8 |
9 | ## Teaching philosophy
10 | We believe in *learning by doing*. Most of your time will be spent by working on exercises, which we call *ToDos*. Although these exercises are ungraded, we highly recommend that you try to do them. If you manage to work through all of them, getting a decent grade on this course is expected.
11 |
12 | ## Overview
13 | In week 1, you will learn the basics of Python. We assume that you have some programming experience in other languages (e.g., Matlab or R). In week 2, you will learn about the Python package [PsychoPy](https://www.psychopy.org/), which you can use to program experiments. The preliminary program can be found below.
14 |
15 | | Week | Day | Format | Topic |
16 | |------|-----|------------------|--------------------------------------------|
17 | | 1 | Mo. | Lecture | Introduction to Python |
18 | | 1 | Mo. | Tutorial | Python essentials |
19 | | 1 | We. | Lecture | Working with data |
20 | | 1 | We. | Tutorial | Matplotlib + Pandas + Numpy |
21 | | 1 | Fr. | Assigment | All of the above |
22 | | 2 | Mo. | Lecture | Introduction to stimulus presentation |
23 | | 2 | Mo. | Tutorial | PsychoPy Builder |
24 | | 2 | We. | - | No lecture! |
25 | | 2 | We. | Tutorial | PsychoPy Coder |
26 | | 2 | Fr. | Exam | Create a PsychoPy experiment from scratch! |
27 |
28 | Expect to spend about 20-40 hours per week on this course (as is expected for a four week, full-time 6 EC course), which includes watching the lecture, doing the tutorials (including exercises), and working on the assignments. The amount of time you need for this course depends, of course, on your previous experience with programming in general, and programming in Python specifically.
29 |
30 | ## Examination
31 | For students from the Research Master taking this course, there will be two graded assignments: one on Friday in week 1 and one on Friday in week 2 (but the latter might be postponed). The assignment in week 1 will involve a task in which you need to use your Python and Pandas skills to preprocess some data, perform several simple analyses, and use Matplotlib to visualize the results. This will be done in a Jupyter notebook on our Jupyterhub server. For the assignment in week 2, you'll have to program an experiment from scratch using the PsychoPy Coder interface.
32 |
33 | For both assignments, you have 3 hours to complete it. It's an "open-book" assignment, but you have to do it on your (i.e., no collaboration with your fellow students), and you'll have to be present on Zoom during those three hours. The assignments are based only on the material discussed in the tutorials; the material that is indicated to be *optional* won't be part of either of the assignments. About 80% of the assignment will be similar in difficulty as most exercises ("ToDos") in the tutorials, but about 20% of the assignment will feature substantially more difficult exercises (similar in difficulty, but not in content, to the optional exercises from the tutorials). In other words, if you complete all tutorials, getting an 8 (out of 10) for the assignments is definitely doable. But getting a(n even) better grade will be more challenging!
34 |
35 | ## Learning goals
36 | At the end of this course, you will ...
37 |
38 | * know the major differences between Python and R;
39 | * know the (dis)advantages of Python relative to other programming languages;
40 | * understand the concept of "object-oriented programming";
41 | * be able to create basic Python scripts;
42 | * be able to implement basic data processing operations and visualization using [*pandas*](https://pandas.pydata.org/) and [*matplotlib*](https://matplotlib.org/);
43 | * know the basics of stimulus presentation;
44 | * be able to implement simple experiments using the PsychoPy Builder and Coder interface.
45 |
46 | Importantly, this course focuses on the *basics* of Python and PsychoPy, but we have highlighted several resources that you may use to continue your Python/PsychoPy journey [here](week_2/psychopy_how_to_continue.md).
47 |
48 | ## Getting started
49 | Learn more about the course [here](getting_started/about.md) or [get started with the installation instructions](getting_started/installation.md).
50 |
51 | ## Buy me a coffee?
52 |
53 | Even though I have left academia, I keep maintaining this repository in my free time.
54 | If you appreciate these educational materials, you can say thanks by buying me a coffee! :smile:
55 |
56 | [](https://www.buymeacoffee.com/lukassnoeka)
57 |
--------------------------------------------------------------------------------
/intropy/misc/CONDUCT.md:
--------------------------------------------------------------------------------
1 |
2 | # Code of Conduct
3 |
4 | ## Our Pledge
5 |
6 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
7 |
8 | ## Our Standards
9 |
10 | Examples of behavior that contributes to creating a positive environment include:
11 |
12 | * Using welcoming and inclusive language
13 | * Being respectful of differing viewpoints and experiences
14 | * Gracefully accepting constructive criticism
15 | * Focusing on what is best for the community
16 | * Showing empathy towards other community members
17 |
18 | Examples of unacceptable behavior by participants include:
19 |
20 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
21 | * Trolling, insulting/derogatory comments, and personal or political attacks
22 | * Public or private harassment
23 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
24 | * Other conduct which could reasonably be considered inappropriate in a professional setting
25 |
26 | ## Our Responsibilities
27 |
28 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
29 |
30 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
31 |
32 | ## Scope
33 |
34 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
35 |
36 | ## Enforcement
37 |
38 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
39 |
40 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
41 |
42 | ## Attribution
43 |
44 | This Code of Conduct is adapted from the [Contributor Covenant, version 1.4](http://contributor-covenant.org/version/1/4).
45 |
--------------------------------------------------------------------------------
/intropy/misc/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcome, and they are greatly appreciated! Every little bit
4 | helps, and credit will always be given. You can contribute in the ways listed below.
5 |
6 | ## Report Bugs
7 |
8 | Report bugs using GitHub issues.
9 |
10 | If you are reporting a bug, please include:
11 |
12 | * Your operating system name and version.
13 | * Any details about your local setup that might be helpful in troubleshooting.
14 | * Detailed steps to reproduce the bug.
15 |
16 | ## Fix Bugs
17 |
18 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
19 | wanted" is open to whoever wants to implement it.
20 |
21 | ## Implement Features
22 |
23 | Look through the GitHub issues for features. Anything tagged with "enhancement"
24 | and "help wanted" is open to whoever wants to implement it.
25 |
26 | ## Write Documentation
27 |
28 | introPy could always use more documentation, whether as part of the
29 | official introPy docs, in docstrings, or even on the web in blog posts,
30 | articles, and such.
31 |
32 | ## Submit Feedback
33 |
34 | The best way to send feedback is to file an issue on GitHub.
35 |
36 | If you are proposing a feature:
37 |
38 | * Explain in detail how it would work.
39 | * Keep the scope as narrow as possible, to make it easier to implement.
40 | * Remember that this is a volunteer-driven project, and that contributions
41 | are welcome :)
42 |
43 | ## Get Started
44 |
45 | Ready to contribute? Here's how to set up `introPy` for local development.
46 |
47 | 1. Fork the repo on GitHub.
48 | 2. Clone your fork locally.
49 | 3. Install your local copy into a virtualenv, e.g., using `conda`.
50 | 4. Create a branch for local development and make changes locally.
51 | 5. Commit your changes and push your branch to GitHub.
52 | 6. Submit a pull request through the GitHub website.
53 |
54 | ## Code of Conduct
55 |
56 | Please note that the introPy project is released with a [Contributor Code of Conduct](CONDUCT.md). By contributing to this project you agree to abide by its terms.
57 |
--------------------------------------------------------------------------------
/intropy/misc/bibliography.md:
--------------------------------------------------------------------------------
1 | # Bibliography
2 |
3 | ```{bibliography} ../references.bib
4 | ```
--------------------------------------------------------------------------------
/intropy/misc/for_developers.md:
--------------------------------------------------------------------------------
1 | # For developers
2 | If you wish to contribute to the course materials, you can find some instructions below.
3 |
4 | ## Building the book
5 | To build the book, make sure you have the [jupyter book](https://jupyterbook.org) package installed. Then, run the following in the root of the repository:
6 |
7 | ```
8 | ./build_book
9 | ```
10 |
11 | Note that this does not work on Windows (Mac/Linux) only.
12 |
13 | ## Using `nbgrader`
14 | We use [nbgrader](https://nbgrader.readthedocs.io/en/stable/) to convert the *solution* notebooks (which contain the solutions to the exercises) to the *tutorial* notebooks (without the solutions). If you do this yourself, make sure you use the `nbgrader_config.py` file from this repository (because we use the directory names "solutions" and "tutorials" instead of "source" and "release").
15 |
16 | To regenerate the notebooks from week 1 (week 2 doesn't have any notebooks), run in the root of this repository the following command:
17 |
18 | ```
19 | nbgrader generate_assignment --force week_*
20 | ```
21 |
22 | ## Testing
23 | To test the notebooks, run the following (note: needs the packages `pytest` and `nbval`; Mac/Linux only):
24 |
25 | ```
26 | ./test_material
27 | ```
--------------------------------------------------------------------------------
/intropy/references.bib:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @article{peirce2019psychopy2,
5 | title={PsychoPy2: Experiments in behavior made easy},
6 | author={Peirce, Jonathan and Gray, Jeremy R and Simpson, Sol and MacAskill, Michael and H{\"o}chenberger, Richard and Sogo, Hiroyuki and Kastman, Erik and Lindel{\o}v, Jonas Kristoffer},
7 | journal={Behavior research methods},
8 | volume={51},
9 | number={1},
10 | pages={195--203},
11 | year={2019},
12 | publisher={Springer}
13 | }
14 |
15 | @inproceedings{kluyver2016jupyter,
16 | title={Jupyter Notebooks-a publishing format for reproducible computational workflows.},
17 | author={Kluyver, Thomas and Ragan-Kelley, Benjamin and P{\'e}rez, Fernando and Granger, Brian E and Bussonnier, Matthias and Frederic, Jonathan and Kelley, Kyle and Hamrick, Jessica B and Grout, Jason and Corlay, Sylvain and others},
18 | booktitle={ELPUB},
19 | pages={87--90},
20 | year={2016}
21 | }
22 |
23 | @inproceedings{hamrick2016creating,
24 | title={Creating and grading IPython/Jupyter notebook assignments with NbGrader},
25 | author={Hamrick, Jessica B},
26 | booktitle={Proceedings of the 47th ACM Technical Symposium on Computing Science Education},
27 | pages={242--242},
28 | year={2016}
29 | }
30 |
31 | @article{thaler2013best,
32 | title={What is the best fixation target? The effect of target shape on stability of fixational eye movements},
33 | author={Thaler, Lore and Schutz, Alexander C and Goodale, Melvyn A and Gegenfurtner, Karl R},
34 | journal={Vision research},
35 | volume={76},
36 | pages={31--42},
37 | year={2013},
38 | publisher={Elsevier}
39 | }
40 |
41 | @article{rouder2011measure,
42 | title={How to measure working memory capacity in the change detection paradigm},
43 | author={Rouder, Jeffrey N and Morey, Richard D and Morey, Candice C and Cowan, Nelson},
44 | journal={Psychonomic bulletin \& review},
45 | volume={18},
46 | number={2},
47 | pages={324--330},
48 | year={2011},
49 | publisher={Springer}
50 | }
--------------------------------------------------------------------------------
/intropy/solutions/week_1/example_data.csv:
--------------------------------------------------------------------------------
1 | participant_id,age,condition,wm_score
2 | sub-01,25,A,41
3 | sub-02,21,B,48
4 | sub-03,28,A,34
5 | sub-04,25,B,39
6 |
--------------------------------------------------------------------------------
/intropy/solutions/week_1/example_file.py:
--------------------------------------------------------------------------------
1 | # This is an example Python script
2 |
3 | message = "Hi, welcome to introPy!"
4 | print(message)
5 |
6 | # Script has ended!
--------------------------------------------------------------------------------
/intropy/solutions/week_1/example_module.py:
--------------------------------------------------------------------------------
1 | # An example module with a single function
2 | def average(arg1, arg2):
3 | """ Computes the average of two numbers. """
4 | result = (arg1 + arg2) / 2
5 | return result
--------------------------------------------------------------------------------
/intropy/solutions/week_1/example_script.py:
--------------------------------------------------------------------------------
1 | from example_module import average
2 |
3 | a = 5
4 | b = 10
5 |
6 | average_number = average(a, b)
7 | print(f"The average of {a} and {b} is {average_number}")
--------------------------------------------------------------------------------
/intropy/solutions/week_1/rhr_by_gender.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_1/rhr_by_gender.png
--------------------------------------------------------------------------------
/intropy/solutions/week_1/rhr_stratified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_1/rhr_stratified.png
--------------------------------------------------------------------------------
/intropy/solutions/week_1/solution_sine_wave_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_1/solution_sine_wave_plot.png
--------------------------------------------------------------------------------
/intropy/solutions/week_1/tests.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | def test_list_indexing(todo_list):
4 |
5 | try:
6 | assert(todo_list[2] == 'REPLACED')
7 | except AssertionError as e:
8 | print("The element 'TO_REPLACE_1' is not correctly replaced!")
9 | raise(e)
10 |
11 | try:
12 | assert(todo_list[-1][-1][-1] == 'REPLACED')
13 | except AssertionError as e:
14 | print("The element 'TO_REPLACE_2' is not correctly replaced!")
15 | raise(e)
16 |
17 | print('Well done!')
18 |
19 |
20 | def test_slicing_1(lst):
21 |
22 | c_answer = [2, 3, 4, 5, 6]
23 | try:
24 | assert(lst == c_answer)
25 | except AssertionError:
26 | print('The slice is incorrect!')
27 | raise IncorrectAnswer(lst, c_answer)
28 | else:
29 | print("Well done!")
30 |
31 |
32 | def test_slicing_2(lst):
33 |
34 | c_answer = [5, 7, 9, 11]
35 |
36 | try:
37 | assert(lst == c_answer)
38 | except AssertionError:
39 | print('The slice is incorrect!')
40 | raise IncorrectAnswer(lst, c_answer)
41 | else:
42 | print("Well done!")
43 |
44 |
45 | def test_create_array_with_zeros(arr):
46 |
47 | c_answer = np.zeros((2, 3, 5, 3, 7))
48 | try:
49 | assert(np.all(arr.shape == c_answer.shape))
50 | except AssertionError as e:
51 | print("Your array has the wrong shape, namely %r, but I expected %r" % (arr.shape, c_answer.shape,))
52 | raise(e)
53 |
54 | try:
55 | assert(np.all(arr == 0.0))
56 | except AssertionError as e:
57 | print("Your array does not contain zeros ... Did you use np.zeros()?")
58 | raise(e)
59 |
60 | print("Well done!")
61 |
62 |
63 | def test_fill_array_with_complement(arr):
64 |
65 | c_answer = 1.0 / np.arange(1, 9)
66 | try:
67 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
68 | except AssertionError as e:
69 | print("Your array (%r) does not match the correct answer (%r)!" % (arr, c_answer))
70 | raise(e)
71 | else:
72 | print("AWESOME!")
73 |
74 |
75 | def test_set_odd_indices_to_zero(arr):
76 |
77 | c_answer = np.arange(3, 25)
78 | c_answer[1::2] = 0.0
79 |
80 | try:
81 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
82 | except AssertionError as e:
83 | print("Your array (%r) does not match the correct answer (%r)!" % (arr, c_answer))
84 | raise(e)
85 | else:
86 | print("Good job!")
87 |
88 |
89 | def test_set_lower_right_value_to_one(arr):
90 |
91 | c_answer = np.zeros((3, 3))
92 | c_answer[-1, -1] = 1.0
93 |
94 | try:
95 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
96 | except AssertionError as e:
97 | print("Your array: \n\n%r\n\ndoes not match the correct answer:\n\n%r!" % (arr, c_answer))
98 | raise(e)
99 | else:
100 | print("Superb!")
101 |
102 |
103 | def test_bloodpressure_index(arr):
104 |
105 | np.random.seed(42)
106 | bp_data = np.random.normal(loc=100, scale=5, size=(20, 24, 30, 2))
107 | c_answer = bp_data[:, :, 17, 1]
108 |
109 | try:
110 | assert(arr.shape == (20, 24))
111 | except AssertionError as e:
112 | print("The result of your indexing operation is of shape %r, "
113 | "while it should be %r, namely 20 subjects by 24 hours" % (arr.shape, (20, 24)))
114 | raise(e)
115 |
116 | try:
117 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
118 | except AssertionError as e:
119 | print("Your answer is not correct! Did you perhaps forget that Python has zero-based indexing? (First index is 0!)")
120 | raise(e)
121 |
122 | print("You're incredible!")
123 |
124 |
125 | def test_boolean_indexing(arr):
126 |
127 | my_array = np.array([[0, 1, -1, -2],
128 | [2, -5, 1, 4],
129 | [10, -2, -4, 20]])
130 | c_answer = my_array[my_array ** 2 > 4]
131 |
132 | try:
133 | np.testing.assert_array_equal(arr, c_answer)
134 | except AssertionError as e:
135 | print("Incorrect answer! I expected %r, but I got %r" % (c_answer, arr))
136 | raise(e)
137 |
138 | print("EPIC!")
139 |
140 |
141 | def test_tvalue_computation(arr, h0, tval_ans):
142 |
143 | c_tval = (arr.mean() - h0) / (arr.std() / np.sqrt(arr.size - 1))
144 |
145 | try:
146 | np.testing.assert_almost_equal(tval_ans, c_tval)
147 | except AssertionError as e:
148 | print("T-value is incorrect! Your t-value is %.3f, while it should be %.3f" % (tval_ans, c_tval))
149 | raise(e)
150 |
151 | print("Correct! You stats wizard!")
152 |
153 |
154 | def test_array_product_and_sum(arr):
155 |
156 | arr_A = np.arange(10).reshape((5, 2))
157 | arr_B = np.arange(10, 20).reshape((5, 2))
158 | c_answer = (arr_A * arr_B) + 5
159 |
160 | try:
161 | np.testing.assert_array_equal(arr, c_answer)
162 | except AssertionError as e:
163 | print("Your answer is incorrect! I got:\n\n%r\n\nbut I expected:\n\n%r" % (arr, c_answer))
164 | raise(e)
165 | else:
166 | print("Great!")
167 |
168 |
169 | def test_compute_range_vectorized(arr, ans):
170 |
171 | c_answer = arr.max(axis=0) - arr.min(axis=0)
172 |
173 | try:
174 | assert(ans.shape == c_answer.shape)
175 | except AssertionError as e:
176 | print("The shape of your answer is incorrect! I got %r, "
177 | "but I expected %r for input-array of shape %r" % (ans.shape, c_answer.shape, arr.shape))
178 | raise(e)
179 |
180 | try:
181 | np.testing.assert_array_almost_equal(ans, c_answer, 4)
182 | except AssertionError as e:
183 | print("Your answer is incorrect! Your answer is:\n\n%r/n/n But I expected:\n\n%r" % (ans, c_answer))
184 | raise(e)
185 |
186 | print("Easy peasy!")
--------------------------------------------------------------------------------
/intropy/solutions/week_1/utils.py:
--------------------------------------------------------------------------------
1 | class Person:
2 | """ Example Person class.
3 |
4 | Parameters
5 | ----------
6 | name : str
7 | Name of the person
8 | age : int/float
9 | Age of the person
10 | """
11 | def __init__(self, name, age):
12 | """ Initializes a Person object. """
13 | self.name = name
14 | self.age = age
15 |
16 | def introduce(self):
17 | """ Introduces the Person object. """
18 | print(f"Hi, I am {self.name}!")
19 |
20 | def is_older_than_30(self):
21 | """ Checks whether the person is older than 30. """
22 | older = self.age >= 30
23 | return older
24 |
25 | def increase_age(self, nr):
26 | """ Increases the age of the Person object by 'nr'.
27 |
28 | Parameters
29 | ----------
30 | nr : int
31 | Number to increase age with.
32 | """
33 | self.age = self.age + nr
34 |
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Builder/conditions.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_2/Builder/conditions.xlsx
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Builder/stroop.psyexp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Builder/thank_you.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_2/Builder/thank_you.png
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Coder/angry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_2/Coder/angry.png
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Coder/emo_conditions.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_2/Coder/emo_conditions.xlsx
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Coder/emo_stroop.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | from psychopy.gui import DlgFromDict
3 | from psychopy.visual import Window, TextStim, ImageStim
4 | from psychopy.core import Clock, quit, wait
5 | from psychopy.event import Mouse
6 | from psychopy.hardware.keyboard import Keyboard
7 |
8 | ### DIALOG BOX ROUTINE ###
9 | exp_info = {'participant_nr': 99, 'age': ''}
10 | dlg = DlgFromDict(exp_info)
11 |
12 | # If pressed Cancel, abort!
13 | if not dlg.OK:
14 | quit()
15 | else:
16 | # Quit when either the participant nr or age is not filled in
17 | if not exp_info['participant_nr'] or not exp_info['age']:
18 | quit()
19 |
20 | # Also quit in case of invalid participant nr or age
21 | if exp_info['participant_nr'] > 99 or int(exp_info['age']) < 18:
22 | quit()
23 | else: # let's star the experiment!
24 | print(f"Started experiment for participant {exp_info['participant_nr']} "
25 | f"with age {exp_info['age']}.")
26 |
27 | # Initialize a fullscreen window with my monitor (HD format) size
28 | # and my monitor specification called "samsung" from the monitor center
29 | win = Window(size=(1920, 1080), fullscr=False, monitor='samsung')
30 |
31 | # Also initialize a mouse, although we're not going to use it
32 | mouse = Mouse(visible=False)
33 |
34 | # Initialize a (global) clock
35 | clock = Clock()
36 |
37 | # Initialize Keyboard
38 | kb = Keyboard()
39 | kb.clearEvents()
40 |
41 | ### START BODY OF EXPERIMENT ###
42 | #
43 | # This is where we'll add stuff from the second
44 | # Coder tutorial.
45 | #
46 | ### END BODY OF EXPERIMENT ###
47 |
48 | ### WELCOME ROUTINE ###
49 | # Create a welcome screen and show for 2 seconds
50 | welcome_txt_stim = TextStim(win, text="Welcome to this experiment!", color=(1, 0, -1), font='Calibri')
51 | welcome_txt_stim.draw()
52 | win.flip()
53 | wait(2)
54 |
55 | ### INSTRUCTION ROUTINE ###
56 | instruct_txt = """
57 | In this experiment, you will see emotional faces (either happy or angry) with a word above the image (either “happy” or “angry”).
58 |
59 | Importantly, you need to respond to the EXPRESSION of the face and ignore the word. You respond with the arrow keys:
60 |
61 | HAPPY expression = left
62 | ANGRY expression = right
63 |
64 | (Press ‘enter’ to start the experiment!)
65 | """
66 |
67 | # Show instructions and wait until response (return)
68 | instruct_txt = TextStim(win, instruct_txt, alignText='left', height=0.085)
69 | instruct_txt.draw()
70 | win.flip()
71 |
72 | # Initialize keyboard and wait for response
73 | kb = Keyboard()
74 | while True:
75 | keys = kb.getKeys()
76 | if 'return' in keys:
77 | # The for loop was optional
78 | for key in keys:
79 | print(f"The {key.name} key was pressed within {key.rt:.3f} seconds for a total of {key.duration:.3f} seconds.")
80 | break # break out of the loop!
81 |
82 | ### TRIAL LOOP ROUTINE ###
83 | # Read in conditions file
84 | cond_df = pd.read_excel('emo_conditions.xlsx')
85 | cond_df = cond_df.sample(frac=1)
86 |
87 | # Create fixation target (a plus sign)
88 | fix_target = TextStim(win, '+')
89 | trial_clock = Clock()
90 |
91 | # START exp clock
92 | clock.reset()
93 |
94 | # Show initial fixation
95 | fix_target.draw()
96 | win.flip()
97 | wait(1)
98 |
99 | for idx, row in cond_df.iterrows():
100 | # Extract current word and smiley
101 | curr_word = row['word']
102 | curr_smil = row['smiley']
103 |
104 | # Create and draw text/img
105 | stim_txt = TextStim(win, curr_word, pos=(0, 0.3))
106 | stim_img = ImageStim(win, curr_smil + '.png', )
107 | stim_img.size *= 0.5 # make a bit smaller
108 |
109 | # Initially, onset is undefined
110 | cond_df.loc[idx, 'onset'] = -1
111 |
112 | trial_clock.reset()
113 | kb.clock.reset()
114 | while trial_clock.getTime() < 2:
115 | # Draw stuff
116 |
117 | if trial_clock.getTime() < 0.5:
118 | stim_txt.draw()
119 | stim_img.draw()
120 | else:
121 | fix_target.draw()
122 |
123 | win.flip()
124 | if cond_df.loc[idx, 'onset'] == -1:
125 | cond_df.loc[idx, 'onset'] = clock.getTime()
126 |
127 | # Get responses
128 | resp = kb.getKeys()
129 | if resp:
130 | # Stop the experiment when 'q' is pressed
131 | if 'q' in resp:
132 | quit()
133 |
134 | # Log reaction time and response
135 | cond_df.loc[idx, 'rt'] = resp[-1].rt
136 | cond_df.loc[idx, 'resp'] = resp[-1].name
137 |
138 | # Log correct/incorrect
139 | if resp[-1].name == 'left' and curr_smil == 'happy':
140 | cond_df.loc[idx, 'correct'] = 1
141 | elif resp[-1].name == 'right' and curr_smil == 'angry':
142 | cond_df.loc[idx, 'correct'] = 1
143 | else:
144 | cond_df.loc[idx, 'correct'] = 0
145 |
146 | effect = cond_df.groupby('congruence').mean()
147 | rt_con = effect.loc['congruent', 'rt']
148 | rt_incon = effect.loc['incongruent', 'rt']
149 | acc = cond_df['correct'].mean()
150 |
151 | txt = f"""
152 | Your reaction times are as follows:
153 |
154 | Congruent: {rt_con:.3f}
155 | Incongruent: {rt_incon:.3f}
156 |
157 | Overall accuracy: {acc:.3f}
158 | """
159 | result = TextStim(win, txt)
160 | result.draw()
161 | win.flip()
162 | wait(5)
163 |
164 | cond_df.to_csv(f"sub-{exp_info['participant_nr']}_results.csv")
165 |
166 | # Finish experiment by closing window and quitting
167 | win.close()
168 | quit()
--------------------------------------------------------------------------------
/intropy/solutions/week_2/Coder/happy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/solutions/week_2/Coder/happy.png
--------------------------------------------------------------------------------
/intropy/tutorials/extra_exercises/rhr_by_gender.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/extra_exercises/rhr_by_gender.png
--------------------------------------------------------------------------------
/intropy/tutorials/extra_exercises/rhr_stratified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/extra_exercises/rhr_stratified.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/example_data.csv:
--------------------------------------------------------------------------------
1 | participant_id,age,condition,wm_score
2 | sub-01,25,A,41
3 | sub-02,21,B,48
4 | sub-03,28,A,34
5 | sub-04,25,B,39
6 |
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/example_file.py:
--------------------------------------------------------------------------------
1 | # This is an example Python script
2 |
3 | message = "Hi, welcome to introPy!"
4 | print(message)
5 |
6 | # Script has ended!
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/example_module.py:
--------------------------------------------------------------------------------
1 | # An example module with a single function
2 | def average(arg1, arg2):
3 | """ Computes the average of two numbers. """
4 | result = (arg1 + arg2) / 2
5 | return result
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/example_script.py:
--------------------------------------------------------------------------------
1 | from example_module import average
2 |
3 | a = 5
4 | b = 10
5 |
6 | average_number = average(a, b)
7 | print(f"The average of {a} and {b} is {average_number}")
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/solution_sine_wave_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_1/solution_sine_wave_plot.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/tests.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | def test_list_indexing(todo_list):
4 |
5 | try:
6 | assert(todo_list[2] == 'REPLACED')
7 | except AssertionError as e:
8 | print("The element 'TO_REPLACE_1' is not correctly replaced!")
9 | raise(e)
10 |
11 | try:
12 | assert(todo_list[-1][-1][-1] == 'REPLACED')
13 | except AssertionError as e:
14 | print("The element 'TO_REPLACE_2' is not correctly replaced!")
15 | raise(e)
16 |
17 | print('Well done!')
18 |
19 |
20 | def test_slicing_1(lst):
21 |
22 | c_answer = [2, 3, 4, 5, 6]
23 | try:
24 | assert(lst == c_answer)
25 | except AssertionError:
26 | print('The slice is incorrect!')
27 | raise IncorrectAnswer(lst, c_answer)
28 | else:
29 | print("Well done!")
30 |
31 |
32 | def test_slicing_2(lst):
33 |
34 | c_answer = [5, 7, 9, 11]
35 |
36 | try:
37 | assert(lst == c_answer)
38 | except AssertionError:
39 | print('The slice is incorrect!')
40 | raise IncorrectAnswer(lst, c_answer)
41 | else:
42 | print("Well done!")
43 |
44 |
45 | def test_create_array_with_zeros(arr):
46 |
47 | c_answer = np.zeros((2, 3, 5, 3, 7))
48 | try:
49 | assert(np.all(arr.shape == c_answer.shape))
50 | except AssertionError as e:
51 | print("Your array has the wrong shape, namely %r, but I expected %r" % (arr.shape, c_answer.shape,))
52 | raise(e)
53 |
54 | try:
55 | assert(np.all(arr == 0.0))
56 | except AssertionError as e:
57 | print("Your array does not contain zeros ... Did you use np.zeros()?")
58 | raise(e)
59 |
60 | print("Well done!")
61 |
62 |
63 | def test_fill_array_with_complement(arr):
64 |
65 | c_answer = 1.0 / np.arange(1, 9)
66 | try:
67 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
68 | except AssertionError as e:
69 | print("Your array (%r) does not match the correct answer (%r)!" % (arr, c_answer))
70 | raise(e)
71 | else:
72 | print("AWESOME!")
73 |
74 |
75 | def test_set_odd_indices_to_zero(arr):
76 |
77 | c_answer = np.arange(3, 25)
78 | c_answer[1::2] = 0.0
79 |
80 | try:
81 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
82 | except AssertionError as e:
83 | print("Your array (%r) does not match the correct answer (%r)!" % (arr, c_answer))
84 | raise(e)
85 | else:
86 | print("Good job!")
87 |
88 |
89 | def test_set_lower_right_value_to_one(arr):
90 |
91 | c_answer = np.zeros((3, 3))
92 | c_answer[-1, -1] = 1.0
93 |
94 | try:
95 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
96 | except AssertionError as e:
97 | print("Your array: \n\n%r\n\ndoes not match the correct answer:\n\n%r!" % (arr, c_answer))
98 | raise(e)
99 | else:
100 | print("Superb!")
101 |
102 |
103 | def test_bloodpressure_index(arr):
104 |
105 | np.random.seed(42)
106 | bp_data = np.random.normal(loc=100, scale=5, size=(20, 24, 30, 2))
107 | c_answer = bp_data[:, :, 17, 1]
108 |
109 | try:
110 | assert(arr.shape == (20, 24))
111 | except AssertionError as e:
112 | print("The result of your indexing operation is of shape %r, "
113 | "while it should be %r, namely 20 subjects by 24 hours" % (arr.shape, (20, 24)))
114 | raise(e)
115 |
116 | try:
117 | np.testing.assert_array_almost_equal(arr, c_answer, 4)
118 | except AssertionError as e:
119 | print("Your answer is not correct! Did you perhaps forget that Python has zero-based indexing? (First index is 0!)")
120 | raise(e)
121 |
122 | print("You're incredible!")
123 |
124 |
125 | def test_boolean_indexing(arr):
126 |
127 | my_array = np.array([[0, 1, -1, -2],
128 | [2, -5, 1, 4],
129 | [10, -2, -4, 20]])
130 | c_answer = my_array[my_array ** 2 > 4]
131 |
132 | try:
133 | np.testing.assert_array_equal(arr, c_answer)
134 | except AssertionError as e:
135 | print("Incorrect answer! I expected %r, but I got %r" % (c_answer, arr))
136 | raise(e)
137 |
138 | print("EPIC!")
139 |
140 |
141 | def test_tvalue_computation(arr, h0, tval_ans):
142 |
143 | c_tval = (arr.mean() - h0) / (arr.std() / np.sqrt(arr.size - 1))
144 |
145 | try:
146 | np.testing.assert_almost_equal(tval_ans, c_tval)
147 | except AssertionError as e:
148 | print("T-value is incorrect! Your t-value is %.3f, while it should be %.3f" % (tval_ans, c_tval))
149 | raise(e)
150 |
151 | print("Correct! You stats wizard!")
152 |
153 |
154 | def test_array_product_and_sum(arr):
155 |
156 | arr_A = np.arange(10).reshape((5, 2))
157 | arr_B = np.arange(10, 20).reshape((5, 2))
158 | c_answer = (arr_A * arr_B) + 5
159 |
160 | try:
161 | np.testing.assert_array_equal(arr, c_answer)
162 | except AssertionError as e:
163 | print("Your answer is incorrect! I got:\n\n%r\n\nbut I expected:\n\n%r" % (arr, c_answer))
164 | raise(e)
165 | else:
166 | print("Great!")
167 |
168 |
169 | def test_compute_range_vectorized(arr, ans):
170 |
171 | c_answer = arr.max(axis=0) - arr.min(axis=0)
172 |
173 | try:
174 | assert(ans.shape == c_answer.shape)
175 | except AssertionError as e:
176 | print("The shape of your answer is incorrect! I got %r, "
177 | "but I expected %r for input-array of shape %r" % (ans.shape, c_answer.shape, arr.shape))
178 | raise(e)
179 |
180 | try:
181 | np.testing.assert_array_almost_equal(ans, c_answer, 4)
182 | except AssertionError as e:
183 | print("Your answer is incorrect! Your answer is:\n\n%r/n/n But I expected:\n\n%r" % (ans, c_answer))
184 | raise(e)
185 |
186 | print("Easy peasy!")
--------------------------------------------------------------------------------
/intropy/tutorials/week_1/utils.py:
--------------------------------------------------------------------------------
1 | class Person:
2 | """ Example Person class.
3 |
4 | Parameters
5 | ----------
6 | name : str
7 | Name of the person
8 | age : int/float
9 | Age of the person
10 | """
11 | def __init__(self, name, age):
12 | """ Initializes a Person object. """
13 | self.name = name
14 | self.age = age
15 |
16 | def introduce(self):
17 | """ Introduces the Person object. """
18 | print(f"Hi, I am {self.name}!")
19 |
20 | def is_older_than_30(self):
21 | """ Checks whether the person is older than 30. """
22 | older = self.age >= 30
23 | return older
24 |
25 | def increase_age(self, nr):
26 | """ Increases the age of the Person object by 'nr'.
27 |
28 | Parameters
29 | ----------
30 | nr : int
31 | Number to increase age with.
32 | """
33 | self.age = self.age + nr
34 |
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/Builder/thank_you.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/Builder/thank_you.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/Coder/angry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/Coder/angry.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/Coder/happy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/Coder/happy.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/Matlab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/Matlab.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/Python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/Python.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/R.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/tutorials/week_2/R.png
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/intropy_demo.psyexp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
--------------------------------------------------------------------------------
/intropy/tutorials/week_2/stimuli.csv:
--------------------------------------------------------------------------------
1 | image
2 | Python.png
3 | R.png
4 | Matlab.png
5 |
--------------------------------------------------------------------------------
/intropy/week_1/gradebook.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukassnoek/introPy/3df98e53810a96bbdd6ac91d0aa35ef2fb3295ef/intropy/week_1/gradebook.db
--------------------------------------------------------------------------------
/intropy/week_1/python.md:
--------------------------------------------------------------------------------
1 | # Python essentials
2 | In this week, we will cover the essentials of Python.
3 |
4 | ## Lecture slides
5 | Note that some information in these lecture slides only apply to students from the Research Master Psychology taking the "Programming for Psychological Science" course.
6 |
7 |
8 |
9 | ## Tutorials
10 | Note that all tutorial from this week are written in Jupyter notebooks, which are meant to be used interactively. Run them online using Binder or Jupyterhub, or run them on your own computer using your own Python installation. Note that students from the Research Master are recommended to work on the UvA JupyterHub.
11 |
12 | The first two tutorials (*Introduction to Python* and *Python basics*) will introduce you to the basics of Jupyter notebooks, Python syntax, and the concept of object-oriented programming. The next three notebooks will discuss plotting using the package [matplotlib](https://matplotlib.org/) (*Introduction to Matplotlib*), working with tabular data using [pandas](https://pandas.pydata.org/) (*Introduction to Pandas*), and working with array data using [numpy](https://numpy.org/) (*Introduction to Numpy*).
13 |
14 | The *numpy* tutorial is **optional** (i.e., its contents won't be featured on the exam/assignments), but highly recommended for those wanting to develop more advanced data analysis skills (which are useful for, e.g., machine learning and neuroimaging research). Also, if you want some extra exercises to practice with basic Python functionality, Pandas, and Matplotlib, we recommend going through the *Extra exercises* notebook!
15 |
16 | :::{tip}
17 | The solutions to the tutorial exercises ("ToDos") are actually embedded in the tutorial pages on this website, but hidden by default. Click on the plus symbol next to the "Click to show" text to reveal the cell with the solution!
18 | :::
19 |
20 | Let's start with [the first Python tutorial](../solutions/week_1/0_introduction.ipynb)!
21 |
--------------------------------------------------------------------------------
/intropy/week_1/python_how_to_continue.md:
--------------------------------------------------------------------------------
1 | # How to continue with Python?
2 | After going through all tutorial from week 1, you should know the basics of Python and how to leverage it for data preprocessing, analysis, and visualization! There is, of course, much more to learn about Python. What about [creating your own Python packages](https://packaging.python.org/)? Or using one of the many [excellent machine learning libraries](https://www.geeksforgeeks.org/best-python-libraries-for-machine-learning/) in Python? Or [building websites in Python](https://flask.palletsprojects.com)?
3 |
4 | [This article](https://www.apa.org/science/about/psa/2019/07/python-research) on the APA blog outlines some excellent places to continue your Python journey. There are also plenty of books about learning Python, nicely summarized [here](https://realpython.com/best-python-books/). Personally, I also find the articles on [Real Python](https://realpython.com/) very insightful. If you're more a hands-on type, there are many online Python courses available, such as the [Python specialization](https://www.coursera.org/specializations/python) on Coursera. Note that most of the online courses on machine learning also use Python (such as [machine learning specialization](https://www.coursera.org/specializations/machine-learning) on Coursera), which may also be a nice way to develop your Python skills further. Note that, as a student, you may be eligible for [financial aid](https://learner.coursera.help/hc/en-us/articles/209819033-Apply-for-Financial-Aid-or-a-Scholarship) for Coursera courses.
5 |
6 | Finally, probably the best way to get better at Python is *to actually use it in a project*! So, whenever you have to program an experiment, analyse some data, or create a plot, consider using Python!
7 |
8 |
--------------------------------------------------------------------------------
/intropy/week_2/builder_test.md:
--------------------------------------------------------------------------------
1 | # Test your Builder skills!
2 | By now, you should be able to create a simple experiment using the PsychoPy Builder interface! In the tutorials, we guided you through the process of building a Builder experiment from beginning to end. If you want to test your skills, try to recreate the Lexican Decision Task
3 |
4 | Start the Lexical Decision Task
5 |
6 |
7 | Try to include the following:
8 |
9 | * A dialog box asked for the participant ID and age of the participant
10 | * Note: you don't have to recreate the "Field marked with an asterisk (*) are required" text
11 | * A welcome screen with text
12 | * An instruction screen, which continues upon a button press by the participant
13 | * A loop with trials including a fixation target, the stimulus, and feedback (text showing "correct", "incorrect", or "missed")
14 | * Create the stimuli (real words, fake words) yourself
15 | * Make sure that the trial conditions (real word, fake word) are presented randomly
16 | * A "goodbye" screen, thanking the participant for their contribution
--------------------------------------------------------------------------------
/intropy/week_2/coder_test.md:
--------------------------------------------------------------------------------
1 | # Test your Coder skills!
2 | By now, you know the basics of creating experiments in the PsychoPy Coder! If you want to test your Coder skills, you can try to recreate the Lexical Decision Task like you did with the Builder before!
3 |
4 | To refresh your memory, run the Lexical Decision task by clicking on the button below.
5 |
6 | Start the Lexical Decision Task
7 |
8 |
9 | Try to include the following:
10 |
11 | * A dialog box asked for the participant ID and age of the participant
12 | * Note: you don't have to recreate the "Field marked with an asterisk (*) are required" text
13 | * A welcome screen with text
14 | * An instruction screen, which continues upon a button press by the participant
15 | * A loop with trials including a fixation target, the stimulus, and feedback (text showing "correct", "incorrect", or "missed")
16 | * Create the stimuli (real words, fake words) yourself
17 | * Make sure that the trial conditions (real word, fake word) are presented randomly
18 | * Make sure the responses (left/right) and reaction time per trial are stored in a Pandas DataFrame
19 | * A "goodbye" screen, thanking the participant for their contribution
20 | * Make sure to save the Pandas DataFrame to disk using a sensible filename
21 | * Include the participant ID in the filename
22 | * Make sure the file contains, per trial, the condition (real/fake), response (right, left), and reaction time (in seconds)
--------------------------------------------------------------------------------
/intropy/week_2/intro_psychopy.md:
--------------------------------------------------------------------------------
1 | # Introduction to PsychoPy (tutorial)
2 | PsychoPy is currently the most used and complete Python package to create experiments. Before we will explain how to use it, please read the [overview](https://www.psychopy.org/about/overview.html) on the PsychoPy website.
3 |
4 | Now, let's familiarize ourselves with PsychoPy. Let's start by opening PsychoPy! After opening, you'll see a "Tip of the Day" pop-up; you may ignore that for now and close it.
5 |
6 | :::{warning}
7 | On Mac, PsychoPy might not open right after starting it. In that case, clicking on the icon again seems to work.
8 | :::
9 |
10 | ## Subwindows
11 | Psychopy by default opens three subwindows: the *PsychoPy Builder*, the *PsychoPy Coder*, and the *Experiment runner*. The *Builder* is the graphical interface of PsychoPy, which you can use to create experiments without any code, whereas the *Coder* interface provides an editor in which you can program experiments using Python code (as provided by the PsychoPy package). The *Experiment runner* is a tool to create complex *sets* of experiments/tasks (e.g., a battery of different tasks or questionnaires). It also provides a "log" of whatever is happening in your experiment when you run it. In this tutorial, we will only discuss some general PsychoPy features, for which the *Builder* interface suffices, so you may close the *Coder* interface and the *Experiment runner* for now.
12 |
13 | To read more about the different interfaces, read the [Getting started](https://www.psychopy.org/gettingStarted.html) page on the PsychoPy website.
14 |
15 | :::{note}
16 | In this course's PsychoPy tutorials, we'll often refer to the PsychoPy documentation. This is not because we're too lazy to explain it ourselves. We do this because looking up and reading code/package documentation is an essential programming skill! Even experienced programmers (like your teachers) have to look up things in the documentation *all the time*.
17 | :::
18 |
19 | ## Running an experiment
20 | To get an idea what a PsychoPy experiment may look like, let's run a demo! We created a super simple demo that showcases some of the functionality of PsychoPy, which can be found in the materials: `tutorials/week_2/intropy_demo.psyexp`. In the next tutorial, we are going to discuss this in more detail. For now, run the demo by doing the following:
21 |
22 | * Open the `intropy_demo.psyexp` file (File → Open);
23 | * Then, click the large green "play" button (►) to start the experiment;
24 | * This will open the *Experiment runner* and, after a couple of seconds, a new window;
25 |
26 | :::{warning}
27 | Currently, running experiments when PsychoPy is full screen doesn't (always) work... So make sure it's *not* full screen when you run the demo (or any experiment, really).
28 | :::
29 |
30 | After the experiment has finished, the experiment window closes automatically. In the *Experiment runner*, you see some information about the experiment (but nothing super interesting). Mac users may see some text mentioning "ApplePersistenceIgnoreState"; this is a harmless warning (not an error) and can be ignored. You may close the *Experiment runner* for now.
31 |
32 | :::{tip}
33 | Want to quit an experiment before it has finished? Press the escape key! In most experiments, this will abort the experiment.
34 | :::
35 |
36 | ## Global preferences
37 | PsychoPy as a lot of global settings, which you can view and change if you want. You can open the *PsychoPy Preferences* window by clicking on *PsychoPy* in the top-most menu bar and then on *Preferences*. Any changes you make here should be applied to future sessions. For now, no need to change any global preferences.
38 |
39 | ## Experiment settings (Builder only)
40 | When you are using the *Builder* interface, you can set several global settings in the *Experimental settings* window. To open this window, click on the gear icon (⚙). In the various tabs, you can edit the experiment's settings. For example, under the "Basic" tab, you can edit the "info dialog": a pop-up that asks the participant for some information. Which information is asked can be changed at the "Experimental info" line.
41 |
42 | :::{admonition} ToDo
43 | :class: attention
44 | Enable the info dialog by clicking the checkbox next to "Show info dialog" and add a new field, "age", to the info dialog (without a default value). Then, run the demo experiment again (press the escape key to quit). Just before the experiment window opens, you should see the info dialog pop-up!
45 | :::
46 |
47 | Under the "Data" tab, there are various options to fine-tune how you want your experimental data to be saved. Next to "Data filename", you can specify the filename of the datafiles that will be saved. By default, a new directory, `data`, is created in which the files will be saved. In our demo experiment, we furthermore specified that the filename should be `sub-%s_%s'`, in which the format specifiers (`%s`) are replaced by the participant identifier (`expInfo['participant']`) and experiment name (`expInfo['expName']`). Here, `expInfo`, refers to a Python variable (a dictionary) that represents the info dialog pop-up (plus some additional information). This way, you can customize your output filenames according to the information provided by the participant!
48 |
49 | :::{admonition} ToDo (optional)
50 | :class: attention
51 | Assuming you added the "age" field to the info dialog earlier, try to add the participant's age to the output filename such that if, for example, participant 01 who is 29 years old does the experiment, the output filename will be `sub-01_age-29_intropy_demo` (+ extension). If you're feeling adventurous, try using F-strings instead of format specifiers!
52 | :::
53 |
54 | In addition to the mandatory "psydat" file (which we personally never used), you can also have Psychopy save an extensive log file and CSV files. We recommend always saving the log and the "trial-by-trial" CSV files.
55 |
56 | Under the "Audio" tab, you can specify which soundlibrary Psychopy should use. Currently, Psychopy advises to use the Psychtoolbox (ptb) soundlibrary. The "Online" tab contains various settings to export your experiment to a format that can be used online (only applicable to *Builder* experiments), but this is beyond the scope of this course.
57 |
58 | Finally, the "Screen" tab contains several important settings that specify the experiment window. The "Screen" option (default: 1), for example, specifies on which screen the experiment should run in case of multiple monitor set-ups. You can also choose to run the experiment full screen (the default) or whether to specify a particular window size (in pixels) and the background color used in the window ("Color") and the colorspace used through the experiment ("Color space"). The standard background color is `[0, 0, 0]` in RGB space, where the first value specifies the amount of **R**ed, the second value the amount of **G**reen, and the third value the amount of **B**lue. These values can range from -1 (minimum amount) to 1 (maximum amount). The color `[0, 0, 0]` specifies gray (as you've seen in the demo). You can read more about PsychoPy's color spaces [here](https://psychopy.org/general/colours.html). Another important setting is the "Units" that Psychopy should use.
59 |
60 | :::{admonition} ToDo
61 | :class: attention
62 | Please read the excellent explanation of the different settings for the "Units" on the [PsychoPy website](https://www.psychopy.org/general/units.html). To see the effect of a different unit for size, change "Units" from "height" to, e.g., "pixels" and run the demo experiment again.
63 | :::
64 |
65 | Another important setting is the *Monitor*. Here, you need to fill in the name of the specific monitor configuration you want to use in your experiment. How to create a monitor configuration is explained in the next section!
66 |
67 | ## Monitors
68 | Another important element of each experiment, both in the *Coder* and *Builder* interface, is the monitor that it is displayed on. In Psychopy's [*Monitor Center*](https://www.psychopy.org/general/monitors.html), you can specify several properties of the monitor(s) that you intend to use for your experiment. Although it is not strictly necessary to specify a monitor for your experiment (if you don't, PsychoPy will use a default configuration), it is a prerequisite for some "Units" settings (such as *degree visual angle*)! If possible, we recommend always specifying a monitor.
69 |
70 | To open the *Monitor Center*, click on the monitor icon ( ). You should see the default monitor `testMonitor`, which is, as the notes say, a "default (not very useful) monitor." To create a new monitor, click *New* and give your new monitor a name (e.g., "laptop"). Then, you can specify several properties of your monitor. For example, you can specify the number of pixels of your monitor (e.g., 1920×1080 for a full HD screen), which is important if you use the "pixel" setting under "Units". You can also set the screen distance, i.e., how far participants are seated from the monitor (important when stimuli are specified in [degrees visual angle](https://en.wikipedia.org/wiki/Visual_angle)) and the screen width.
71 |
72 | Note that it is also possible to run a calibration procedure in the monitor center and to add the procedure's results to your monitor configuration. Such a calibration procedure makes sure your monitor displays colors as specified in your experiment. This procedure, however, needs specialized equipment (a photometer), which you most likely do not have at home, so you may ignore this for now.
73 |
74 | :::{admonition} ToDo
75 | :class: attention
76 | Create a new monitor specific to your own laptop/desktop monitor. Fill in your current screen distance, screen size, and screen width. When you're done, click *Save*. Set in the *Experiment settings* the "Units" to "deg" (visual degree angle) and run the demo experiment. Then, change the screen distance to 200 cm and run the demo experiment again. You should see that the size of the stimuli appears smaller on the screen.
77 | :::
78 |
79 | Alright, by now you know your way around PsychoPy, so you're ready to start with the [Builder interface](psychopy_builder_part1.md)!
80 |
--------------------------------------------------------------------------------
/intropy/week_2/psychopy.md:
--------------------------------------------------------------------------------
1 | # PsychoPy
2 | In this week, we will cover the essentials of [PsychoPy](https://www.psychopy.org/). The lecture will give an introduction to stimulus presentation. The following tutorials wills give an introduction to the PsychoPy software package (*Introduction to Psychopy*), discuss its *Builder* interface (*Introduction to the Builder* and *A Builder experiment from scratch*), and its *Coder* interface (*Introduction to the Coder* and *A Coder experiment from scratch*).
3 |
4 | ## Lecture slides
5 |
6 |
7 | ## Tutorials
8 | Unlike the tutorials in week 1, this week's tutorials are not written in Jupyter Notebooks, but are just embedded as pages with instructions on this website. Please go through them in order (see the table of contents on the left side of this page).
9 |
10 | That said, let's start with [the first PsychoPy tutorial](intro_psychopy.md)!
--------------------------------------------------------------------------------
/intropy/week_2/psychopy_builder_part1.md:
--------------------------------------------------------------------------------
1 | # Introduction to the PsychoPy Builder (tutorial)
2 | In this tutorial, we will discuss and show you how to use the *Builder* interface of PsychoPy. We will explain the basic elements of the Builder interface so that, in the next tutorial, we can focus more on the implementational details by building a new experiment from scratch.
3 |
4 | You might think, "Why learn how to use a graphical interface in a programming course?" The reason we first teach you how to use the *Builder* interface is because it allows us to focus on the structure of experiments before elaborating on the underlying code. Another advantage of Builder experiments is that they can be used online! (But this is beyond the scope of this course.)
5 |
6 | :::{admonition} ToDo
7 | :class: attention
8 | Read [this page](https://workshops.psychopy.org/3days/10introductions.html) which discusses the respective advantages of the Builder and Coder interface in more detail.
9 | :::
10 |
11 | ## Builder vs. Coder
12 | As discussed before, the Builder and Coder interfaces can both be used to create experiments. Whereas the Builder allows you create experiments graphically, the Coder allows you to program your experiment directly in Python. There are merits to both interfaces: the Builder interface allows you to quickly prototype and develop experiments, which can be run online with a single click, while the Coder interface offers immense flexibility and opportunity to harnass the power and versatility of Python (and Python packages)!
13 |
14 | It is important to realize, though, that when PsychoPy runs Builder experiments, it actually first generates (or "compiles") the experiment as a Python script (as if you created it using the Coder)!
15 |
16 | :::{admonition} ToDo
17 | :class: attention
18 | Let's see this Builder-to-Coder compilation in action. If you haven't loaded the demo Builder experiment (`intropy_demo.psyexp`), do so now. Then, click the *Compile to script* button (right of the *Edit experiment settings* button). This should open the *Coder* interface with the code equivalent of the demo Builder experiment!
19 | :::
20 |
21 | The generated `intropy_demo.py` script contains the code necessary to run the experiment originally specified in the Builder interface (i.e., in the `intropy_demo.psyexp` file). In fact, everytime your run a Builder experiment on your own computer, Psychopy first generates the corresponding Python script, which is then executed to start the experiment.
22 |
23 | Most of the time, you can ignore the script associated with your Builder experiment. It may, however, give you some insight about what is going on "under the hood". Take a look at the generated script; do you see elements from the demo experiment (e.g., the text or images shown during the demo experiment)?
24 |
25 | ## Elements of the Builder interface
26 | Now, let's take a look at the elements of the Builder interface. Make sure you (still) have the demo experiment active in the Builder. Apart from the list of icons on top of the Builder window, there are several subwindows (or panes): the *Routines* pane, the *Components* pane, and the *Flow* pane. We'll discuss these in turn.
27 |
28 | ### The routines pane
29 | The [*Routines* pane](https://www.psychopy.org/builder/routines.html
30 | ) consist of the different elements of your experiment, where each element gets its own tab. In the demo experiment, for example, there are four routines: *intro*, *show_stimulus*, *gabor*, and *wrap_up*. Each routine may consist of multiple components (e.g., text, images, and sounds). For example, if you click on the *intro* routine tab, the routine pane shows, across different "rows", that this routine consists of three consecutive text components (*hello*, *welcome*, and *wait_key*) and a "keyboard" component (*key_resp*). Moreover, the routine pane also shows you the onset and offsets of the different components. Note that routines do not *have to* contain multiple components; for example, the *show_stimulus* routine only contains a single component (i.e., *stim*). It's up to you how you how you structure your routines!
31 |
32 | :::{admonition} ToThink
33 | :class: attention
34 | In the *intro* routine, the *wait_key* and *key_resp* components seem to lack an explicit offset. Considering the demo experiment, do you understand why?
35 | :::
36 |
37 | ### The components pane
38 | The [*components* pane](https://www.psychopy.org/builder/components.html
39 | ) contains, as you might have guessed, the different components you can include in your routines. Some of the most used components are listed under *favorites* (such as *text* and *image* components). The *stimuli* section contains various different stimulus components you might want to use in your experiment, such as [dot stimuli](https://www.psychopy.org/builder/components/dots.html), [gratings](https://www.psychopy.org/builder/components/grating.html), and [sounds](https://www.psychopy.org/builder/components/sound.html). The *responses* section contains several components that facilitate interaction with the participant. For example, the [mouse component](https://www.psychopy.org/builder/components/mouse.html) allows you to record and use mouse movements and clicks and the [rating scale component](https://www.psychopy.org/builder/components/ratingscale.html) creates a rating scale which you can use to collect ratings on, for example, questionnaire items.
40 |
41 | By clicking on a particular component, a pop-up appears in which you can set the *properties* of the component, such as the component name, onset and and duration, and several component-specific properties. For example, if you click on a *text* component, you can set the color, font, font size ("letter height"), position, and of course the text itself.
42 |
43 | :::{tip}
44 | In the properties window, if you hover your cursor over the different options, you see a little window with an explanation of that option! Also, the PsychoPy documentation contains detailed information about each component. The easiest way to find the appropriate page is, in my experience, just googling "psychopy component {component name}".
45 | :::
46 |
47 | In the properties window, if you click the "OK" button, PsychoPy will add this component to the currently active routine. If you want, you can still change the properties afterwards. We will discuss setting component properties in more detail in the next tutorial!
48 |
49 | :::{admonition} ToDo (optional)
50 | :class: attention
51 | Try adding another *text* component with the text "The end!" to the *wrap_up* routine. Make sure it immediately starts after the *goodbye* component and it lasts one second. Run the experiment to see whether it worked!
52 | :::
53 |
54 | ### The flow pane
55 | Finally, the [*flow* pane](https://www.psychopy.org/builder/flow.html) shows and defines the order of your experiment's routines. In the demo experiment, for example, the flow pane shows that the experiment starts with the *intro* routine, followed by the *show_stimulus* routine, and finally the *gabor* and *wrap_up* routines. The colors of the routines in the flow pane indicate whether the routines has a known and exact duration (green) or not (blue or red). For experiments in which precision of onsets/offsets is not crucial, this is not really important. But in experiments in which you want to be sure your routines' onsets, offsets, and durations are precise (i.e., [non-slip timing](https://www.psychopy.org/general/timing/nonSlipTiming.html) in PsychoPy lingo), such as in neuroimaging experiments, you want to make sure each routine is green.
56 |
57 | :::{admonition} ToThink
58 | :class: attention
59 | Do you understand why the *intro* routine is blue instead of green? Hint: the answer to this question is the same as to the previous *ToThink*.
60 | :::
61 |
62 | :::{admonition} ToDo (optional)
63 | :class: attention
64 | Try inserting a new routine at the end of the experiment flow (i.e., after the *goodbye* routine). For example, create a new routine called *the_end* (in the top menu: *Experiment* → *New routine*) with a single text component lasting 1 second. Then, to insert it in the experiment flow, click on *Insert Routine*, select your new routine, and click on the flow line in between *wrap_up* and the arrow head to insert it!
65 | :::
66 |
67 | Anothing think you might encounter in the flow pane is "loops", like the *stimulus_loop* in the demo experiment. This functionality allows you to, well, add loops across routines! In the demo experiment, we use this to repeat our *show_stimulus* routine for the three different images. This is, of course, much more efficient than creating three different routines (or, equivalently, a single routine with three image components)! We will discuss loops in more detail in the next tutorial!
68 |
69 | Alright, now you should know enough of the Builder functionality to start creating a new experiment, which we'll do in the [next tutorial](psychopy_builder_part2.md).
70 |
--------------------------------------------------------------------------------
/intropy/week_2/psychopy_builder_part2.md:
--------------------------------------------------------------------------------
1 | # Creating a Builder experiment from scratch (tutorial)
2 | Alright, now let's get to the interesting part: actually creating experiments! In this tutorial, we will guide you through creating a "Stroop task", step by step. If you are not familiar with the Stroop task, check out the video below!
3 |
4 |
5 |
6 | Using the Builder interface, we are going to create a simple color-word Stroop experiment, including instructions, with two conditions: *congruent* (trials in which the text color matches the word, e.g., red) and *incongruent* (trials in which the text color is different from the word, e.g., red). Along the way, we explain several PsychoPy features, which you will practice with in *ToDos*. A finished Stroop experiment is available under `solutions/week_2/Builder/stroop.psyexp`, but we highly recommend that you first try to complete the exercises without peaking at the solution!
7 |
8 | :::{warning}
9 | Make sure you save your experiment (*File* → *Save*, or `cmd/ctrl + s`) often during this tutorial!
10 | :::
11 |
12 | ## Create a new experiment
13 | Let's start by creating a new experiment.
14 |
15 | :::{admonition} ToDo
16 | :class: attention
17 | Create a new experiment (*File* → *New*) and immediately save the experiment with the name `stroop.psyexp` in the `tutorials/week_2` folder.
18 | :::
19 |
20 | Also, let's change some of the default settings.
21 |
22 | :::{admonition} ToDo
23 | :class: attention
24 | In the *Experiment settings* window (*Basic* tab), enter `stroop` next to *Experiment name* and remove the `session` option in the *Experiment info* box. In the *Data* tab, make sure the data is saved as `sub-{nr}`. Finally, in the *Screen* tab, make sure the experiment uses your own monitor (which you created in an earlier tutorial) and set the *Units* to "norm".
25 | :::
26 |
27 | Note that the choice of [normalized units](https://www.psychopy.org/general/units.html) ("norm") is somewhat arbitrary. We personally like it to easily create stimuli with the appropriate size (but YMMV).
28 |
29 | ## Creating routines and adding components
30 | Let's start our experiment with a nice welcome to our participants who are willing to participate in our experiment. To do so, we'll create a new routine with a single text component. Note that new experiments contain, by default, a single routine named *trial*.
31 |
32 | :::{admonition} ToDo
33 | :class: attention
34 | We'll use the default *trial* routine, but let's rename it to *welcome*. In the flow pane, right-click the *trial* routine, select *rename*, and change its name to *welcome*. Then, in the components pane, select a text component.
35 | :::
36 |
37 | After clicking on the text component icon, the previously discussed properties window pops up. This window has different tabs, but most often you only change things in the *Basic* tab (and sometimes in the *Advanced* tab). First of all, although PsychoPy provides a default component name (here: "text"), we recommend you choose a descriptive name of the new component.
38 |
39 | :::{admonition} ToDo
40 | :class: attention
41 | Give the component a new, descriptive name in the *Name* field (e.g., `welcome_txt`).
42 | :::
43 |
44 | Then, the next property to determine is the start (onset) and stop (offset) of the component relative to the start of the current routine. For both the start and the stop times of your component, you can choose whether to define these times in seconds — `time (s)` in the dropdown menu — or in the number of frames — `frame N` in the dropdown menu. We will revisit timing in terms of the number of frames in the *Coder* tutorials later; for now, we will use the `time (s)` option (for more info about the `frame N` and `condition` options, check [the PsychoPy website](https://www.psychopy.org/builder/startStop.html)).
45 |
46 | In addition to the seconds/frames option, the stop time can also be defined in terms of the component's duration (which is, in fact, the default). When the start time is 0, then the `duration (s)` and `time (s)` give the same results, of course.
47 |
48 | :::{admonition} ToDo
49 | :class: attention
50 | Set the component onset to 0 and the duration to 3 seconds.
51 | :::
52 |
53 | Other properties include the color and font of the text component. The *Color* property accepts any standard [X11 color name](https://www.w3schools.com/Colors/colors_names.asp) and you can use any font available on your system. For now, let's leave these properties at their default values (`white` and `Arial`).
54 |
55 | The next property is the size (or *Letter height*) of the text. The units of the font size are whatever you specified in the *Experiment settings*! As we specified normalized units, the default (`0.1`) represents 10% of the half the the screen. Then, you can specify the position of text component with two numbers: `x` (the horizontal position) and `y` (the vertical position). Like the letter height, the units depend on whatever you specified in the *Experiment settings*.
56 |
57 | :::{admonition} ToDo
58 | :class: attention
59 | Let's make this a little bigger. Set the letter height to 0.2. Then (for now specific reason whatsover), set the position such that the text will appear horizontally in the middle, but vertically halfway between the top and the middle. Make sure you have read the explanation of [normalized units on the PsychoPy website](https://www.psychopy.org/general/units.html) before you try to do this!
60 | :::
61 |
62 | Finally, the only thing we need to specify is, of course, the text itself! In the box associated with the *Text* property, you may specify any plain text, including line breaks ("enters"). Note that PsychoPy will automatically try to wrap the text if it exceeds the window (which can be customized with the *Wrap width* option in the *Advanced* tab).
63 |
64 | :::{admonition} ToDo
65 | :class: attention
66 | Add some text to the text component to welcome our participant. When you're done, click `OK` to save all the changes to the properties.
67 | :::
68 |
69 | By now, you should see the new text component in both the *routines* pane (with its onset/offset) and in the *flow* pane. Try running the experiment by clicking on the green play button (►) to check whether everything works as expected! If the *Experiment runner* displays `##### Experiment ended. #####`, everything ran without problems.
70 |
71 | :::{admonition} ToDo
72 | :class: attention
73 | Each Builder component has a *Help* button in the lower left corner of the properties window. If you click this button, your browser will open the PsychoPy documentation of the associated component!
74 | :::
75 |
76 | ## Keyboard interaction
77 | After welcoming our participants, let's give them some general instructions about our task. As a side note, we want to stress that spending some time and effort to create clear and extensive instructions can, in our experience, matter a lot for the quality of your data! Here, we'll keep it short, but keep this in mind for your future experiments.
78 |
79 | :::{admonition} ToDo
80 | :class: attention
81 | Add a new routine (*Experiment* → *New Routine*) and name it `instructions`.
82 | :::
83 |
84 | After doing so, you should see that an empty routine appears in the routine pane. Also, note that PsychoPy does not automatically add your new routine to the flow pane (after all, it doesn't know *where* you want this routine to appear). To do so, click on *Insert Routine* in the flow pane, select the *instructions* routine, and click on the flow in between the *welcome* routine and the right arrow head.
85 |
86 | :::{admonition} ToDo
87 | :class: attention
88 | Add the *instructions* routine to the flow right after the *welcome* routine.
89 | :::
90 |
91 | Now, we need another text component with instructions of course, but this time we are going to implement it slightly differently than we did in the *welcome* routine. We want to make sure our participants have enough time to read the instructions, so setting a predefined duration (like we did in the *welcome* routine) is not ideal. Instead, we will let the participant indicate whenever they are done and want to continue by having them press the return ("enter") key. But first, we need a text component with some instructions.
92 |
93 | :::{admonition} ToDo
94 | :class: attention
95 | Add a text component with the following text:
96 |
97 | > In this experiment, you will see words (either “green” or “red”) in different colors (also either “green” or “red”).
98 | > Importantly, you need to respond to the COLOR of the word and you need to ignore the actual word. You respond with the arrow keys:
99 | >
100 | > GREEN color = left
101 | > RED color = right
102 | >
103 | > (Press ‘enter’ to start the experiment!)
104 |
105 | Give the component a sensible name, keep the letter height at the default (0.1), and leave the *stop* property empty.
106 | :::
107 |
108 | The effect of leaving the *stop* property empty is that you, technically, create a component with an infinite duration. This is highlighted in the routine pane by the bar corresponding to the component extending beyond the time axis. As mentioned, we'd like to continue the experiment if the participant pressed the return key. To implement this, we'll need to add a [*keyboard component*](https://www.psychopy.org/builder/components/keyboard.html). In addition to some standard properties (like *name*, *start*, and *stop*), the keyboard component also has the property *Allowed keys*, which specifies which keys are recorded and affect this component, and *Store*, which specifies which of the potentially multiple key presses should be saved. The property *Store correct* is not relevant, here, so we'll ignore that for now.
109 |
110 | Another important property, especially in our current use case, is the *Force end of Routine* option. When enabled (the default), it will end the current routine and move on to the next whenever one of the allowed keys is pressed, which is exactly what we want for our instruction routine!
111 |
112 | :::{admonition} ToDo
113 | :class: attention
114 | Add a keyboard component to the *instruction* routine. Make sure the *stop* property is left empty and that it ends the routine when the participant presses the return key (i.e., use "return" for *Allowed keys*).
115 | :::
116 |
117 | If you did the ToDo correctly, you should see a new keyboard component in the *instruction* routine which similarly extends beyond the time axis of the routine pane (indicating that it does not have an offset). Now, run the experiment again and check whether the instruction routine works as expected! (Note: because the *instruction* routine is the experiment's last routine, it may seem that the experiment doesn't advance immediately after pressing enter, but that's because it takes a second or two to quit the experiment after the last routine due to saving data and such.)
118 |
119 | If this were a real experiment for your master thesis, for example, we'd recommend adding some more detailed instructions and practice trials. Also, you probably want to use a larger variety of color-word pairs to increase generalizability (see, e.g., [Westfall, Nichols, & Yarkoni, 2017](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5428747/)). But to keep this experiment relatively simple, our current instructions suffice and we'll only work with two colors (green and red).
120 |
121 | ## Shape (polygon) components
122 | Often, experiments contain a "fixation target" before and in between trials to prevent participants from making too many eyemovements which may impact the results. Often, a simple plus sign is used (which can be created using a text component). For educational purposes, however, let's use a small circle ("fixation dot"), which can be created using the *Polygon* component. Let's add an initial fixation target to our experiment, so that the first trial doesn't immediately show up after the instructions.
123 |
124 | :::{admonition} ToDo
125 | :class: attention
126 | Create a new routine, named *init_fix*, with a single *Polygon* component representing a white circle of size (0.01, 0.01) lasting 2 seconds. Note: "circle" is not part of the standard polygon shapes you can choose. Read the [documentation](https://www.psychopy.org/builder/components/polygon.html) carefully to figure out how to create a circle!
127 | :::
128 |
129 | After creating the *init_fix* routine, run the experiment to see whether it works as expected!
130 |
131 | :::{admonition} ToThink
132 | :class: attention
133 | If you run the experiment, the fixation dot may look more like an oval than a circle... Do you understand why? Do you know how to fix this? Hint: it has to do with the experiment's units.
134 | :::
135 |
136 | If you want a challenge, try the (optional) ToDo below.
137 |
138 | :::{admonition} ToDo
139 | :class: attention
140 | In their article [What is the best fixation target? The effect of target shape on stability of fixational eye movements](https://www.sciencedirect.com/science/article/pii/S0042698912003380) {cite}`thaler2013best`, Thaler and colleagues (2013) investigate the effect of different fixation targets on eye movements and find that the fixation target below leads to the fewest eye movements.
141 |
142 | 
143 |
144 | Try creating this "optimal fixation target" instead of the circle from the previous ToDo. Note that you need multiple *Polygon* components in the same routine to achieve this.
145 | :::
146 |
147 | ## Loops and conditions files
148 | Now, it's time to focus on the most important element of the experiment: the actual "color-word" trials! To do so, we can create a routine with a single text component (in which we can vary the text itself and the text color). Let's start with a congruent trial in which both the word and the color is red. Also, it would be nice if the routine terminates after 5 seconds *or* upon a button press (limited to either the 'left' or 'right' keys) and is followed by a fixation target routine of 0.5 seconds (a so-called "inter-stimulus interval", or ISI).
149 |
150 | :::{admonition} ToDo
151 | :class: attention
152 | Add a new routine, named *stim*, with a text stimulus (*trial_txt*) with the word "red" in the color red and font size 0.2, which terminates after 5 seconds *or* when the participant presses the left or right arrow key (for which you need to add a keyboard component!) and is followed by a new routine, named *isi*, which shows a fixation dot (like in the *init_fix* routine we created before) for 0.5 seconds. Try running the experiment when you're done to see whether everything works as expected!
153 | :::
154 |
155 | Alright, that's a start. But we need more than one trial, of course! One strategy would be to keep adding adding additional *stim* routines (e.g., *stim1*, *stim2*, ... , *stim100*) with different color-word pairs and subsequent ISI routines (e.g., *isi1*, *isi2*, ..., *isi100*), but that would not be very efficient, right? You probably see where I'm going: we can use a *loop* for this! In this loop, we can reuse the general structure of the trial (a *stim* routine + a *isi* routine) and only vary the elements that differ across trials (i.e., the words and text colors). These varying elements can be *any* property of *any* component within the loop!
156 |
157 | The way to specify the varying elements in a loop is through a *conditions file* (an Excel or CSV file). In this file, the rows represent the different trials and the columns represent the different elements that vary across trials. For our Stroop experiment, we could create a file, *conditions.xlsx* (or *conditions.csv*) with two columns — *stim_word* and *stim_color* — and twenty rows: 5 rows for each color-word combination (5 for red-red, 5 for red-green, 5 for green-green, and 5 for green-red), assuming we want a 50/50 split between the congruent/incongruent conditions. The values for the *stim_word* and *stim_color* columns can then be used to modify, per iteration of the loop, the *Text* and *Color* attributes of our text component, respectively.
158 |
159 | :::{admonition} ToDo
160 | :class: attention
161 | Create an Excel (or CSV) file with two columns named *stim_word* and *stim_color* and 20 rows outlining the words and colors (which should be either *red* or *green*). Note that your final file should have 21 rows (the first row being the column headers). Make sure to save this file in the same directory as your `stroop.psyexp` file.
162 | :::
163 |
164 | Now, to create the loop, you need to click *Insert Loop* in the flow pane. Then, when hovering your cursor above the actual flow diagram, a small circle should appear; click on the flow diagram where you'd like your loop to start and click a second time on the diagram where you'd like to your loop to end, after which a new *Loop Properties* window should pop up. In this window, you can specify the name of the loop, the type of the loop (i.e., how to loop across the different rows), and whether this is a loop across trials or blocks (i.e., the *Is trials* option, which you may ignore for now).
165 |
166 | The *nReps* property indicates how often you want to loop across your different trials and the *Selected rows* optionally allows you to specify a subset of rows to loop over. By setting the *random seed* (an integer), you can make sure that the loop shuffles the trials the same way every time you run the experiment. Finally, the *Conditions* property should point to the Excel or CSV file with the properties that change across the different trials.
167 |
168 | :::{admonition} ToDo
169 | :class: attention
170 | Create a loop across the *stim* and *isi* routines (i.e., the loop should encompass these two routines). Name this loop *trial_loop* and make sure it loops randomly across trials a total for 3 repetitions (generating 60 trials). No need to select a subset of rows or to set a random seed. Select your previously created *conditions.xlsx* (or *conditions.csv*) for the *Conditions* property.
171 | :::
172 |
173 | Although we have created our loop, the data in the *Conditions* file has not been linked to our text component (in the *stim* routine), yet! To do so, we need to modify the *Color* and *Text* properties in our text component in two ways. First, we need to tell PsychoPy that the value of the property changes every iteration of the loop. To do so, we need to change the *constant* value to *set every repeat* in the dropdown menu next to the property. Second, we need to tell PsychoPy the column name (from our conditions file) that contains the values for the property we want to update every iteration. Importantly, this column name needs to be prefixed by a dollar sign (`$`), i.e., `$some_column_name`.
174 |
175 | :::{admonition} ToDo
176 | :class: attention
177 | In the text component from your *stim* routine, change *constant* to *set every repeat* for both the *Color* and *Text* properties. Then, make sure the values for the *Color* and *Text* properties refer to the *stim_color* and *stim_word* columns from your conditions file, respectively. Click *OK* to update the text component. Run the experiment to see whether everything works as expected!
178 | :::
179 |
180 | If you made it to this point in the tutorial: good job! You created a complete Stroop experiment from scratch! In the following sections, we'll add some more (non-essential) elements to our experiment as an excuse to explain some more Builder components.
181 |
182 | :::{tip}
183 | In the next section, we are going to add some routines after our trial loop. When we want to test this, it is quite annoying that we have to go through our entire trial loop before seeing the new routines. One way to "skip" the trial loop is to enable the *Disable component* property (in the *Testing* tab of the properties window) of each component in the *stim* and *isi* routines, which will skip said routines.
184 |
185 | Another thing you can do is to set the *nReps* property of the loop to 0!
186 | :::
187 |
188 | ## Mouse interaction
189 | After the trials, we might want to get some feedback on the task from the participant. Let's ask our participant the question "Did you like this task?" to which the participant can answer "yes" or "no". This time, though, we'll make the participant answer using the mouse (instead of the keyboard) by clicking in either a green circle on the left (for "yes") or a red circle on the right (for "no"). Note that this is a completely useless addition the current experiment, but we included it nonetheless to demonstrate the Mouse component.
190 |
191 | :::{admonition} ToDo
192 | :class: attention
193 | Create a new routine, named *feedback*, which creates a display like the image below (doesn't have to *exactly* like it). Make sure each component has an infinite duration (by leaving the *stop* property empty). Hint: you can change the (RGB-specified) color of the Polygon components in the *Advanced* tab of the properties window. If you test your implementation, remember that you can use the *escape* key to abort the experiment.
194 |
195 | 
196 | :::
197 |
198 | To enable interaction through the mouse we can, guess what, add a *Mouse* component! Like the keyboard component, this component can force the end of the routine with the *End Routine on Press* property. By default, this is set to *any click*, meaning that the routine will end at the first button press of the participant. However, we'd like to only end the routine when the participant made a "valid" click, i.e., clicked one of the circles. To do so, you can set the *End Routine on Press* to *valid click* and explicitly specify which components, when clicked, count as "valid clicks" at the *Clickable stimuli* property.
199 |
200 | :::{admonition} ToDo
201 | :class: attention
202 | Add a Mouse component, give it a sensible name, set the duration to infinite, and make sure it forces the end of the routine *only* when one of the circles have been clicked by filling in the component names of your circles in the *Clickable stimuli* field (separated by a comma). Run the experiment to see whether everything works as expected!
203 | :::
204 |
205 | ## Image components
206 | We are of course thankful for the participant's efforts, so let's thank them! We found a nice image to include in a final routine, `thank_you.png` (which is located in the `tutorials/week_2` directory). To embed an image in your experiment, you can use the *Image* component.
207 |
208 | :::{admonition} ToDo
209 | :class: attention
210 | Add a new routine after the *feedback* routine, named *goodbye*, which contains a single Image component, which lasts 3 seconds. Make sure to set the *Image* property with the `thank_you.png` file. Run the experiment to see whether everything works as expected!
211 | :::
212 |
213 | ## Code components (optional)
214 | Alright, for those that want to delve a little deeper into the more advanced Builder features, let's take a look at *Code* components (this is an optional section). With Code components, you can "inject" custom Python code into your Builder experiment. To showcase Code components, let's use one to implement random ISIs (instead of the fixed 0.5 seconds we use now). Using variable instead of fixed ISIs is a trick to prevent participants to anticipate the upcoming stimulus/trial.
215 |
216 | As we want to vary the ISI, we need to change the fixation dot in the *isi* routine. To do so, we'll create a new Python variable that represents a random ISI in a Code compoment, which we subsequently need to link to the Polygon component (i.e., the fixation target). To generate a random ISI (e.g., uniformly distributed between 0 and 1), we can use the [uniform] function from the built-in Python module `random`:
217 |
218 | ```python
219 | import random
220 | t_isi = random.uniform(0, 1)
221 | ```
222 |
223 | Here, `t_isi` is a float between 0 and 1. When creating a new Code component, the properties window actually allows you to specify different code types: Python (`py`), Javascript (`JS`), or a combination of both (`both`). Then, you can specify your code to run at different times during the experiment (*Before Experiment*, *Begin Experiment*, *End Experiment*) and routine (*Begin Routine*, *End Routine*).
224 |
225 | :::{admonition} ToDo
226 | :class: attention
227 | Create a new Code component, give it a sensible name, and make sure the code snippet above runs at the start of the *isi* routine.
228 | :::
229 |
230 | The only thing we still need to do is to make sure the Polygon component uses the randomly generated ISI (i.e., `t_isi`) for its duration. In general, you can write Python code and access Python variables "under the hood" by prefixing the value by a dollar sign (`$`), like we did when accessing the columns from the conditions file earlier. So, to access the Python variable `t_isi` from our Code component for the Polygon *end* property, you can use `$t_isi`.
231 |
232 | :::{admonition} ToDo
233 | :class: attention
234 | Make sure the *end* property of the fixation dot Polygon component uses the `t_isi` variable from our Code component. Then, run the experiment to verify that the ISIs are now different from trial to trial.
235 | :::
236 |
237 | Alright, if you are up for a challenge, try one or both of the next ToDos.
238 |
239 | :::{admonition} ToDo (optional/difficult!)
240 | :class: attention
241 | In some experiments, you may want to give your participant feedback after each trial. Add a routine after the *stim* routine within the trial loop that shows, for 0.5 seconds, the text "correct!" when the participant gave the right response, "incorrect!" when the participant gave the wrong response, and "too late!" when the participant didn't respond within 5 seconds. You need to include a Code component in this new routine that determines this feedback. Hint: in your Code component, the color of the current stimulus is stored in the Python variable `stim_color` and the response from the participant (i.e., either 'left' or 'right') is stored in the Python variable `{name_kb_comp}.keys` (replace `{name_kb_comp}` with the actual name of your keyboard componet in the *stim* routine).
242 | :::
243 |
244 | :::{admonition} ToDo (optional/difficult!)
245 | :class: attention
246 | In the current experiment, we indicated that participants should respond 'left' to green-colored words and 'right' to red-colored words. However, ideally, you'd want to counterbalance this color-response contingency across participants, i.e., (approximately) half of the participants should respond red-left/green-right and the other half should respond red-right/green-left. This between-subject condition should affect the text Component of the *instruction* routine. Arguably the easiest way to implement this is by creating another conditions file (e.g., *participants.{xlsx,csv}*) that outlines the color-response condition, which modifies the *instruction* routine.
247 |
248 | Bonus: try to implement this ToDo and the previous optional ToDo in the same experiment!
249 | :::
250 |
251 | Finally, we're at the end of the Builder tutorial! By now, you know most of the essential features of PsychoPy's Builder interface. Of course, PsychoPy offers many more (advanced) functionality and funky components, but we'll leave that up to you to explore yourself! For now, let's continue with the [first Coder tutorial](psychopy_coder_part1.md)!
252 |
--------------------------------------------------------------------------------
/intropy/week_2/psychopy_how_to_continue.md:
--------------------------------------------------------------------------------
1 | # How to continue with PsychoPy?
2 | In this course, you learned the basics of stimulus presentation using PsychoPy, but PsychoPy has many more awesome features than we had time to discuss (including creating online experiments). Their [resources page](https://www.psychopy.org/resources/resources.html) features an extensive collection of materials that you may use to extend your PsychoPy skills!
3 |
4 | One resource we particularly like is the book written by Jonathan Peirce (PsychoPy's creator) and Michael MacAskill: [Building Experiments in PsychoPy](https://uk.sagepub.com/en-gb/eur/building-experiments-in-psychopy/book253480). Apart from practical information about the PsychoPy software, it also contains several informative chapters about stimulus presentation in general.
5 |
6 | ```{image} ../img/psychopy_book.jpg
7 | :alt: PsychoPy book
8 | :class: bg-primary
9 | :width: 200px
10 | :align: center
11 | ```
12 |
13 | Also, for some shameless self-promotion, if you're comfortable with object-oriented programming in Python, you may want to check out the [exptools2](https://github.com/VU-Cog-Sci/exptools2) Python package. This package is built on top of the PsychoPy package to facilitate accurate (psychophysics and neuroimaging) experiments.
14 |
15 |
--------------------------------------------------------------------------------
/psychopy-env.yml:
--------------------------------------------------------------------------------
1 | name: psychopy
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - python=3.9
6 | - psychopy
7 | - pip
8 | - pip:
9 | - psychtoolbox
10 | - pygame
11 | - pyo
12 | - pyparallel; platform_system != "Windows"
13 | - SoundFile; platform_system == "Windows"
14 | - websocket_client
15 |
--------------------------------------------------------------------------------
/psychopy_test.py:
--------------------------------------------------------------------------------
1 | """ A simple test to see whether the (non-standalone) install
2 | of PsychoPy was successful. """
3 |
4 | from psychopy.core import quit
5 | from psychopy.visual import Window, TextStim
6 | from psychopy.hardware.keyboard import Keyboard
7 |
8 | win = Window()
9 | kb = Keyboard()
10 | txt = TextStim(win, "Testing PsychoPy!\n\nIf you see this, it probably works just fine :-)\n\nPress enter to quit.")
11 | txt.draw()
12 | win.flip()
13 |
14 | while 'return' not in kb.getKeys():
15 | kb.getKeys()
16 |
17 | quit()
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | jupyter-book
2 | ghp-import
3 | numpy
4 | scipy
5 | pandas
6 | matplotlib
7 | pytest
8 | nbval
9 | notebook
10 |
--------------------------------------------------------------------------------
/test_material:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | pytest --nbval --ignore=intropy/_build/ \
3 | --ignore=intropy/solutions/assignment \
4 | --ignore=intropy/solutions/assignment_resit \
5 | --ignore=intropy/tutorials \
6 | --ignore=intropy/submitted \
7 | --ignore=intropy/autograded \
8 | --ignore=psychopy_test.py
--------------------------------------------------------------------------------