psychopy keyboard answer breaks down - python

I am trying to write an Go_nogo Task in Psychopy. Even though I managed to write a script which is working, there are still a few things that make troubles. First, I present pictures of emotional stimuli (im_n, neural; im_a, emotional) and people should only answer by pressing "space" if neutral emotional pictures are presented. When I run the code below everything works well until I don't press any key or the wrong key. So my question is, how do I have to write the code that I don't get kicked out of the run while not answering...? Thanks everybody!
for im in imlist: # Loop for each Image in the List
picShown = bitmap.setImage(im)
bitmap.draw()
win.flip()
rt_clock.reset()
resp = False
while rt_clock.getTime() < timelimit: # timelimit is defined 2 s
if not resp:
resp = event.getKeys(keyList=['space'])
rt = rt_clock.getTime()
if im in im_n: # im_n is an extra list of one kind of images
correctResp = 'space'
if resp[0]==correctResp:
corrFb.draw() # is defined as a "green O"
else:
incorrFb.draw() # is defined as a "red X"
win.flip()
core.wait(ISI)
I get the error message:
if resp[0]==correctResp:
IndexError: list index out of range

My guess is that you get this error message at the if resp[0]==correctResp: line:
IndexError: list index out of range
Is that true? If yes, it is simply because event.getKeys() returns an empty list [] if no responses were collected. And doing [][0] will give you the above error because there's no first element (index zero) just like [1,2,3,4][1000] will give you the same error. Note that even if you press a lot of keys and none of them are in the keyList, getKeys will return an empty list because it ignores everything but the contents of the keyList (unless you set keyList=None, in which case it accepts all keys).
There's a few simple ways out of this. Firstly, you can simply check whether resp is empty and give a "fail" score if it is and only check for correctness if it is not. A more general solution, which would work with many response keys and scoring criteria, is to do if correctResp in resp and then score as a success if yes. This comparison will work with an empty list as well, in which case it always returns False as empty lists per definition can't contain anything.
But in your particular case, you only have one response option so it is even simpler! Since you've "filtered" responses sing the keyList, you KNOW that if resp is [], the subject answered "no-go" and conversely if resp is not [], he/she answered "go". So:
if im in im_n: # im_n is an extra list of one kind of images
if resp: # if subject answered 'go'
corrFb.draw() # is defined as a "green O"
else:
incorrFb.draw() # is defined as a "red X"
Actually, I suspect that you also want to give feedback in trials without neutral images. In that case, define correct as bool(resp) is (im in im_n):
if bool(resp) is (im in im_n): # if answer correspond to trial type
corrFb.draw() # is defined as a "green O"
else:
incorrFb.draw() # is defined as a "red X"

Related

Python - Trying to use a range function to iterate through dictionary

response = requests.get('https://v2.jokeapi.dev/joke/Any?safe-mode&amount=5')
json_string = response.content
parsed_json = json.loads(json_string)
#part of the joke is that this code will sometimes run and sometimes not run. real funny if you ask me.
for i in range(4):
print("your jokes sir: ", parsed_json['jokes'][i]['setup'], parsed_json['jokes'][i]['delivery'])
I import 5 jokes and use a range of 4 to iterate through the separate instances of ['jokes'][i]['delivery'], I thought that this would cycle through the jokes, however it when it runs it doesn't always print the same amount, sometimes it doesnt print anything at all and constantly gives key errors. Wondering how to properly iterate through this
(i have tried changing the range number around and it doesnt seem to have any effect on hitting the key error)
(not using pandas or numpy cause this was for a class assignment and we did not use those for this assignment)
Not all jokes have the setup and delivery keys (I think the joke key and the setup delivery key pair to be mutually exclusive: there are jokes that consist of a whole joke string and jokes made of a setup and delivery) hence the error.
With dict.get() you can get values from dict while having a default value in case the key is missing:
for i, joke in enumerate(parsed_json['jokes']):
print(f"""joke #{i}: {joke.get('joke', '')}{joke.get('setup', '')} {joke.get('delivery', '')}""")
I printed the indexes just to be explicit, but you can use straight objects, and should use indexes only if necessary:
for joke in parsed_json['jokes']:
print(f"""your joke sir: {joke.get('joke', '')}{joke.get('setup', '')} {joke.get('delivery', '')}""")

Confused on dictionary input example in Python Crash Course

