From ab4e12c4717944a3812b382f6349eeb0161faf5d Mon Sep 17 00:00:00 2001 From: Minseung Choi Date: Tue, 12 Mar 2024 15:19:16 -0700 Subject: [PATCH] Change idle background on the fly without starting stim --- stimpack/experiment/client.py | 3 ++- stimpack/experiment/gui.py | 24 +++++++++++++++++++----- stimpack/experiment/protocol.py | 29 +++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/stimpack/experiment/client.py b/stimpack/experiment/client.py index e1e273f..1310b2f 100644 --- a/stimpack/experiment/client.py +++ b/stimpack/experiment/client.py @@ -8,6 +8,7 @@ from stimpack.rpc.transceiver import MySocketClient from stimpack.visual_stim.screen import Screen +from stimpack.visual_stim.util import get_rgba from stimpack.experiment.server import BaseServer from stimpack.experiment.util import config_tools from stimpack.device import daq @@ -95,7 +96,7 @@ def start_run(self, protocol_object, data, save_metadata_flag=True): protocol_object.prepare_run(recompute_epoch_parameters=False) # Set background to idle_color - self.manager.target('visual').set_idle_background(protocol_object.run_parameters['idle_color']) + self.manager.target('visual').set_idle_background(get_rgba(protocol_object.run_parameters.get('idle_color', 0))) if save_metadata_flag: data.create_epoch_run(protocol_object) diff --git a/stimpack/experiment/gui.py b/stimpack/experiment/gui.py index ae2164f..a27bc69 100755 --- a/stimpack/experiment/gui.py +++ b/stimpack/experiment/gui.py @@ -481,7 +481,7 @@ def on_selected_protocol_ID(self, text, preset_name='Default'): # update display lists of run & protocol parameters self.protocol_object.load_parameter_presets() self.protocol_object.select_protocol_preset(name=preset_name) - self.protocol_object.prepare_run() + self.protocol_object.prepare_run(manager=self.client.manager) self.update_parameter_preset_selector() self.update_parameters_input() self.update_window_width() @@ -797,7 +797,7 @@ def update_run_parameters_input(): for key, value in self.protocol_object.run_parameters.items(): self.run_parameter_input[key] = make_parameter_input_field(key, value, self.parameters_grid_row_ct) self.parameters_grid_row_ct += 1 - set_validator(self.run_parameter_input[key], type(value)) + # set_validator(self.run_parameter_input[key], type(value)) def update_protocol_parameters_input(): # update display window to show parameters for this protocol @@ -1038,8 +1038,22 @@ def parse_param_str(s, param_type=float): if isinstance(self.run_parameter_input[key], QCheckBox): #QCheckBox self.protocol_object.run_parameters[key] = self.run_parameter_input[key].isChecked() else: # QLineEdit - run_parameter_input_text = self.run_parameter_input[key].text() - self.protocol_object.run_parameters[key] = float(run_parameter_input_text) if len(run_parameter_input_text)>0 else 0 + # run_parameter_input_text = self.run_parameter_input[key].text() + # self.protocol_object.run_parameters[key] = float(run_parameter_input_text) if len(run_parameter_input_text)>0 else 0 + raw_input = self.run_parameter_input[key].text() + parsed_input = parse_param_str(raw_input) + + if isinstance(parsed_input, ParseError): # Parse error + default_value = self.protocol_object.get_run_parameter_defaults()[key] + default_value_input_text = self.make_parameter_input_text(default_value) + error_text = parsed_input.message + '\n' + \ + 'Raw input: ' + raw_input + '\n' + \ + 'Using default value: ' + default_value_input_text + open_message_window(title='Parameter parse error', text=error_text) + self.protocol_object.run_parameters[key] = default_value + self.run_parameter_input[key].setText(default_value_input_text) + else: # Successful parse + self.protocol_object.run_parameters[key] = parsed_input for key, value in self.protocol_parameter_input.items(): if isinstance(self.protocol_parameter_input[key], QCheckBox): #QCheckBox @@ -1060,7 +1074,7 @@ def parse_param_str(s, param_type=float): else: # Successful parse self.protocol_object.protocol_parameters[key] = parsed_input - self.protocol_object.prepare_run(recompute_epoch_parameters=compute_epoch_parameters) + self.protocol_object.prepare_run(manager=self.client.manager, recompute_epoch_parameters=compute_epoch_parameters) self.update_run_progress() self.mid_parameter_edit = False diff --git a/stimpack/experiment/protocol.py b/stimpack/experiment/protocol.py index 495b1b6..668014f 100644 --- a/stimpack/experiment/protocol.py +++ b/stimpack/experiment/protocol.py @@ -197,7 +197,7 @@ def check_required_run_parameters(self): required_run_parameters: list of tuples (parameter_name, parameter_dtype) parameter is cast to parameter_dtype; if no cast is needed, use None """ - required_run_parameters = [('num_epochs', int), ('idle_color', float)] + required_run_parameters = [('num_epochs', int), ('idle_color', None)] if self.loco_available: required_run_parameters.append(('do_loco', bool)) @@ -206,10 +206,19 @@ def check_required_run_parameters(self): raise ValueError(f'Run parameter {p} is required but not found in {self.run_parameters}') else: if dtype is not None: - try: - self.run_parameters[p] = dtype(self.run_parameters[p]) - except: - raise ValueError(f'Run parameter {p} could not be cast to {dtype}') + if not isinstance(dtype, list): + dtype = [dtype] + + value_error = False + for d in dtype: + try: + self.run_parameters[p] = d(self.run_parameters[p]) + value_error = False + break + except: + value_error = True + if value_error: + raise ValueError(f'Run parameter {p} could not be cast to {dtype}.') def check_required_epoch_protocol_parameters(self): """ @@ -228,7 +237,7 @@ def check_required_epoch_protocol_parameters(self): except: raise ValueError(f'Epoch protocol parameter {p} could not be cast to {dtype}') - def prepare_run(self, recompute_epoch_parameters=True): + def prepare_run(self, manager=None, recompute_epoch_parameters=True): """ recompute_epoch_parameters: bool If True, precompute epoch parameters even if they have been computed already @@ -250,13 +259,17 @@ def prepare_run(self, recompute_epoch_parameters=True): # Estimate run time self.__estimate_run_time() + # If manager exists, set visual_stim background to idle_color + if manager is not None: + manager.target('visual').set_idle_background(get_rgba(self.run_parameters.get('idle_color', 0))) + def load_stimuli(self, manager, multicall=None): if multicall is None: multicall = stimpack.rpc.multicall.MyMultiCall(manager) - bg = self.run_parameters.get('idle_color') + bg = get_rgba(self.run_parameters.get('idle_color', 0)) multicall.target('visual').set_idle_background(bg) - multicall.target('visual').load_stim('ConstantBackground', color=get_rgba(bg), hold=True) + multicall.target('visual').load_stim('ConstantBackground', color=bg, hold=True) if isinstance(self.epoch_stim_parameters, list): for ep in self.epoch_stim_parameters: