def main(): # ------------------------------------------------------------------------- # Load config; establish database connection; ask the user for anything else # ------------------------------------------------------------------------- log.info("Asking user for config filename") config = load_config_or_die( mandatory=['database_url'], defaults=dict(server='localhost', port=DEFAULT_PORT), log_config=True # send to console (beware security of database URLs) ) db = connect_to_db_using_attrdict(config.database_url) # Any additional user input required? num_pings = ask_user("Number of pings", default=10, type=int, min=1) ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T']) # ------------------------------------------------------------------------- # Set up task and go # ------------------------------------------------------------------------- session = AttrDict(start=datetime.now(), subject=config.subject, session=config.session, num_pings=num_pings) insert_and_set_id(db[SESSION_TABLE], session) # save to database log.info("Off we go...") task = MyWhiskerTask(config, db, session) task.connect(config.server, config.port) # noinspection PyUnresolvedReferences reactor.run() # starts Twisted and thus network processing log.info("Finished.") # ------------------------------------------------------------------------- # Done. Calculate summaries. Save data from this session to new CSV files. # ------------------------------------------------------------------------- # Retrieve all our trials. (There may also be many others in the database.) # NOTE that find() returns an iterator (you get to iterate through it ONCE). # Since we want to use this more than once (below), use a list. trials = list(db[TRIAL_TABLE].find(session_id=session.id)) # Calculate some summary measures summary = AttrDict( session_id=session.id, # foreign key n_pings_received=sum(t.received for t in trials)) insert_and_set_id(db[SUMMARY_TABLE], summary) # save to database # Save data. (Since the session and summary objects are single objects, we # encapsulate them in a list.) save_data("session", [session], timestamp=session.start, taskname=TASKNAME_SHORT) save_data("trial", trials, timestamp=session.start, taskname=TASKNAME_SHORT) save_data("summary", [summary], timestamp=session.start, taskname=TASKNAME_SHORT)
def shutdown(): log.info("Storing Data") # ------------------------------------------------------------------------- # Done. Calculate summaries. Save data from this session to new CSV files. # ------------------------------------------------------------------------- # Retrieve all our trials. (There may also be many others in the database.) # NOTE that find() returns an iterator (you get to iterate through it ONCE). # Since we want to use this more than once (below), use a list. trials = list(db[TRIAL_TABLE].find(session_id=session.id)) # Calculate some summary measures summary = AttrDict( session_id=session.id, # foreign key date=datetime.utcnow(), trials=len(trials), trials_rewarded=sum(t.rewarded for t in trials), ) insert_and_set_id(db[SUMMARY_TABLE], summary) # save to database # Save data. (Since the session and summary objects are single objects, we # encapsulate them in a list.) save_data("session", [session], timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location) save_data("trial", trials, timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location) save_data("summary", [summary], timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location)
def main(): # ------------------------------------------------------------------------- # Load config; establish database connection; ask the user for anything else # ------------------------------------------------------------------------- log.info("Asking user for config filename") config = load_config_or_die( mandatory=['database_url'], defaults=dict(server='localhost', port=DEFAULT_PORT), log_config=True # send to console (beware security of database URLs) ) db = connect_to_db_using_attrdict(config.database_url) # Any additional user input required? num_pings = ask_user("Number of pings", default=10, type=int, min=1) ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T']) # ------------------------------------------------------------------------- # Set up task and go # ------------------------------------------------------------------------- session = AttrDict(start=datetime.now(), subject=config.subject, session=config.session, num_pings=num_pings) insert_and_set_id(db[SESSION_TABLE], session) # save to database log.info("Off we go...") task = MyWhiskerTask(config, db, session) task.connect(config.server, config.port) # noinspection PyUnresolvedReferences reactor.run() # starts Twisted and thus network processing log.info("Finished.") # ------------------------------------------------------------------------- # Done. Calculate summaries. Save data from this session to new CSV files. # ------------------------------------------------------------------------- # Retrieve all our trials. (There may also be many others in the database.) # NOTE that find() returns an iterator (you get to iterate through it ONCE). # Since we want to use this more than once (below), use a list. trials = list(db[TRIAL_TABLE].find(session_id=session.id)) # Calculate some summary measures summary = AttrDict( session_id=session.id, # foreign key n_pings_received=sum(t.received for t in trials) ) insert_and_set_id(db[SUMMARY_TABLE], summary) # save to database # Save data. (Since the session and summary objects are single objects, we # encapsulate them in a list.) save_data("session", [session], timestamp=session.start, taskname=TASKNAME_SHORT) save_data("trial", trials, timestamp=session.start, taskname=TASKNAME_SHORT) save_data("summary", [summary], timestamp=session.start, taskname=TASKNAME_SHORT)
def incoming_event(self, event, timestamp=None): """An event has arrived from the Whisker server.""" # timestamp is the Whisker server's clock time in ms; we want real time now = datetime.utcnow() print("Event: {e} (timestamp {t}, real time {n})".format( e=event, t=timestamp, n=now.isoformat())) # We could do lots of things at this point. But let's keep it simple: if event == "EndOfTask": # noinspection PyUnresolvedReferences reactor.stop() # stops Twisted and thus network processing else: trial = AttrDict( session_id=self.session.id, # important foreign key trial_num=self.trial_num, event="Ping!", received=True, # now we're just making things up... when=now, ) insert_and_set_id(self.db[TRIAL_TABLE], trial) # save to database self.trial_num += 1 log.info("{} pings received so far".format(self.trial_num))
def main(): # ------------------------------------------------------------------------- # Load config; establish database connection; ask the user for anything else # ------------------------------------------------------------------------- log.info("Asking user for config filename") config = load_config_or_die( mandatory=['database_url','stimuli_presentation_millis','iti_millis','feedback_millis','feedback_flash_millis','timeout_millis','num_trials','max_task_time_millis','stimuli','screen_resolution','pairings'], defaults=dict(server='localhost', port=DEFAULT_PORT), log_config=True # send to console (beware security of database URLs) ) log.info("Asking user where to store the data") save_location=open_file_dialog() if not save_location: log.critical("No directory to store given; exiting.") sys.exit(1) log.info("Storing data is: {}".format(save_location)) # with open("./config.yaml") as infile: # config = AttrDict(yaml.safe_load(infile)) # config.port=DEFAULT_PORT validate(config) db = connect_to_db_using_attrdict(config.database_url) # Any additional user input required? # ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T']) # ------------------------------------------------------------------------- # Set up task and go # ------------------------------------------------------------------------- session = AttrDict(start=datetime.now(), subject=config.subject, session=config.session) insert_and_set_id(db[SESSION_TABLE], session) # save to database log.info("Off we go...") task = VisualDiscriminationTask(config, db, session) task.connect(config.server, config.port) def shutdown(): log.info("Storing Data") # ------------------------------------------------------------------------- # Done. Calculate summaries. Save data from this session to new CSV files. # ------------------------------------------------------------------------- # Retrieve all our trials. (There may also be many others in the database.) # NOTE that find() returns an iterator (you get to iterate through it ONCE). # Since we want to use this more than once (below), use a list. trials = list(db[TRIAL_TABLE].find(session_id=session.id)) # Calculate some summary measures summary = AttrDict( session_id=session.id, # foreign key date=datetime.utcnow(), trials=len(trials), trials_rewarded=sum(t.rewarded for t in trials), ) insert_and_set_id(db[SUMMARY_TABLE], summary) # save to database # Save data. (Since the session and summary objects are single objects, we # encapsulate them in a list.) save_data("session", [session], timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location) save_data("trial", trials, timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location) save_data("summary", [summary], timestamp=session.start, taskname=TASKNAME_SHORT,directory=save_location) reactor.addSystemEventTrigger('before', 'shutdown', shutdown) # noinspection PyUnresolvedReferences reactor.run() # starts Twisted and thus network processing log.info("Finished.") shutdown()
def incoming_event(self, event, timestamp=None): """An event has arrived from the Whisker server.""" # timestamp is the Whisker server's clock time in ms; we want real time now = datetime.utcnow() whisker=self.whisker config=self.config print("Event: {e} (timestamp {t}, real time {n})".format( e=event, t=timestamp, n=now.isoformat())) if event=="flash": if self.flashCount%2==1: pen=Pen(colour=BLACK) brush=Brush(colour=BLACK) whisker.display_add_obj_rectangle(self.selection_screen.key,"mask",self.flashmask,pen,brush) else: whisker.display_delete_obj(self.selection_screen.key,"mask") self.flashCount+=1 return if self.state=="iti": self.set_state("start") whisker.display_show_document("screen","start") self.checkConditions() elif self.state=="start": self.selection_screen=self.trial_order[self.trial_num] while not self.selection_screen.enabled: trial = AttrDict( session_id=self.session.id, # important foreign key trial_num=self.trial_num, selected="SKIPPED", when=now, stimuli_left=self.selection_screen.stimuli[0].key, stimuli_right=self.selection_screen.stimuli[1].key, rewarded=False, ) insert_and_set_id(self.db[TRIAL_TABLE], trial) self.trial_num+=1 self.selection_screen=self.trial_order[self.trial_num] whisker.display_show_document("screen",self.selection_screen.key) self.set_state("selection") whisker.timer_set_event("stimuli_selection_timeout",config.stimuli_presentation_millis,0) elif self.state=="selection": whisker.display_delete_obj("summary","choice") whisker.display_add_obj_text("summary","choice",[ self.state_screen_centre_x,self.state_screen_centre_y+60] ,"Selected: "+event,50,None,False,False,0,[255,255,255]) if event=="stimuli_selection_timeout": self.set_state("iti") whisker.display_blank("screen") whisker.timer_set_event("stimuli_selection",config.iti_millis) self.correctResponse=False else: self.set_state("feedback") whisker.timer_set_event("feedback",config.feedback_millis,0) whisker.timer_set_event("flash",config.feedback_flash_millis,4*3-2) self.flashmask=whisker.display_get_object_extent(self.selection_screen.key,event) if self.flashmask: pen=Pen(colour=BLACK) brush=Brush(colour=BLACK) whisker.display_add_obj_rectangle(self.selection_screen.key,"mask",self.flashmask,pen,brush) self.flashCount=0 rewards=False for s in self.selection_screen.stimuli: if s.key==event: rewards=s.reward_ratio>=random.random() if "extinction_rate" in s: s.reward_ratio-=s.extinction_rate self.correctResponse=rewards whisker.timer_clear_event("stimuli_selection_timeout") whisker.display_add_obj_text("summary","choice",[ self.state_screen_centre_x,self.state_screen_centre_y+120] ,"Rewarded: "+str(self.correctResponse),50,None,False,False,0,[255,255,255]) trial = AttrDict( session_id=self.session.id, # important foreign key trial_num=self.trial_num, selected=event, # either time out or the symbol pressed when=now, stimuli_left=self.selection_screen.stimuli[0].key, stimuli_right=self.selection_screen.stimuli[1].key, rewarded=self.correctResponse, ) insert_and_set_id(self.db[TRIAL_TABLE], trial) # save to database self.reward_sequence.append(self.correctResponse) self.trial_num += 1 log.info("{} event received so far".format(self.trial_num)) elif self.state=="feedback": whisker.display_blank("screen") if self.correctResponse: self.set_state("collect_reward") whisker.line_set_state("tray_lights",True) whisker.line_set_event("ir_beam","beam_broken") else: whisker.line_set_state("house_lights",True) self.set_state("timeout") whisker.timer_set_event("timeout",config.timeout_millis,0) elif event=="timeout" or event=="beam_broken": if event=="timeout": whisker.line_set_state("house_lights",False) else: whisker.line_set_state("tray_lights",False) whisker.line_clear_event("beam_broken") self.set_state("iti") whisker.timer_set_event("stimuli_selection",config.iti_millis) if self.trial_num>=self.config.num_trials or event == "task_time_out": reactor.stop() # stops Twisted and thus network processing