I am working my way through Python Crash Course, and in Chapter 8 the author gives the following code as an example for filling a dictionary with user input. I am confused in the step where he stores the responses into the dictionary, as to my eye it looks as though he is only saving one piece of , "response" which is immutable data to the "responses" dictionary under the key "name". I am missing how both the name input and response input are put into the dictionary.
It seems to make no sense to me, but that is what I have loved about this journey so far, finding sense in seeming nonsense. Thank you for helping demystify this world for me.
responses = {}
# Set a flag to indicate that polling is active.
polling_active = True
while polling_active:
#Prompt for the person's name and response.
name = input("\nWhat is your name? ")
response = input("Which mountain would you like to climb someday? ")
#Store the response in the dictionary:
responses[name] = response
#Find out if anyone else is going to take the poll.
repeat = input("Would you like to let another person respond? (yes/no) ")
if repeat == 'no':
polling_active = False
#Polling is complete. Show the results.
print("\n--- Poll Results ---")
for name, response in responses.items():
print(name + " would like to climb " + response + ".")
The thing with dictionaries is that you can change the value of the key like this: dictionary[key] = value. If the key doesn't exist it will simply create a new key. You don't need any function like append which is used for lists. The line where you wrote responses[name] = response works because it stays in a while loop. After the loop runs again it asks another input and replaces the old name with a new name and old response with a new response. In conclusion, name and response is added every time the loop runs if the name is not already in the dictionary. If the name is there then it will simply change its value response if that is different from the old one.
Does this answer your question?
name and response are variables names that are filled with the inputted data, let's say 'John' and 'Kalimanjaro'.
Now, 'John' and 'Kalimanjaro' are indeed immutable, but that doesn't mean you can't replace the values stored in name and response in the next loop. You can assign a new value, maybe also immutable, to name if you want.
One possible source of confusion could be that you started learning dictionaries using statements like responses['John'] = 'Kalimanjaro', where both key and value were strings. Now you are doing responses[name] = response (no quotes around name and response). So you create a key called whatever was stored in name and a value with whatever was stored in response.
If in the next iteration the value of name is replaced by, let's say 'Maria' and response becomes 'Andes', the new responses[name] = response will be equivalent to responses['Maria'] = 'Andes'.
In the most basic explanation, dictionaries associates an arbitrary value at an arbitrary key. So, what the author is actually doing is associating the user's response with their name. The author does this by using the name as a key and the response as a value. Using dictionaries like this is fairly common.
If you want to retrieve a value in the array, you must know it key. However, you can retrieve all key and value pairs with dictionary.items(). This way, the author can get those two associated pieces of data (the name and the response).

How to use the most recently printed line as an input?

I am trying to create a Twitter bot that posts a random line from a text file. I have gone as far as generating the random lines, which print one at a time, and giving the bot access to my Twitter app, but I can't for the life of me figure out how to use a printed line as a status.
I am using Tweepy. My understanding is that I need to use api.update_status(status=X), but I don't know what X needs to be for the status to match the most recently printed line.
This is the relevant section of what I have so far:
from random import choice
x = 1
while True:
file = open('quotes.txt')
content = file.read()
lines = content.splitlines()
print(choice(lines))
api.update_status(status=(choice(lines)))
time.sleep(3600)
The bot is accessing Twitter no problem. It is currently posting another random quote generated by (choice(lines)), but I'd like it to match what prints immediately before.
I may not fully understand your question, but from the very top, where it says, "How to use the most recently printed line as an input", I think I can answer that. Whenever you use the print() command, store the argument into a string variable that overwrites its last value. Then it saves the last printed value.
Instead of directly printing a choice:
print(choice(lines))
create a new variable and use it in your print() and your api.update_status():
selected_quote = choice(lines)
print(selected_quote)
api.update_status(status=selected_quote)

How Do I Start Pulling Apart This Block of JSON Data?

