diff --git a/labs/.DS_Store b/labs/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/labs/.DS_Store differ diff --git a/labs/lab_01.ipynb b/labs/lab_01.ipynb deleted file mode 100644 index a03f558..0000000 --- a/labs/lab_01.ipynb +++ /dev/null @@ -1,65 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "lab_01.ipynb", - "provenance": [], - "authorship_tag": "ABX9TyPvlJ60+yJQJwurM00gkTc0", - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "GGHEmj0Z9SkB", - "outputId": "deac36a9-4f6e-43b1-873c-8732e5408865" - }, - "source": [ - "print('hi!')" - ], - "execution_count": 1, - "outputs": [ - { - "output_type": "stream", - "text": [ - "hi!\n" - ], - "name": "stdout" - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "kaSEpNQC9WVK" - }, - "source": [ - "" - ], - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/labs/lecture_6_lab.py b/labs/lecture_6_lab.py new file mode 100644 index 0000000..601ac89 --- /dev/null +++ b/labs/lecture_6_lab.py @@ -0,0 +1,229 @@ +# # Class 6: Basics of experimental design in PsychoPy +# # Created by Ben Muzekari, edited by Abby Hsiung +# +# # The main goal of today is to introduce some important building blocks when it comes to creating an +# # experiment in PsychoPy. +# +# # More specifically, we will: +# # - Learn how to create stimuli +# # - Learn how to display stimuli to the screen +# # - Learn about randomization and counterbalancing +# +# # Lets get started!!!! +# +# # First we will learn how to create stimuli. Often in experiments, researchers will display different stimuli to the +# # screen for the participant to view and make a response. +# +# # For example, researchers who want to understand food preferences may display varying types of foods on the screen +# # and ask participants to select their preferences. +# +# # Before being able display stimuli on the screen, there are a few things we need to do. +# +# # The first step is importing the appropriate classes we will need. A reminder, classes contain their own set of +# # functions that will help us along the way. +# +# # For now, we will import the visual class from the library PsychoPy. +# # This class allows us to display different stimuli to the participant. +# +# # Below are some examples using the visual class: +# +# # visual.Window(): setting up the screen on which you will display all of your stimuli +# # visual.TextBox(): displaying text on your screen +# # visual.Circle(): displaying circles on your screen +# # visual.RatingScale(): display a rating scale to collect responses from +# +# # ------------------------------------------------------------------------------------------------------------------- +# +# # The way these scripts will work will be different than how we're used to in Google Colab. When we run a .py script, +# # the ENTIRE script runs (not but the specific cell). This means that in order to move through this lecture, we will +# # be taking full advantage of comments (#). We will move through this lecture by slowly un-commenting lines of code +# # below so we can get a step-by-step sense of how we work with stimulus creation. +# +# # All of the code below is currently commented out. As we work through the script, you'll see "UNCOMMENT ME!" tags +# # above lines of code to uncomment as we move through. +# +# # Side note: a shortcut for commenting and un-commenting multiple lines of code is to select the code you want to +# # comment in or out and press 'Command' and '/' +# +To practice, comment +these lines of code out +which are not real lines of code +but me just typing out loud. +# +# # -------------------------------------------------------------------------------------------------------------------- +# +# # UNCOMMENT ME: to import the visual class from main library, PsychoPy +# from psychopy import visual +# +# # We have imported the visual class! +# # Now, we need to create a screen so we can actually display our stimuli to the participant +# +# # UNCOMMENT ME: to create a window so we can display experiment. +# win = visual.Window() # Note: "win" is commonly used to name the screen variable. +# +# # Let's run the script and see what happens! +# # Hopefully you were able to see a screen pop up! Let's next play with some of the arguments in the Window Function +# # to create something more custom +# +# # UNCOMMENT ME: to customize a window so we can display experiment. +# win = visual.Window(size=(800, 800), pos=(400, -300), color=([-0.5, 0.7, 0.7])) +# # full documentation for the many customizable elements of Window here: https://www.psychopy.org/api/visual/window.html +# +# # Now let's try to create our first stimulus! +# # Before we start, we'll comment out one of the windows so we don't dsiplay both to our screen everytime +# +# # UNCOMMENT ME: to create a circle using the Circle function +# my_circle = visual.Circle(win) +# +# # Cool. We've created the stimulus, but we still need to tell PsychoPy to actually display our stimulus. +# # To do this, we can use the draw function: +# +# # UNCOMMENT ME: to draw the circle +# my_circle.draw() +# +# # We also need to use the flip function. +# # PsychoPy has a buffer, meaning whatever is currently being drawn will be stored, but not actually displayed until... +# # we tell PsychoPy to "flip" the screen. Then, whatever is in the buffer is drawn. +# +# # UNCOMMENT ME: to reset the buffer +# win.flip() +# +# # Hmmmm. What happened? +# # Let's take a peak at the circle documentation: https://psychopy.org/api/visual/circle.html +# +# # UNCOMMENT ME X 3: to try our circl drawing again! +# my_circle = visual.Circle(win, fillColor='blue') +# my_circle.draw() # draw the circle +# win.flip() # flip window +# +# # We can also specify the amount of time we'd like to display the circle. To do this we need another class called Core. +# # The core class allows us to set, manipulate, and keep track of time in our experiment +# +# # UNCOMMENT ME: to import another class from the library PsychoPy +# from psychopy import core # importing the core class +# +# # UNCOMMENT ME: to redraw the circle and have is appear for a longer interval +# my_circle.draw() # draw the circle +# win.flip() # flip window +# core.wait(2) # wait 2 seconds before closing +# +# # Now let's try a text stim, a function to draw text to our screen! +# +# # UNCOMMENT ME x 4: to draw and display some text to the screen +# msg = visual.TextStim(win, text="Welcome to my experiment") # create text stim +# msg.draw() # draw text stim +# win.flip() # flip the screen to display text stim +# core.wait(2) # wait 2 seconds +# +# # Now let's try to draw TWO stimuli to the screen at the same time! What will we have to specify? +# +# # UNCOMMENT ME x 6: to draw and display two shapes onto our screen at the same time +# blue_rect = visual.Rect(win, fillColor='blue', pos=(-.4, 0)) +# red_rect = visual.Rect(win, fillColor='red', pos=(.4, 0)) +# +# blue_rect.draw() +# red_rect.draw() +# win.flip() +# core.wait(2) # wait 2 seconds +# +# # Notice that as we build things onto the screen using .draw(), .flip(), we are cycling through the different +# # elements in a sequential order. This can be leveraged to help you advance from one screen to another in your exp. +# +# # -------------------------------------------------------------------------------------------------------------------- +# # Now that we have some experience displaying stimuli, let's talk about randomization and counterbalancing. +# +# # Randomization is used in several ways during research experiments. In brief, randomization is when participants are +# # assigned by chance to different groups, treatments, or interventions in a study. +# +# # A classic example of randomization is during a clinical drug trial in which half the participants are randomly +# # assigned to receive the actual drug and the other half receive a placebo. +# +# # Randomization is important because we want to ensure that the observed behavior in the task is due to an +# # experimental factor and not an external factor. +# +# # Now let's apply this technique. Let's say we have an experiment in which we want to understand how a participant's +# # motivational state is effected by reading different key words on the screen. +# +# # We can create two conditions, one where the keywords may be related to feelings of motivations and another condition +# # that acts as a control +# +# # UNCOMMENT ME x 2: to create our condition text stimuli +# motivational_words = visual.TextStim(win, text="success, growth, achievement, accomplish") +# control_words = visual.TextStim(win, text="block, water, table, cloud") +# +# # UNCOMMENT ME: to import the random module which help us do random things... +# import random +# +# # UNCOMMENT ME x 6: to create a list with the stim, shuffle that list and display it to the screen! +# stim_list = [motivational_words, control_words] +# random.shuffle(stim_list) # shuffle the list +# stim_to_draw = stim_list[0] # select the first element for the list +# +# stim_to_draw.draw() +# win.flip() +# core.wait(2) +# +# # But what if we want to show BOTH conditions to the same participant but in a random order? +# +# # UNCOMMENT ME x 8: to create separate conditions with the motivational words and with the control words +# condition_one = stim_list[0] # select the first element for the list +# condition_two = stim_list[1] # select the second element for the list +# +# condition_one.draw() +# win.flip() +# core.wait(2) +# +# condition_two.draw() +# win.flip() +# core.wait(2) +# +# # Cool! But let's break this down? +# +# # 1. We created two text variables using the visual.Text function and put both of those elements into a list +# # 2. We then randomly shuffled the list and then chose the first element of the list to draw first +# # 3. We then chose the second element of the list and drew that to the screen. +# +# # By doing this, we counterbalanced conditions. Counterbalancing is the systematic variation of conditions in a study. +# # Similar to randomization, counterbalanacing is also important because it ensures that the observed behavior in +# # the task is due to an experimental factor and not an external factor. +# +# # In this example, we counterbalance the order of conditions, meaning some participants may see the motivational +# # condition first while others may see the control. This allows us to avoid potential order effects, meaning we +# # know the results are not due to the order in which they were presented. +# +# # Now, let's go back to our example of drawing two stimuli on the screen simultaneously. For example, we can again +# # draw the blue rectangle and the red rectangle... +# # but this time, maybe the participant is told that each rectangle represents a certain reward value and they are to +# # choose to the better one. +# +# # What will we want to randomize here? +# # What will we want to counterbalance here? +# +# # Lets code this one together!! +# +# # START: +# +# +# # END: +# +# # EXTRA! +# +# # Now let's try to display some real world stimuli. +# # Head to google and download two images to the folder where this script lives. +# # Try to load these images into Psychopy and display them side by side. +# +# # UNCOMMENT ME: to load in the stimuli by defining image path +# food_image_1 = ('YOUR/PATH/TO/IMAGE/HERE/picture.png") +# food_image_2 = ('YOUR/PATH/TO/IMAGE/HERE/other_picture.png") +# +# # write code to display images +# +# # START: +# +# +# # END +# +# # Amazing. Today we learned how to create and display stimuli, as well as the importance and implementation of +# # randomization and counterbalancing. +# +# # For next time: We will learn how to collect and store keyboard responses and how to save and export data! diff --git a/labs/lecture_7_lab.py b/labs/lecture_7_lab.py new file mode 100644 index 0000000..8cc8e33 --- /dev/null +++ b/labs/lecture_7_lab.py @@ -0,0 +1,393 @@ +# # Class 7: Collecting, storing, and saving in PsychoPy +# # Created by Ben Muzekari, edited by Abby Hsiung +# +# # Last class, we learned how to create stimuli, display these stimuli to the screen, and how to randomize and +# # counterbalance stimuli. +# +# # However, in experiments we often like to display stimuli AND collect responses from the participant. +# +# # Some common responses to collect are: +# # 1) The choice option (which option the participant chose) +# # 2) Reaction times (how quickly the participant chose) +# +# # Today, we will: +# # - Learn how to collect keyboard responses +# # - Learn how to store responses +# # - Learn how save data +# +# # Lets get started!!!! +# +# # First, let's import the classes we will need. +# # Last lesson, we learned about the visual class which allows us to display different stimuli to the participant, +# # and about the core class which allows us to set, manipulate, and keep track of time in our experiment. +# +# # Today, we will introduce two more classes that are required for building an experiment. +# # One of these classes is the event class. The event class allows us to track and allow for participant responses. +# +# # Below are some examples using the event class: +# # event.Mouse(): easy way to track what your mouse is doing +# # event.waitKeys(): wait for certain keyboard responses before moving on +# # event.getKeys(): returns a list of keys that were pressed +# +# # The way that we record and save data uses a new python library called pandas. +# # Pandas allows us to keep track and store relevant data in a data frame. More on this below! +# +# # ------------------------------------------------------------------------------------------------------------------- +# # Great. Let's do some coding! +# +# # UNCOMMENT BELOW: to import the visual, core, event, and data classes +# from psychopy import visual, core, event, data +# +# # UNCOMMENT BELOW: to create a window so we can display experiment. +# win = visual.Window(size=(800, 800), pos=(400, -300), color=([-0.8, 0.2, 0.1])) +# +# # Now, let's set up a decision-making task where subjects are to choose from two stimuli on the screen. +# # Let's create a green triangle and an orange triangle. Hint: use the Polygon component. +# +# # UNCOMMENT BELOW: let's create the stimuli +# green_triangle = +# orange_triangle = +# +# # We have created the stimuli, but since this is a decision-making task, we need to display both stimuli on the +# # screen simultaneously. Therefore, we need to specify the position of each stimuli. Ideally, we'd like to draw one +# # stimulus to the left of the screen and one to the right. +# +# # Last lesson, we also learned about the importance of randomization. Let's create a randomizer in which we can use +# # to randomize the location of each stimuli. +# +# # UNCOMMENT BELOW: to import the random module +# import random +# +# # Now, we will need to make a list containing two possible stimulus locations. Let's make one location (-.4, 0) and +# # the other location (.4, 0). +# +# # Then, let's shuffle the list using the random function and then assign the first position in the list to the green +# # triangle and the second to the orange triangle. +# +# # UNCOMMENT BELOW and code away. +# position_list = +# +# # shuffle the list here +# green_triangle_pos = # select the first element of the position list +# orange_triangle_pos = # select the second element of the position list +# +# # Awesome. Now we can assign each of our stimuli a position. +# +# # UNCOMMENT BELOW: to assign each stimulus to their position which was randomized above. How are we doing this? +# green_triangle.pos = green_triangle_pos +# orange_triangle.pos = orange_triangle_pos +# +# draw the green triangle +# draw the orange triangle +# +# flip the window +# wait 2 seconds +# +# # NOW: Run the code and see what happens! +# # Note: If the stimuli are overlapping, try changing the size of both +# +# # ------------------------------------------------------------------------------------------------------------------- +# # Now let's collect responses from the keyboard. First, +# # UNCOMMENT BELOW x 4: This help break up our script into separate parts +# fixation_cross = visual.TextStim(win, text = '+') +# fixation_cross.draw() +# win.flip() +# core.wait(2) +# +# # Now, let's shuffle the position list again, assign each stimulus a position, and draw the stimuli. You can copy +# # the code you've created above. +# +# # UNCOMMENT BELOW +# shuffle the list here +# +# green_triangle_pos = # select the first element of the position list +# orange_triangle_pos = # select the second element of the position list +# +# green_triangle.pos = green_triangle_pos +# orange_triangle.pos = orange_triangle_pos +# +# draw the green triangle +# draw the orange triangle +# +# flip the window +# +# # Now we have the same set-up as before. However, after we flip the window, there is a few things we want to do. +# # One of them is collect reaction item, since we want to know how quickly participants respond. +# +# # To do this, we can use the clock component from the core class +# +# # UNCOMMENT BELOW: to create the clock variable +# clock = core.Clock() +# # Note: the clock will start wherever we first create, so we are creating right after the window flips and the +# # trial starts +# +# # Now we will create a variable that allows us to collect a keyboard response +# # We can do this by using event.waitKeys +# +# # The variable has been created for you below. However, some parameters need to specified: +# # - Set the wait time to 5 seconds +# # - Only look for input from the 'w' and 'o' keys. Participants will use 'w' if they want to select +# # the stimulus on the left and 'o' if they want to select the stimulus on the right +# # - Lastly use the timeStamped parameter and pass in the clock variable we created +# +# # Use the documentation as a guide: https://psychopy.org/api/event.html +# +# # UNCOMMENT DOWN x 2: to create keyboard variable +# resp_key = event.waitKeys() # Note: All of the parameters above should be placed here +# print(resp_key) # Let's also print the variable to the screen to see its output. +# +# # Now, run the code and try to make a decision! +# +# # What happened? Did it work? If so, your decision should have ended the trial. +# # Check the output as well. We printed the resp_key, so we should get some information. +# # Specifically, we should see a list that tells us which key was pressed as well as the reaction time. Do you see it? +# +# # Amazing! We collected a keyboard response and allowed the participant to make a decision to between stimuli. +# # However, sometimes in experiments, the stimuli may represent some reward value and depending on the choice of +# # the participant, they will receive some feedback about the outcome. +# # ------------------------------------------------------------------------------------------------------------------- +# +# # For this lesson, let's say this is a learning task and the participant is attempting to choose the better stimulus. +# # One is a good stimulus and one is a bad stimulus. Then, depending on their choice, the participant receives feedback +# # as to whether they made a good choice or bad one. +# +# # UNCOMMENT BELOW to make a new trial. +# fixation_cross.draw() +# win.flip() +# core.wait(2) +# +# # Now, let's shuffle the position list again, assign each stimulus a position, and draw the stimuli. You can copy +# # the code you've created above. +# +# # UNCOMMENT BELOW +# shuffle the list here +# +# green_triangle_pos = # select the first element of the position list +# orange_triangle_pos = # select the second element of the position list +# +# green_triangle.pos = green_triangle_pos +# orange_triangle.pos = orange_triangle_pos +# +# # Now, let's assign each stimulus to a condition. We can use counterbalancing to ensure the good and bad stimuli vary +# # between the green and orange triangle. +# +# # UNCOMMENT BELOW: to counterbalance the good and the bad stimulus +# stim_outcome_list = # put two strings in this list, 'good' and 'bad' +# +# shuffle the list here +# +# green_triangle_outcome = # select the first element of the list +# orange_triangle_outcome = # select the second element of the list +# +# draw the green triangle +# draw the orange triangle +# +# flip the window +# print(green_triangle_outcome, orange_triangle_outcome) +# +# # Did the print statement print what you expected? +# +# # Great, now we are ready to create and if/else statement to identify which stimulus the participant chose and what +# # the outcome was. Remember when we printed the key_resp variable and the first element was the key pressed? +# +# # We will need to reference that key pressed by indexing the list. We will also need to know the position of the +# # stimulus and whether it was the good or bad stimulus. +# +# # Additionally, we will create a few empty variables so we can add info to them as we go through the if/else statement +# +# # UNCOMMENT BELOW: and complete the if/else statement +# feedback_text = [] # leave this empty +# stim_chosen = [] # leave this empty +# +# # things in [brackets] are verbal explanations of what the code should be +# if [key in response key list (indexed)]: # reference key pressed by indexing the list. +# if [left triangle is green and the green triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'green_triangle' +# elif [left triangle is orange and the orange triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'orange_triangle' +# else: +# feedback_text = 'bad choice :(' +# elif [other key in response key list (indexed)]: # reference key pressed by indexing the list. +# if [right triangle is green and the green triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'green_triangle' +# elif [right triangle is orange and the orange triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'orange_triangle' +# else: +# feedback_text = 'bad choice :(' +# +# +# Lastly, to display the feedback to participants, complete the statement below +# +# # Now, let's create the feedback text stim and pass our feedback_text variable as the text +# +# # UNCOMMENT ME: to create the feedback stim and draw it to the screen +# feedback = visual.TextStim(win, text = feedback_text) +# feedback.draw() # draw the feedback text to the screen +# +# win.flip() # flip the screen +# core.wait(2) # wait 2 seconds +# +# # UNCOMMENT ME to make a new trial. +# fixation_cross.draw() +# win.flip() +# core.wait(2) +# +# # Run the code! Did you get feedback about your decision? Did you make the right choice?! +# # ------------------------------------------------------------------------------------------------------------------- +# # Cool. We have learned to collect a response from the keyboard and show feedback accordingly. +# +# # Now if we're interested in doing many trials of this and seeing if participants can learn which triangle is good and +# # which is bad, we might also have them rate their confidence of their choice. This can give us a measure of how well +# # people are learning across time! +# +# # Let's include a rating scale so after each choice but before feedback, participants rate how confident they are that +# # they chose to right triangle. +# +# # Hint: look at the documentation here: https://www.psychopy.org/api/visual/ratingscale.html +# +# # UNCOMMENT BELOW: and fill in the rest of the code! +# +# fixation_cross.draw() +# win.flip() +# core.wait(2) +# +# stim_outcome_list = # put two strings in this list, 'good' and 'bad' +# +# shuffle the list here +# +# green_triangle_outcome = # select the first element of the list +# orange_triangle_outcome = # select the second element of the list +# +# draw the green triangle +# draw the orange triangle +# +# flip the window +# print(green_triangle_outcome, orange_triangle_outcome) +# +# # RATING SCALE GOES HERE! +# # First, set up the parameters of you confidence ratings scale +# min_confidence = ?? +# max_confidence = ?? +# +# # Next, identify that range of your confidence scale (make sure to add + 1 to your max to get the full range included) +# confidence_range = [range] +# +# # Next, identify the labels points you want to have on your rating scale on range 0 - 1 +# label_points = # the fractions of the range you want to have labels at +# +# # Then determine the labels of your label_points (can be numbers (0, 5,..., 100) or words (low, medium, high)) +# labels = # the actual text for each label +# ticks = [len(confidence_range) * point for point in label_points] # the position along the track for each label +# ​​ +# ratingScale = visual.RatingScale(win, choices=??, labels=??, tickMarks=??) +# +# # Next, set up the actual question you will be asking participants with TextStim +# scale_Q = visual.TextStim(win, "[Question to participants]") +# +# # Lastly, this loop will allow participants to select a rating and submit that rating (and we can record it!) +# while ratingScale.noResponse: +# item.draw() +# ratingScale.draw() +# win.flip() +# rating = ratingScale.getRating() +# +# print(rating) +# +# feedback_text = [] # leave this empty +# stim_chosen = [] # leave this empty +# +# # things in [brackets] are verbal explanations of what the code should be +# if [key in response key list (indexed)]: # reference key pressed by indexing the list. +# if [left triangle is green and the green triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'green_triangle' +# elif [left triangle is orange and the orange triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'orange_triangle' +# else: +# feedback_text = 'bad choice :(' +# elif [other key in response key list (indexed)]: # reference key pressed by indexing the list. +# if [right triangle is green and the green triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'green_triangle' +# elif [right triangle is orange and the orange triangle is good]: +# feedback_text = 'good choice :)' +# stim_chosen = 'orange_triangle' +# else: +# feedback_text = 'bad choice :(' +# +# +# feedback = visual.TextStim(win, text = feedback_text) +# feedback.draw() # draw the feedback text to the screen +# +# win.flip() # flip the screen +# core.wait(2) # wait 2 seconds +# +# fixation_cross.draw() +# win.flip() +# core.wait(2) +# +# # ------------------------------------------------------------------------------------------------------------------- +# +# # Great! We've learned how to collect keyboard responses and how to temporarily store and refer to those responses +# # The final lesson for today is how to save all of our data and export it. This way, we can analyze it later :) +# # First, let's examine an example with fake data +# +# # The pandas library is a python library used for data analysis. It allows us to convert our data into a lovely +# # dataframe, which facilitates data manipulation and analysis. +# +# # Before we get started saving data, let's first decide where we are going to save that data to (aka, the data needs +# 3 a place to live on your computer! It cannot live in PsychoPy! +# +# # First: create a folder in your CNRI folder where your psychopy scripts live, name it Data. Then find the path for +# # your Data folder (should be something like /Users/[your computer name]/[path to CNRI folder]/Data) +# +# # UNCOMMENT BELOW: +# import pandas as pd +# subject_id = 999 # create a subject id num - this will be used to name our file +# output_path = # set up your output path, i.e. where you'd like the data file to be exported (aka, the Data folder) +# save_name = # name the file by the subject id and then in a 'csv' format +# save_file = output_path + save_name # create full file path +# +# # Now, we need to decide what we want to put in our dataframes and how we want them to be organized. For typical +# # experiments, we organize our dataframes so that each column is a variable of interest (e.g., like the ratings, the +# # choices, the position of the two triangles, etc.) and each row represents a different trial the participants did. +# +# # So, because we know the variables that we want before collecting data, we can initial our dataframe with just the +# # names of the columns. +# output_file = pd.DataFrame(columns=[]) # fill in the columns=[] with the columns you want to have for data analysis +# +# # Now we'll create some fake data to put into our pandas data frame. +# +# num_fake_trials = ?? +# +# for i in range(num_fake_trials): +# output_file.loc[i] = [data for each column (ask for help on this once you've decided what columns you're including)] +# +# # The last thing you want to do is export your data into the Data folder so we can see our output in a clean and +# # organized way! +# output_file.to_csv(save_file, index = False) # export the data! +# +# # Now, check where you exported the data - do you see it? What is the layout like? +# +# # HOMEWORK: Awesome. Now that you know how to export data, copy the code from our decision-making task, but this time +# # try to export the real data from the task. Make the columns: which stimulus was chosen, the outcome, and the +# # reaction time. +# +# Code away below! +# +# +# +# +# +# +# +# +# +# +# +# \ No newline at end of file diff --git a/lectures/lecture_6_final-project-text-editors.pptx b/lectures/lecture_6_final-project-text-editors.pptx new file mode 100644 index 0000000..15dc7f8 Binary files /dev/null and b/lectures/lecture_6_final-project-text-editors.pptx differ diff --git a/lectures/lecture_8_usertesting-debugging.ipynb b/lectures/lecture_8_usertesting-debugging.ipynb new file mode 100644 index 0000000..d5657cd --- /dev/null +++ b/lectures/lecture_8_usertesting-debugging.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"lecture8_usertesting-debugging.ipynb","provenance":[],"collapsed_sections":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"wOvIfzlxAJRS"},"source":["# Class 8: An overview of user testing and debugging strategies\n","\n","Created by Miles Martinez, edited by Abby Hsiung"]},{"cell_type":"markdown","metadata":{"id":"VnELGKXftKHf"},"source":["Welcome back friends! Today we'll be looking at how we confront problems in our code and the steps we take to get our code to run precisely how we want it to! \n","\n","Specifically, we're going to practice debugging code, meaning we will figure out all the fun problems we'll inevitably run into while coding."]},{"cell_type":"markdown","metadata":{"id":"aGrHYUketgFA"},"source":["### Learning outcomes:\n","- Be able to identify different types of bugs (aka problems)\n","- Understand strategies for finding and addressing errors in code\n","- Understand the importance of user testing and how to do it \n","\n","### Homeworks: \n","- Finish reviewing the notebook\n","- Work on your code projects!"]},{"cell_type":"markdown","metadata":{"id":"MT9fkU7q77zN"},"source":["---"]},{"cell_type":"markdown","metadata":{"id":"VAW8j77sjtr5"},"source":["## Mistakes: we're only human\n","As much as we all LOVE coding, at this point we should be familiar with the fun (read: not fun) process of dealing with BUGS and ERRORS. Some of the things we've tried have definitely not worked, while on the other hand some of the things we try might work, and we might not understand why. Let's take a look at the following code, and try to understand what should happen in the following cases. \n","\n","---\n","**What do you think should happen when we run the code below?**\n","\n","---\n","\n"]},{"cell_type":"code","metadata":{"id":"PkFg4nfPi7Gw","colab":{"base_uri":"https://localhost:8080/","height":198},"executionInfo":{"status":"error","timestamp":1635294366692,"user_tz":240,"elapsed":229,"user":{"displayName":"Abby Hsiung","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"01152592401722013049"}},"outputId":"d067817c-d058-4483-c5a4-116ed01bc6df"},"source":["turtle = 'turtle'\n","seven = 7\n","seven + turtle\n"],"execution_count":1,"outputs":[{"output_type":"error","ename":"TypeError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mturtle\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'turtle'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mseven\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m7\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mseven\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mturtle\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'"]}]},{"cell_type":"markdown","metadata":{"id":"moG4q1gts9cT"},"source":["---\n","**What about this code?**\n","\n","---"]},{"cell_type":"code","metadata":{"id":"PK755pfilXJm","colab":{"base_uri":"https://localhost:8080/","height":35},"executionInfo":{"status":"ok","timestamp":1635294371842,"user_tz":240,"elapsed":226,"user":{"displayName":"Abby Hsiung","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"01152592401722013049"}},"outputId":"1390bb93-bf3a-488d-94ab-083470979ed9"},"source":["seven * turtle\n"],"execution_count":2,"outputs":[{"output_type":"execute_result","data":{"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"},"text/plain":["'turtleturtleturtleturtleturtleturtleturtle'"]},"metadata":{},"execution_count":2}]},{"cell_type":"markdown","metadata":{"id":"53YVcKb0ldgw"},"source":["Each of these outcomes is \"strange\" in a different way, and deciphering these strange outcomes is honestly one of the main time-sucks when coding - I probably spend almost as much time debugging as I do planning my code or actually coding the experiment. \n","\n","I like to break down **bugs** into three categories:\n","\n","- things that should work, but don't\n","- things that shouldn't work, but do\n","- things that should work one way, but work differently than expected\n","\n","These are loosely ordered by how difficult I think it is to debug them. So for today, we'll go through them in that order. We will also go over what makes them difficult to debug & strategies for debugging.\n","\n","# Category 1: Things that should work, but don't\n","\n","These errors are the main thing that you're probably going to run into, and probably have seen before. They're the kind of error that you'll get in examples like above, when you try to add 7 and 'turtle' together - aka:\n","```\n","TypeError: unsupported operand type(s) for +: 'int' and 'str'\n","```\n","\n","---\n","**What's the best way to deal with these errors?**\n","\n","---\n","My main strategy for dealing with these errors is to copy the error code/error type and paste it [into this website](https://www.google.com). \n","\n","One of the big problems that people often run into with googling these errors is that the specific reason that the error happened is indeed specific to the coder. However, the error **code** or **type** is general, and lots of people have run into that issue before. Therefore by googling the error code, you USUALLY get to a stackoverflow page filled with people who have dealt with and solved your problem before!\n","\n","The second thing I do when dealing with these errors is look at which line they errored on. Sometimes the error might have happened on one line, but is ACTUALLY a consequence of something unexpected that happened earlier in the code! Therefore when considering how to debug, if we get something like above that says:\n","```\n","-----> 3 seven + turtle\n","```\n","We have to consider that our error happened because of the addition, OR because of the way we set up our variables earlier in the code. It could be either one! Additionally, you'll run into cases where both of those things happen in your own code. "]},{"cell_type":"markdown","metadata":{"id":"O-KW7SC7Jx_t"},"source":["To practice situations like this, let's do a lil debugging exercise below. \n","\n","There will be several bugs here -- talk to a classmate and think about where the errors may or may not be, then try to get it running. \n","\n","In this example, let's pretend that we want to print all the elements of list1 and all the corresponding elements of list2."]},{"cell_type":"code","metadata":{"id":"i-qeWNfIr5De"},"source":["list1 = [1,3,4,5,6,1,2,3,4,,]\n","list2 = [4,5,56,6,3,2,1,3,4,5,6,6,7,]\n","\n","l = len(list2)\n","\n","for ii in range(l):\n"," list1 = list1[ii]\n"," print('List 1 element: ', list1)\n"," print('List 2 element: ', l2[ii])\n","\n"," ii = list1\n","\n","\n"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"SlS363a5mcJI"},"source":["# Category 2: Things that shouldn't work, but do"]},{"cell_type":"markdown","metadata":{"id":"LRApTxrDmnJ4"},"source":["Sometimes when coding, you may want part of your code to stop working SPECIFICALLY if a user does something wrong, or just to debug your code. However, when you get to the point where your code should stop working, sometimes it just...keeps running. What do we do then??\n","\n","---\n","**Why would we want our code to stop running in the first place? What would we be testing here?**\n","\n","---\n","\n","Well first, we should generally take a look at the place where we expected it to stop. We then have some questions to ask\n","- Did we set our stop condition correctly? (in other words, was it actually triggered when we expected it to be)\n","- Did our code even reach our stop condition?\n","- Is our stop condition being reset before it has the chance to be triggered?\n","\n","We'll do an example where we have to find and catch all three of those below. In my opinion, these problems are harder to deal with, as they don't pop up an error code or anything for you to google - they will just work and not tell you why! \n","\n","Therefore tracking where things SHOULD break and where they shouldn't is really important, and using \"`print`\" statements can really help with that. \n","\n","With a partner, take a look at the code below - try to predict where the code will keep running, mark where it should stop, and then try to get it to stop under the right conditions."]},{"cell_type":"code","metadata":{"id":"mC166uTCu53g","colab":{"base_uri":"https://localhost:8080/","height":579},"executionInfo":{"status":"error","timestamp":1635295139504,"user_tz":240,"elapsed":12146,"user":{"displayName":"Abby Hsiung","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"01152592401722013049"}},"outputId":"44450432-16c6-47d7-e95a-4ef6bbe34344"},"source":["# if the participant does not match the prompt/condition combination,\n","# end the experiment\n","import random\n","\n","prompts = ['olympics','temple','jamboree','turtle','jeffrey']\n","\n","conditions = ['the same','a different']\n","\n","n_trials = 10\n","responses = []\n","\n","for iter in range(n_trials):\n","\n"," # choose prompt, condition randomly\n"," t_type = random.sample(conditions,1)\n"," t_word = random.sample(prompts,1)\n"," in_word = input(\"Please enter {:s} word: \\'{:s}\\' \".format(t_type[0],t_word[0]))\n","\n"," responses.append(in_word)\n"," wrong = 0\n"," t_word == in_word\n","\n","\n"," if t_type == conditions[0]:\n","\n"," tword = in_word\n"," if t_word == in_word:\n","\n"," corr += 1\n","\n"," if wrong:\n"," print('WRONG')\n"," break\n","\n"," elif t_type == conditions[1]:\n","\n","\n"," t_word = in_word\n"," if not(t_word == in_word):\n","\n"," corr += 1\n","\n","\n"," if wrong:\n"," print('WRONG')\n"," break\n","\n","\n","\n"],"execution_count":4,"outputs":[{"name":"stdout","output_type":"stream","text":["Please enter the same word: 'jamboree' jam\n","Please enter a different word: 'jeffrey' but\n","Please enter the same word: 'jamboree' jam\n"]},{"output_type":"error","ename":"KeyboardInterrupt","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 728\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 729\u001b[0;31m \u001b[0mident\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreply\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstdin_socket\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 730\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/jupyter_client/session.py\u001b[0m in \u001b[0;36mrecv\u001b[0;34m(self, socket, mode, content, copy)\u001b[0m\n\u001b[1;32m 802\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 803\u001b[0;31m \u001b[0mmsg_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msocket\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv_multipart\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 804\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mzmq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mZMQError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/zmq/sugar/socket.py\u001b[0m in \u001b[0;36mrecv_multipart\u001b[0;34m(self, flags, copy, track)\u001b[0m\n\u001b[1;32m 624\u001b[0m \"\"\"\n\u001b[0;32m--> 625\u001b[0;31m \u001b[0mparts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mflags\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtrack\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtrack\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 626\u001b[0m \u001b[0;31m# have first part already, only loop while more to receive\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket.Socket.recv\u001b[0;34m()\u001b[0m\n","\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket.Socket.recv\u001b[0;34m()\u001b[0m\n","\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket._recv_copy\u001b[0;34m()\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/zmq/backend/cython/checkrc.pxd\u001b[0m in \u001b[0;36mzmq.backend.cython.checkrc._check_rc\u001b[0;34m()\u001b[0m\n","\u001b[0;31mKeyboardInterrupt\u001b[0m: ","\nDuring handling of the above exception, another exception occurred:\n","\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mt_type\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msample\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mconditions\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0mt_word\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msample\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprompts\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0min_word\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Please enter {:s} word: \\'{:s}\\' \"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt_type\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mt_word\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mresponses\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0min_word\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 702\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 703\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_header\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 704\u001b[0;31m \u001b[0mpassword\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 705\u001b[0m )\n\u001b[1;32m 706\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;32m/usr/local/lib/python3.7/dist-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 732\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 733\u001b[0m \u001b[0;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 734\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 735\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 736\u001b[0m \u001b[0;32mbreak\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mKeyboardInterrupt\u001b[0m: "]}]},{"cell_type":"markdown","metadata":{"id":"JneD8qFojsgR"},"source":["# Category 3: Things that should work one way, but work a different way"]},{"cell_type":"markdown","metadata":{"id":"10uoX35xmhDl"},"source":["This category can be one of the most difficult to be with. On the surface, problems arising in this way may SEEM perfectly fine - your code ran, you expected it to run, no problems here! \n","\n","However, imagine the situation where you're running an experiment and you bring in a real participant. You check in on them during the experiment, they seem to be doing well, they leave and you're all happy. You go to check their data - and oh no! All of their responses are the exact same! You were watching them so you KNOW they didn't give the same response on every trial - there must be a bug somewhere in your code, but where? \n","\n","This is where user testing becomes super important. If you do not test your code extensively before bringing in participants, this could happen (and has! trust me!). When dealing with these problems, it can be helpful to write down what we EXPECT to happen beforehand at each step (and have print statements to check that so that we can see where the mismatch comes from. \n","\n","For this next ~ experimental ~ block let's try this: \n","\n","---\n","**Write down the set of responses you give and write down the targeted responses, then write down your expected accuracy. Then you can compare the output of the code with your expected output!**\n","\n","**HINT: when working through these types of errors, practice using `print` statements to get a sense of what's going on!**\n","\n","---"]},{"cell_type":"code","metadata":{"id":"-CSh2fMjnxsS","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1635295362162,"user_tz":240,"elapsed":36163,"user":{"displayName":"Abby Hsiung","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"01152592401722013049"}},"outputId":"ee521be4-84f2-435f-cb48-6a15ee36aad8"},"source":["import random\n","\n","PROMPTS = ['olympics','temple','jamboree','turtle','jeffrey']\n","\n","CONDITIONS = ['the same','a different']\n","\n","# function to detect responses\n","def detect_response(response,target,prompt):\n"," if prompt == CONDITIONS[0]:\n","\n"," if target == response:\n","\n"," return True, response, target\n","\n"," else:\n"," return True, response, target\n","\n"," elif prompt == CONDITIONS[1]:\n","\n","\n"," if not(target == response):\n","\n"," return True, response, target\n","\n"," else:\n"," return True, response, target\n"," \n","\n","\n","#### Actual Experiment Stuff\n","n_trials = 5\n","trial_data = []\n","\n","for iter in range(n_trials):\n","\n"," trial_data = []\n"," # choose prompt, condition randomly\n"," t_type = random.sample(CONDITIONS,1)[0]\n"," t_word = random.sample(PROMPTS,1)[0]\n"," response = input(\"Please enter {:s} word: \\'{:s}\\' \".format(t_type,t_word))\n"," acc, _, response = detect_response(response,t_word,t_type)\n","\n"," trial_data.append((t_word,response,acc))\n","\n","print(trial_data)\n"],"execution_count":5,"outputs":[{"output_type":"stream","name":"stdout","text":["Please enter the same word: 'temple' temple\n","the same\n","temple\n","temple\n","Please enter a different word: 'jeffrey' butt\n","a different\n","jeffrey\n","butt\n","Please enter the same word: 'jeffrey' jeffrey\n","the same\n","jeffrey\n","jeffrey\n","Please enter the same word: 'jamboree' butt\n","the same\n","jamboree\n","butt\n","Please enter a different word: 'temple' cheese\n","a different\n","temple\n","cheese\n","[('temple', 'temple', True)]\n"]}]},{"cell_type":"markdown","metadata":{"id":"80iwLsUOXg1Z"},"source":["### User Testing?\n","\n","I've talked a lot about user testing in this lecture - but what actually is user testing? It's something that's pretty vital to our code performing how we want it to. Basically, it is when we (the researchers) run our code against ourselves and do everything we can to break it. \n","\n","---\n","**Discuss: why should we try to break our code?**\n","\n","---\n","\n","We're gonna have one more example here - and it'll contain all three types of errors. Do your best to do the following, based on the description at the top of the code:\n","\n","- predict when the code SHOULD stop (aka when we want to keep our participant from giving more inputs)\n","- predict what inputs should keep our code running (what inputs we want our code to accept)\n","- write down a set of inputs for each trial and the corresponding output you should expect afterwards"]},{"cell_type":"code","metadata":{"id":"4us67TMLepd1"},"source":["#### Experiment Setup\n","#### We want do a word association task \n","#### Given a prompt word, have our participants enter up to five words that are either\n","#### as similar to the prompt word as possible (condition 0) or as dissimilar as \n","#### possible (condition 1). If the participant enters any variation of 'done',\n","#### end the trial early.\n","\n","#### Given that we have five target words, we want our code to do the following:\n","\n","##### 1. shuffle order of TARGETS. We want one trial for each word in targets \n"," #(so that's five trials), and we want them in a random order (generally not\n"," # the same order as TARGETS is defined)\n","##### 2. for each trial, randomly pick a condition (similar to or different from)\n","##### 3. while participants have responded fewer than five times, keep asking them to enter\n"," # words\n","##### 4. If participant enters 'done', end that trial early, move onto the next\n","##### 5. store data on each trial in all_data\n","\n","import random\n","\n","TARGETS = ['olympics','temple','jamboree','turtle','cat']\n","\n","CONDITIONS = ['similar to','different from']\n","\n","#### Actual Experiment Stuff\n","max_responses = 5\n","trial_data = []\n","all_data = []\n","\n","targets_shuffled = random.shuffle(TARGETS[0])\n","\n","for trial_target in TARGETS:\n","\n"," all_data = []\n"," # choose condition randomly\n"," t_type = random.sample(CONDITIONS,1)\n","\n"," while len(trial_data) < max_responses:\n"," response = input(\"Please enter words {:s} \\'{:s}\\': \".format(t_type,trial_target))\n","\n"," if response.lower() == 'done':\n"," \n"," pass\n"," \n"," else:\n"," trial_data.append(response)\n","\n"," all_data.append(trial_data)\n"],"execution_count":null,"outputs":[]}]} \ No newline at end of file