Saving data in data file

Hi there,
I am currently working on my bachelor thesis which grew out of propotion. I now have a lot of code and thankfully it works. I have to be done with it all in 2 days. Now the problem. The data (answers and RT) are not saving for the trials in the automatically created file.
in the pretask to learn what to do it works fine, I’ve done it this way:

Collect response (only collect during response phase)

response_collected = False
timer = core.Clock()
user_response = None  
response_time = None  

while not response_collected and timer.getTime() < 4:  
    keys = event.getKeys(timeStamped=timer)  # NEW: Capture response time

    for key, rt in keys:  # NEW: Unpack key and response time
        if key == "f":
            user_response = "yes"
            response_time = rt  # NEW: Save response time
            response_collected = True
        elif key == "j":
            user_response = "no"
            response_time = rt  # NEW: Save response time
            response_collected = True
        elif key == "escape":
            print("Experiment terminated by user.")
            core.quit()


# Routine 4: Feedback (1 second)
if user_response is not None:  # NEW: Only show feedback if a response was collected
    if user_response == "yes" and feedback_text == "Richtig":
        feedback_right.draw()  
    elif user_response == "no" and feedback_text == "Falsch":
        feedback_right.draw()  
    else:
        feedback_wrong.draw()  
win.flip()
core.wait(1)  # Show feedback for 1 second

#Save the trail data 
thisExp.addData("Trial", trial)  
thisExp.addData("Cue", cue_image_path)  
thisExp.addData("Response", user_response if user_response is not None else "no response")  
thisExp.addData("Correct Response", feedback_text)  
thisExp.addData("Response Time", response_time if response_time is not None else "no response")  
thisExp.addData("Correct", 
(user_response == "yes" and feedback_text == "Richtig") or 
(user_response == "no" and feedback_text == "Falsch") if user_response is not None else "no response" 
)
thisExp.nextEntry()  

ChatGPT helped with it because I have no adviser/tutor for anything regarding coding, now in the more complex actual tasks the experiment is in a new window (I believe this could cause problems) and it is more complex with more loops, more trials and more blocks, I’ve tried everything but the data just wont save.

the code looks like this:
import pandas as pd

Neues Fenster für das Experiment erstellen

exp_win = visual.Window(fullscr=True, color=‘white’, units=‘pix’)

Experiment-Parameter

block_size = 30 # 30 Trials pro Block
num_blocks = 6 # 6 Blöcke

Definierte Zeilenbereiche für jeden Block

block_ranges = [
(1, 30), # Block 1: Zeilen 2-31 (Index 1-30)
(31, 60), # Block 2: Zeilen 32-61 (Index 31-60)
(61, 90), # Block 3: Zeilen 62-91 (Index 61-90)
(91, 120), # Block 4: Zeilen 92-121 (Index 91-120)
(121, 150),# Block 5: Zeilen 122-151 (Index 121-150)
(151, 180) # Block 6: Zeilen 152-181 (Index 151-180)
]

Hintergrundbild (hier wird das Bild geladen und als Hintergrund verwendet)

background_img = visual.ImageStim(exp_win, image=“Space/one.png”, size=(2304, 1296))

Fixation-Kreuz und weißes Quadrat

fixation_bg = visual.Rect(exp_win, width=450, height=450, fillColor=‘white’, lineColor=None)
fixation = visual.TextStim(exp_win, text=‘+’, color=‘black’, height=100)

Stimuli (Bilder, aber noch nicht geladen)

cue_img = visual.ImageStim(exp_win, size=[450, 450])
response_img = visual.ImageStim(exp_win, size=[450, 450])

Antwort-Buttons (weiter nach unten verschoben)

left_box = visual.Rect(exp_win, width=200, height=100, fillColor=‘white’, lineColor=‘black’)
right_box = visual.Rect(exp_win, width=200, height=100, fillColor=‘white’, lineColor=‘black’)

left_text = visual.TextStim(exp_win, text=“Ja”, color=‘black’, height=40, pos=(-150, -320))
right_text = visual.TextStim(exp_win, text=“Nein”, color=‘black’, height=40, pos=(150, -320))

Experiment-Schleife für Blöcke

for block, (start_row, end_row) in enumerate(block_ranges):
# Lade nur die benötigten Zeilen für den aktuellen Block
block_data = pd.read_excel(“Day1_Run1.xlsx”, skiprows=range(1, start_row), nrows=end_row - start_row + 1)

# Spaltennamen bereinigen (optional, falls es unsichtbare Leerzeichen gibt)
block_data.columns = block_data.columns.str.strip()

for i, row in block_data.iterrows():
    # Hintergrundbild zeichnen
    background_img.draw()

    # Fixation Routine (0.6s)
    fixation_bg.draw()  # Weißes Quadrat
    fixation.draw()  # Fixationskreuz
    exp_win.flip()
    core.wait(0.6)

    # Cue Routine (0.3s)
    background_img.draw()  # Hintergrund erneut zeichnen
    fixation_bg.draw()  # Weißes Quadrat
    cue_img.setImage(row['Cue_pics'])  # Cue Bild
    cue_img.pos = (0, 0)  # Bild auf dem weißen Quadrat zentrieren
    cue_img.draw()  # Cue Bild zeichnen
    exp_win.flip()
    core.wait(0.3)

    # Response Routine (max. 4s oder bis eine Taste gedrückt wird)
    background_img.draw()  # Hintergrund erneut zeichnen
    fixation_bg.draw()  # Weißes Quadrat
    response_img.setImage(row['Response_pics'])  # Response Bild
    response_img.pos = (0, 0)  # Bild auf dem weißen Quadrat zentrieren
    response_img.draw()  # Response Bild zeichnen
    left_box.pos = (-150, -320)
    right_box.pos = (150, -320)
    left_box.draw()
    right_box.draw()
    left_text.draw()
    right_text.draw()
    exp_win.flip()

    # Warten auf eine Antwort
    response_clock = core.Clock()
    response = None

    while response_clock.getTime() < 4:
        keys = event.getKeys(keyList=['f', 'j', 'escape'])

        if 'escape' in keys:
            exp_win.close()
            core.quit()
        elif 'f' in keys:
            response = "Ja"
            break
        elif 'j' in keys:
            response = "Nein"
            break

    # Daten speichern
    block_data.at[i, 'Response'] = response

# Pause nach jedem Block (außer nach dem letzten)
if block < num_blocks - 1:
    pause_text = visual.TextStim(exp_win, text="Um fortzufahren, drücken Sie die Leertaste.", color='black', height=40)
    pause_text.draw()
    exp_win.flip()
    event.waitKeys(keyList=['space'])

Fenster schließen

exp_win.close()

Has anyone an idea how to make it work?

For any tip I would be endlessly thankful!
Sarah

Are these in a code component in a builder study or did you code this from scratch?

If you coded it from scratch then the first problem is that “thisExp” shouldn’t exist because there’s no ExperimentHandler object. In that case, your best bet, in my opinion, would be to manually create a list of dictionaries, with each entry in the list being a dictionary that has key:value pairs for every column you want in your data file. There’s a function in the Python csv library called csv.DictWriter which can then just save that list of dictionaries to a csv file.

If you’re using code components with builder, then there’s a whole lot of code you probably don’t actually want or need, but w/r/t the data problem specifically, it’s definitely here:

thisExp.addData("Trial", trial)  
thisExp.addData("Cue", cue_image_path)  
thisExp.addData("Response", user_response if user_response is not None else "no response")  
thisExp.addData("Correct Response", feedback_text)  
thisExp.addData("Response Time", response_time if response_time is not None else "no response")  
thisExp.addData("Correct", 
(user_response == "yes" and feedback_text == "Richtig") or 
(user_response == "no" and feedback_text == "Falsch") if user_response is not None else "no response" 
)
thisExp.nextEntry()  

Adding data to thisExp adds experiment-level data. It’s intended for recording things like participant number or condition, things that will be the same on every line of the data file. What you want to do instead is identify the TrialHandler that this routine is part of and use thisTrial.addData()

As a general rule chatGPT is bad with PsychoPy because the library is relatively niche and updates often, so it’s either out-of-date or just gives you advice for other python libraries that don’t work for PsychoPy. It just doesn’t have enough data to be well-trained on PsychoPy specifically. If you need a general-purpose algorithm it can help you figure out how to do it, but for anything PsychoPy specific I’ve never seen it produce code that actually works.

This isn’t my understanding/experience.

In Builder I use expInfo['varName'] = value if I want to add the variable on every line (from that point on) and thisExp.addData('varName',value) if I want to add the value for that variable on the current row only. I never reference a specific TrialHandler.

Ah, I was thinking of expInfo. You’re right, it should work on that basis, in which case it’s either about the overall structure of the experiment or the conditionals