Untitled

Anonymous
plain_text
01/28/2026 10:05 AM
10.3 KB
12
Indexable
# Author:
# Description:
#
# Template by: Teun Mathijssen, Niels Zwemmer, Julia Dawitz


from interactive_figure import interactive_figure
import matplotlib.pyplot as plt
import pandas as pd
import os
import time 
from treisman import treisman
import random

# Import anything else you need here.


def main():
    """Run the visual search experiment"""
    # Ask participant to enter participant number
    participant_number = input("Enter participant number: ")
    
    # Run the experiment (20 correct trials per condition × 12 conditions)
    data_all_trials = run_experiment()
    
    # Save the data
    save_data(data_all_trials, participant_number)


def is_correct(target_count, key_pressed):
    """
    Test whether the right key is pressed based on whether the target is present or not
    
    :param target_count: 1 if target is present, 0 if target is absent
    :param key_pressed: The key the participant pressed 
    """

    key_pressed = key_pressed.lower() # make pressed key case-insensitive

    # input checks
    if target_count != 0 and target_count != 1:
        raise ValueError("target_count should be either 0 or 1")
    
    if key_pressed != 'l' and key_pressed != 'a':
        raise ValueError("key_pressed should be 'l' or 'a'")
    
    
    if target_count == 1: # target_count == 1 so if target is present press 'l'
        correct_key = 'l'
    else: 
        correct_key = 'a' # target_count == 0 so if target is absent press 'a' 

    return key_pressed == correct_key

# testing the function
# print(is_correct(1, 'l')) # should return True
# print(is_correct(0, 'l')) # should return False
# print(is_correct(1, 'a')) # should return False
# print(is_correct(0, 'a')) # should return True
# print(is_correct(5, 'a')) # should raise ValueError for invalid target_count
# print(is_correct(1, 'c')) # should raise ValueError for invalid key_pressed

def run_trial(vs_type, target_count, setsize):
    """
    Docstring for run_trial
    
    :param vs_type: Description
    :param target_count: Description
    :param setsize: Description
    """
    
    
    # Clear previous figure
    interactive_figure.clear()

    # Hide axes for this trial 
    plt.axis('off')

    # Show the visual search display
    treisman(target_count, vs_type, setsize)
    
    #Measure reaction time

    # while loop totdat a of l is geklikt
    valid_response = False
    start_time = time.time()

    while not valid_response: 
        interactive_figure.wait_for_interaction()
        key_pressed = interactive_figure.get_last_key_press().lower()
        

        if key_pressed in ['l', 'a']:
            valid_response = True
        stop_time = time.time()

    reaction_time = stop_time - start_time

    correct = is_correct(target_count, key_pressed)

    #Print trial data
    print(key_pressed, correct, reaction_time)

    return key_pressed, correct, reaction_time
    

# run
# print(run_trial('dcol', 1, 8)) # output

def run_experiment():
    """
    Coordinate the entire visual search experiment.
    
    Participants need to get 20 correct responses per condition.
    There are 12 conditions (4 setsizes × 3 vs_types).
    Total correct trials: 240 (12 × 20)
    Total actual trials: 240+ (includes incorrect responses)
    After every 60 trials, a 30-second pause with 5-second countdown.
    
    :return: List of dictionaries containing all trial data
    """
    
    # Display instructions
    print("\n" + "="*60)
    print("VISUAL SEARCH EXPERIMENT")
    print("="*60)
    print("\nInstructions:")
    print("- A display with symbols will appear on the screen")
    print("- Your task is to determine if the TARGET symbol is present")
    print("- Press 'L' if you think the target is PRESENT")
    print("- Press 'A' if you think the target is ABSENT")
    print("- Try to be as fast and accurate as possible")
    print("\nYou will complete 20 correct trials per condition.")
    print("There are 12 conditions total (different set sizes and search types).")
    print("="*60 + "\n")
    
    input("Press ENTER when you are ready to begin...")
    
    # Set up conditions
    setsizes = [8, 24, 40, 56]
    vs_types = ['dcol', 'dsym', 'conj']
    conditions = []
    
    for vs_type in vs_types:
        for setsize in setsizes:
            conditions.append({'vs_type': vs_type, 'setsize': setsize})
    
    # Randomize the order of conditions
    random.shuffle(conditions)
        
    # Initialize data storage
    data_all_trials = []
    total_trials_counter = 0
    
    # Main experiment loop - iterate through each condition
    for condition_idx, condition in enumerate(conditions, 1):
        vs_type = condition['vs_type']
        setsize = condition['setsize']
        correct_count = 0
        trials_in_condition = 0
        
        print(f"\n--- Condition {condition_idx}/12: {vs_type} search, set size {setsize} ---")
        print(f"Complete 20 correct trials in this condition...")
        
        # Run trials until 20 correct responses in this condition
        while correct_count < 20:
            # Run a trial
            key_pressed, correct, reaction_time = run_trial(vs_type, random.choice([0, 1]), setsize)
            
            trials_in_condition += 1
            total_trials_counter += 1
            
            # Store trial data
            trial_data = {
                'condition_number': condition_idx,
                'vs_type': vs_type,
                'setsize': setsize,
                'trial_in_condition': trials_in_condition,
                'key_pressed': key_pressed,
                'correct': correct,
                'reaction_time': reaction_time,
                'total_trials': total_trials_counter
            }
            data_all_trials.append(trial_data)
            
            # Update correct count
            if correct:
                correct_count += 1
                print(f"  Trial {trials_in_condition}: CORRECT (Correct: {correct_count}/20) RT: {reaction_time:.3f}s")
            else:
                print(f"  Trial {trials_in_condition}: incorrect (Correct: {correct_count}/20) RT: {reaction_time:.3f}s")
            
            # Pause after every 60 trials
            if total_trials_counter % 60 == 0 and total_trials_counter > 0:
                print(f"\n{'='*60}")
                print(f"BREAK TIME - 30 seconds")
                print(f"{'='*60}")
                time.sleep(25)
                for remaining in range(5, 0, -1):
                    print(f"We will start again in {remaining} seconds...")
                    time.sleep(1)
                print("Resuming experiment...\n")
        
        print(f"✓ Condition {condition_idx} completed!")
    
    print("\n" + "="*60)
    print("EXPERIMENT COMPLETED!")
    print("="*60)
    print(f"Total trials: {total_trials_counter}")
    
    return data_all_trials


def save_data(data_all_trials, participant_number):
    """Save participant data to the data directory on our drive."""
    # Convert data rows to Pandas DataFrame for easy writing and reading
    df = pd.DataFrame(data_all_trials)
    print(f"\nObtained data:\n{df}\n")

    # The name under which we will store the DataFrame on our drive
    filename = os.path.realpath(f"data/{participant_number}.csv")

    # Store the DataFrame
    df.to_csv(filename, index=False)
    print(f"Saved data in:\n{filename}\n")


if __name__ == "__main__":
    # Change our working directory to this project directory
    os.chdir(os.path.dirname(os.path.realpath(__file__)))
    print(f"\nCurrent working directory:\n{os.getcwd()}\n")

    # Ensure data directory exists
    os.makedirs("data", exist_ok=True)

    main()
Editor is loading...
Leave a Comment