I'd like to make a program that makes offline copies of math questions from Khan Academy. I have a huge 21.6MB text file that contains data on all of their exercises, but I have no idea how to start analyzing it, much less start pulling the questions from it.
Here is a pastebin containing a sample of the JSON data. If you want to see all of it, you can find it here. Warning for long load time.
I've never used JSON before, but I wrote up a quick Python script to try to load up individual "sub-blocks" (or equivalent, correct term) of data.
import sys
import json
exercises = open("exercises.txt", "r+b")
byte = 0
frontbracket = 0
backbracket = 0
while byte < 1000: #while byte < character we want to read up to
#keep at 1000 for testing purposes
char = exercises.read(1)
sys.stdout.write(char)
#Here we decide what to do based on what char we have
if str(char) == "{":
frontbracket = byte
while True:
char = exercises.read(1)
if str(char)=="}":
backbracket=byte
break
exercises.seek(frontbracket)
block = exercises.read(backbracket-frontbracket)
print "Block is " + str(backbracket-frontbracket) + " bytes long"
jsonblock = json.loads(block)
sys.stdout.write(block)
print jsonblock["translated_display_name"]
print "\nENDBLOCK\n"
byte = byte + 1
Ok, the repeated pattern appears to be this: http://pastebin.com/4nSnLEFZ
To get an idea of the structure of the response, you can use JSONlint to copy/paste portions of your string and 'validate'. Even if the portion you copied is not valid, it will still format it into something you can actually read.
First I have used requests library to pull the JSON for you. It's a super-simple library when you're dealing with things like this. The API is slow to respond because it seems you're pulling everything, but it should work fine.
Once you get a response from the API, you can convert that directly to python objects using .json(). What you have is essentially a mixture of nested lists and dictionaries that you can iterate through and pull specific details. In my example below, my_list2 has to use a try/except structure because it would seem that some of the entries do not have two items in the list under translated_problem_types. In that case, it will just put 'None' instead. You might have to use trial and error for such things.
Finally, since you haven't used JSON before, it's also worth noting that it can behave like a dictionary itself; you are not guaranteed the order in which you receive details. However, in this case, it seems the outermost structure is a list, so in theory it's possible that there is a consistent order but don't rely on it - we don't know how the list is constructed.
import requests
api_call = requests.get('https://www.khanacademy.org/api/v1/exercises')
json_response = api_call.json()
# Assume we first want to list "author name" with "author key"
# This should loop through the repeated pattern in the pastebin
# access items as a dictionary
my_list1 = []
for item in json_response:
my_list1.append([item['author_name'], item['author_key']])
print my_list1[0:5]
# Now let's assume we want the 'sha' of the SECOND entry in translated_problem_types
# to also be listed with author name
my_list2 = []
for item in json_response:
try:
the_second_entry = item['translated_problem_types'][0]['items'][1]['sha']
except IndexError:
the_second_entry = 'None'
my_list2.append([item['author_name'], item['author_key'], the_second_entry])
print my_list2[0:5]

error using list.append() when print works fine

I'm trying to make a simple web scraper that will send me an e-mail about deals posted on a website's page. I am using beautifulsoup in order to scrape the info into a list called "list". I can get the output to look they way I want it using a print command, but when I try to use the same loops to append the strings into a list I get the following error
> ----- Post with most thanks ------ Traceback (most recent call last):
> ----- Trending Hot Deals ------ File "C:/Users/Geoff/PycharmProjects/web_scraping/Historian_file.py", line
> 45, in <module>
> ----- Popular Threads ------
> print "\n".join(msg)
> ----- New Posts ------ TypeError: sequence item 0: expected string, NoneType found
>
> Process finished with exit code 1
here is the code, the commented out parts don't work, the print commands do.
def title(number):
if number == 1:
print "----- Post with most thanks ------"
elif number == 2:
print "----- Trending Hot Deals ------"
elif number == 3:
print "----- Popular Threads ------"
else:
print "----- New Posts ------"
msg = []
x = 1
for i in list:
print title(x)
#msg.append(title(x))
x = x+1
for j in i:
l = j.encode_contents()
print l
#msg.append(l)
#print "\n".join(msg)
I appreciate any help on this.
Thanks
Change print statement on return in the title function.
def title(number):
if number == 1:
return "----- Post with most thanks ------"
elif number == 2:
return "----- Trending Hot Deals ------"
elif number == 3:
return "----- Popular Threads ------"
else:
return "----- New Posts ------"
Remember that every function without return statement always returns None.
Moved to an answer, because people are shorting you on valid information.
Yes you need to return data from the function, rather than printing it. So change print to return, and you will be set (as long as you return strings, or sanitize your data)
This is a good lesson on debugging code. Your stack trace says the issue, but your title ignores it as do some of the others. .join() expects string types, so that is where this is causing you issue.
To debug strange issues, you will want to pay more attention to the stacktrace, which was a little cluttered by the prints (don't worry - all of us have ignored this data before).
None is a valid type that can be in a list. As a result, calling mylist.append(Foo()) when Foo returns nothing, appends None to your list. It's completely valid.
Your actual issue, however, is when you try to call .join(ListWithNotStringsInIt). Read that as: I gave .join() list of items, at least one of them was not a string, nor could it be implicitly cast to a string (str()).
How should you solve that to avoid issues in the future? Sanitize your data.
List comprehension is a pretty good way to do this, though - it should be completely unnecessary if you are handling your data responsibly:
'\n'.join([str(x) for x in my_list])
Python expects that you as a programmer are wise about how you can use it. As a result, you get lots of rope to hang yourself with (such as seeing errors like this).
List comprehension should not be required here, and if you are responsible at using your list correctly, it is completely unnecessary. But it's a way to check what you are getting, especially when there are exceptions thrown and you're debugging the issue.
Your title function doesn't return anything, so when you try to append the result of calling the function, you're not actually appending the result from title. Instead, you are appending None. To fix this, you need to return them, instead of simply printing them.

Categories

Resources