diff --git a/software/control/_def.py b/software/control/_def.py index ce015dd4..86596292 100644 --- a/software/control/_def.py +++ b/software/control/_def.py @@ -435,6 +435,7 @@ class PLATE_READER: ENABLE_TRACKING = False TRACKING_SHOW_MICROSCOPE_CONFIGURATIONS = False # set to true when doing multimodal acquisition + class AF: STOP_THRESHOLD = 0.85 CROP_WIDTH = 800 diff --git a/software/control/core/core.py b/software/control/core/core.py index de40eefa..6dbd1c8a 100644 --- a/software/control/core/core.py +++ b/software/control/core/core.py @@ -1701,7 +1701,9 @@ def perform_autofocus(self, region_id, fov): config_AF = next( ( config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) if config.name == configuration_name_AF ) ) @@ -1723,7 +1725,9 @@ def perform_autofocus(self, region_id, fov): config_AF = next( ( config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) if config.name == configuration_name_AF ) ) @@ -1837,7 +1841,9 @@ def acquire_rgb_image(self, config, file_ID, current_path, current_round_images, rgb_channels = ["BF LED matrix full_R", "BF LED matrix full_G", "BF LED matrix full_B"] images = {} - for config_ in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for config_ in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): if config_.name in rgb_channels: # update the current configuration self.signal_current_configuration.emit(config_) @@ -2271,7 +2277,9 @@ def start_new_experiment(self, experiment_ID): # @@@ to do: change name to prep # create a new folder utils.ensure_directory_exists(os.path.join(self.base_path, self.experiment_ID)) self.channelConfigurationManager.write_configuration_selected( - self.objectiveStore.current_objective, self.selected_configurations, os.path.join(self.base_path, self.experiment_ID) + "/configurations.xml" + self.objectiveStore.current_objective, + self.selected_configurations, + os.path.join(self.base_path, self.experiment_ID) + "/configurations.xml", ) # save the configuration for the experiment # Prepare acquisition parameters acquisition_parameters = { @@ -2315,9 +2323,13 @@ def set_selected_configurations(self, selected_configurations_name): for configuration_name in selected_configurations_name: self.selected_configurations.append( next( - (config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) - if config.name == configuration_name) + ( + config + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) + if config.name == configuration_name + ) ) ) @@ -2708,7 +2720,7 @@ def start_new_experiment(self, experiment_ID): # @@@ to do: change name to prep utils.ensure_directory_exists(os.path.join(self.base_path, self.experiment_ID)) self.channelConfigurationManager.save_current_configuration_to_path( self.objectiveStore.current_objective, - os.path.join(self.base_path, self.experiment_ID) + "/configurations.xml" + os.path.join(self.base_path, self.experiment_ID) + "/configurations.xml", ) # save the configuration for the experiment except: print("error in making a new folder") @@ -2718,10 +2730,14 @@ def set_selected_configurations(self, selected_configurations_name): self.selected_configurations = [] for configuration_name in selected_configurations_name: self.selected_configurations.append( - next(( - config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) - if config.name == configuration_name) + next( + ( + config + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) + if config.name == configuration_name + ) ) ) @@ -3553,7 +3569,7 @@ def __init__(self): self.all_configs: Dict[ConfigType, Dict[str, ChannelConfig]] = { ConfigType.CHANNEL: {}, ConfigType.CONFOCAL: {}, - ConfigType.WIDEFIELD: {} + ConfigType.WIDEFIELD: {}, } self.active_config_type = ConfigType.CHANNEL if not ENABLE_SPINNING_DISK_CONFOCAL else ConfigType.CONFOCAL @@ -3567,7 +3583,7 @@ def _load_xml_config(self, objective: str, config_type: ConfigType) -> None: if not config_file.exists(): utils_config.generate_default_configuration(str(config_file)) - + xml_content = config_file.read_bytes() self.all_configs[config_type][objective] = ChannelConfig.from_xml(xml_content) @@ -3592,7 +3608,7 @@ def _save_xml_config(self, objective: str, config_type: ConfigType) -> None: if not save_path.parent.exists(): save_path.parent.mkdir(parents=True) - xml_str = config.to_xml(pretty_print=True, encoding='utf-8') + xml_str = config.to_xml(pretty_print=True, encoding="utf-8") save_path.write_bytes(xml_str) def save_configurations(self, objective: str) -> None: @@ -3608,7 +3624,7 @@ def save_configurations(self, objective: str) -> None: def save_current_configuration_to_path(self, objective: str, path: Path) -> None: """Only used in TrackingController. Might be temporary.""" config = self.all_configs[self.active_config_type][objective] - xml_str = config.to_xml(pretty_print=True, encoding='utf-8') + xml_str = config.to_xml(pretty_print=True, encoding="utf-8") path.write_bytes(xml_str) def get_configurations(self, objective: str) -> List[ChannelMode]: @@ -3632,7 +3648,9 @@ def update_configuration(self, objective: str, config_id: str, attr_name: str, v self.save_configurations(objective) - def write_configuration_selected(self, objective: str, selected_configurations: List[ChannelMode], filename: str) -> None: + def write_configuration_selected( + self, objective: str, selected_configurations: List[ChannelMode], filename: str + ) -> None: """Write selected configurations to a file""" config = self.all_configs[self.active_config_type].get(objective) if not config: @@ -3643,7 +3661,7 @@ def write_configuration_selected(self, objective: str, selected_configurations: mode.selected = any(conf.id == mode.id for conf in selected_configurations) # Save to specified file - xml_str = config.to_xml(pretty_print=True, encoding='utf-8') + xml_str = config.to_xml(pretty_print=True, encoding="utf-8") filename = Path(filename) filename.write_bytes(xml_str) @@ -3663,6 +3681,7 @@ def toggle_confocal_widefield(self, confocal: bool) -> None: class LaserAFSettingManager: """Manages JSON-based laser autofocus configurations.""" + def __init__(self): self.autofocus_configurations: Dict[str, LaserAFConfig] = {} # Dict[str, Dict[str, Any]] self.current_profile_path = None @@ -3674,7 +3693,7 @@ def load_configurations(self, objective: str) -> None: """Load autofocus configurations for a specific objective.""" config_file = self.current_profile_path / objective / "laser_af_settings.json" if config_file.exists(): - with open(config_file, 'r') as f: + with open(config_file, "r") as f: config_dict = json.load(f) self.autofocus_configurations[objective] = LaserAFConfig(**config_dict) @@ -3689,7 +3708,7 @@ def save_configurations(self, objective: str) -> None: config_file = objective_path / "laser_af_settings.json" config_dict = self.autofocus_configurations[objective].model_dump(serialize=True) - with open(config_file, 'w') as f: + with open(config_file, "w") as f: json.dump(config_dict, f, indent=4) def get_settings_for_objective(self, objective: str) -> Dict[str, Any]: @@ -3707,21 +3726,25 @@ def update_laser_af_settings(self, objective: str, updates: Dict[str, Any]) -> N config = self.autofocus_configurations[objective] self.autofocus_configurations[objective] = config.model_copy(update=updates) + class ConfigurationManager: """Main configuration manager that coordinates channel and autofocus configurations.""" - def __init__(self, - channel_manager: ChannelConfigurationManager, - laser_af_manager: Optional[LaserAFSettingManager] = None, - base_config_path: Path = Path("acquisition_configurations"), - profile: str = "default_profile"): + + def __init__( + self, + channel_manager: ChannelConfigurationManager, + laser_af_manager: Optional[LaserAFSettingManager] = None, + base_config_path: Path = Path("acquisition_configurations"), + profile: str = "default_profile", + ): super().__init__() self.base_config_path = Path(base_config_path) self.current_profile = profile self.available_profiles = self._get_available_profiles() - + self.channel_manager = channel_manager self.laser_af_manager = laser_af_manager - + self.load_profile(profile) def _get_available_profiles(self) -> List[str]: @@ -4581,7 +4604,7 @@ def __init__( stage: AbstractStage, piezo: Optional[PiezoStage] = None, objectiveStore: Optional[ObjectiveStore] = None, - laserAFSettingManager: Optional[LaserAFSettingManager] = None + laserAFSettingManager: Optional[LaserAFSettingManager] = None, ): QObject.__init__(self) self._log = squid.logging.get_logger(__class__.__name__) @@ -4607,16 +4630,18 @@ def __init__( if self.laserAFSettingManager: self.load_cached_configuration() - def initialize_manual( - self, config: LaserAFConfig) -> None: + def initialize_manual(self, config: LaserAFConfig) -> None: """Initialize laser autofocus with manual parameters.""" - adjusted_config = config.model_copy(update={ - 'x_reference': config.x_reference - config.x_offset, # self.x_reference is relative to the cropped region - 'x_offset': int((config.x_offset // 8) * 8), - 'y_offset': int((config.y_offset // 2) * 2), - 'width': int((config.width // 8) * 8), - 'height': int((config.height // 2) * 2), - }) + adjusted_config = config.model_copy( + update={ + "x_reference": config.x_reference + - config.x_offset, # self.x_reference is relative to the cropped region + "x_offset": int((config.x_offset // 8) * 8), + "y_offset": int((config.y_offset // 2) * 2), + "width": int((config.width // 8) * 8), + "height": int((config.height // 2) * 2), + } + ) self.laser_af_properties = adjusted_config @@ -4624,7 +4649,7 @@ def initialize_manual( self.laser_af_properties.x_offset, self.laser_af_properties.y_offset, self.laser_af_properties.width, - self.laser_af_properties.height + self.laser_af_properties.height, ) self.is_initialized = True @@ -4632,8 +4657,7 @@ def initialize_manual( # Update cache if objective store and laser_af_settings is available if self.objectiveStore and self.laserAFSettingManager and self.objectiveStore.current_objective: self.laserAFSettingManager.update_laser_af_settings( - self.objectiveStore.current_objective, - config.model_dump() + self.objectiveStore.current_objective, config.model_dump() ) def load_cached_configuration(self): @@ -4686,11 +4710,13 @@ def initialize_auto(self) -> bool: self.microcontroller.wait_till_operation_is_completed() # Set up ROI around spot - config = self.laser_af_properties.model_copy(update={ - 'x_offset': x - self.laser_af_properties.width / 2, - 'y_offset': y - self.laser_af_properties.height / 2, - 'x_reference': x - }) + config = self.laser_af_properties.model_copy( + update={ + "x_offset": x - self.laser_af_properties.width / 2, + "y_offset": y - self.laser_af_properties.height / 2, + "x_reference": x, + } + ) self._log.info(f"Laser spot location on the full sensor is ({int(x)}, {int(y)})") self.initialize_manual(config) @@ -4763,16 +4789,14 @@ def _calibrate_pixel_to_um(self) -> bool: self._log.info(f"Pixel to um conversion factor is {pixel_to_um:.3f} um/pixel") # Update config with new calibration values - self.laser_af_properties = self.laser_af_properties.model_copy(update={ - 'pixel_to_um': pixel_to_um, - 'x_reference': (x1 + x0) / 2 - }) + self.laser_af_properties = self.laser_af_properties.model_copy( + update={"pixel_to_um": pixel_to_um, "x_reference": (x1 + x0) / 2} + ) # Update cache if self.objectiveStore and self.laserAFSettingManager: self.laserAFSettingManager.update_laser_af_settings( - self.objectiveStore.current_objective, - self.laser_af_properties.model_dump() + self.objectiveStore.current_objective, self.laser_af_properties.model_dump() ) return True @@ -4896,9 +4920,7 @@ def set_reference(self) -> bool: return False x, y = result - self.laser_af_properties = self.laser_af_properties.model_copy(update={ - 'x_reference': x - }) + self.laser_af_properties = self.laser_af_properties.model_copy(update={"x_reference": x}) # Store cropped and normalized reference image center_y = int(reference_image.shape[0] / 2) @@ -4914,9 +4936,9 @@ def set_reference(self) -> bool: self._log.info(f"Set reference position to ({x:.1f}, {y:.1f})") # Update cache - self.laserAFSettingManager.update_laser_af_settings(self.objectiveStore.current_objective, { - 'x_reference': x + self.laser_af_properties.x_offset - }) + self.laserAFSettingManager.update_laser_af_settings( + self.objectiveStore.current_objective, {"x_reference": x + self.laser_af_properties.x_offset} + ) self.laserAFSettingManager.save_configurations(self.objectiveStore.current_objective) return True @@ -5019,7 +5041,9 @@ def _get_laser_spot_centroid(self) -> Optional[Tuple[float, float]]: # calculate centroid result = utils.find_spot_location(image, mode=self.laser_af_properties.spot_detection_mode) if result is None: - self._log.warning(f"No spot detected in frame {i+1}/{self.laser_af_properties.laser_af_averaging_n}") + self._log.warning( + f"No spot detected in frame {i+1}/{self.laser_af_properties.laser_af_averaging_n}" + ) continue x, y = result @@ -5028,7 +5052,9 @@ def _get_laser_spot_centroid(self) -> Optional[Tuple[float, float]]: successful_detections += 1 except Exception as e: - self._log.error(f"Error processing frame {i+1}/{self.laser_af_properties.laser_af_averaging_n}: {str(e)}") + self._log.error( + f"Error processing frame {i+1}/{self.laser_af_properties.laser_af_averaging_n}: {str(e)}" + ) continue # optionally display the image @@ -5078,4 +5104,4 @@ def get_image(self) -> Optional[np.ndarray]: finally: # turn off the laser self.microcontroller.turn_off_AF_laser() - self.microcontroller.wait_till_operation_is_completed() \ No newline at end of file + self.microcontroller.wait_till_operation_is_completed() diff --git a/software/control/gui_hcs.py b/software/control/gui_hcs.py index 05534db6..3be89164 100644 --- a/software/control/gui_hcs.py +++ b/software/control/gui_hcs.py @@ -236,7 +236,9 @@ def loadObjects(self, is_simulation): self.laserAFSettingManager = core.LaserAFSettingManager() else: self.laserAFSettingManager = None - self.configurationManager = core.ConfigurationManager(channel_manager=self.channelConfigurationManager, laser_af_manager=self.laserAFSettingManager) + self.configurationManager = core.ConfigurationManager( + channel_manager=self.channelConfigurationManager, laser_af_manager=self.laserAFSettingManager + ) self.contrastManager = core.ContrastManager() self.streamHandler = core.StreamHandler() @@ -309,7 +311,7 @@ def loadObjects(self, is_simulation): self.stage, self.piezo, self.objectiveStore, - self.laserAFSettingManager + self.laserAFSettingManager, ) if USE_SQUID_FILTERWHEEL: @@ -547,7 +549,9 @@ def waitForMicrocontroller(self, timeout=5.0, error_message=None): def loadWidgets(self): # Initialize all GUI widgets if ENABLE_SPINNING_DISK_CONFOCAL: - self.spinningDiskConfocalWidget = widgets.SpinningDiskConfocalWidget(self.xlight, self.channelConfigurationManager) + self.spinningDiskConfocalWidget = widgets.SpinningDiskConfocalWidget( + self.xlight, self.channelConfigurationManager + ) if ENABLE_NL5: import control.NL5Widget as NL5Widget @@ -684,7 +688,9 @@ def loadWidgets(self): show_configurations=TRACKING_SHOW_MICROSCOPE_CONFIGURATIONS, ) if ENABLE_STITCHER: - self.stitcherWidget = widgets.StitcherWidget(self.objectiveStore, self.channelConfigurationManager, self.contrastManager) + self.stitcherWidget = widgets.StitcherWidget( + self.objectiveStore, self.channelConfigurationManager, self.contrastManager + ) self.recordTabWidget = QTabWidget() self.setupRecordTabWidget() @@ -978,19 +984,20 @@ def makeConnections(self): self.wellSelectionWidget.signal_wellSelected.connect(self.wellplateMultiPointWidget.update_well_coordinates) self.objectivesWidget.signal_objective_changed.connect(self.wellplateMultiPointWidget.update_coordinates) - self.objectivesWidget.signal_objective_changed.connect(lambda: self.liveControlWidget.update_microscope_mode_by_name( - self.liveControlWidget.currentConfiguration.name - )) + self.objectivesWidget.signal_objective_changed.connect( + lambda: self.liveControlWidget.update_microscope_mode_by_name( + self.liveControlWidget.currentConfiguration.name + ) + ) if SUPPORT_LASER_AUTOFOCUS: + def connect_objective_changed_laser_af(): self.laserAutofocusController.on_objective_changed() self.laserAutofocusControlWidget.update_init_state() self.laserAutofocusSettingWidget.update_values() - self.objectivesWidget.signal_objective_changed.connect( - connect_objective_changed_laser_af - ) + self.objectivesWidget.signal_objective_changed.connect(connect_objective_changed_laser_af) self.laserAutofocusSettingWidget.signal_newExposureTime.connect( self.cameraSettingWidget_focus_camera.set_exposure_time ) @@ -1001,8 +1008,12 @@ def connect_objective_changed_laser_af(): self.laserAutofocusControlWidget.update_init_state ) - self.laserAutofocusSettingWidget.update_exposure_time(self.laserAutofocusSettingWidget.exposure_spinbox.value()) - self.laserAutofocusSettingWidget.update_analog_gain(self.laserAutofocusSettingWidget.analog_gain_spinbox.value()) + self.laserAutofocusSettingWidget.update_exposure_time( + self.laserAutofocusSettingWidget.exposure_spinbox.value() + ) + self.laserAutofocusSettingWidget.update_analog_gain( + self.laserAutofocusSettingWidget.analog_gain_spinbox.value() + ) self.streamHandler_focus_camera.signal_new_frame_received.connect( self.liveController_focus_camera.on_new_frame diff --git a/software/control/utils.py b/software/control/utils.py index 5b9a009b..06b4f773 100644 --- a/software/control/utils.py +++ b/software/control/utils.py @@ -395,4 +395,4 @@ def get_script_dir(follow_symlinks=True): return f"{repo.head.object.hexsha} (dirty={repo.is_dirty()})" except git.GitError as e: _log.warning(f"Failed to get script git repo info: {e}") - return None \ No newline at end of file + return None diff --git a/software/control/utils_channel.py b/software/control/utils_channel.py index f2cf350a..22709d7e 100644 --- a/software/control/utils_channel.py +++ b/software/control/utils_channel.py @@ -1,5 +1,6 @@ from control._def import CHANNEL_COLORS_MAP + def extract_wavelength_from_config_name(name): # Split the string and find the wavelength number immediately after "Fluorescence" parts = name.split() @@ -14,5 +15,7 @@ def extract_wavelength_from_config_name(name): def get_channel_color(channel): - channel_info = CHANNEL_COLORS_MAP.get(extract_wavelength_from_config_name(channel), {"hex": 0xFFFFFF, "name": "gray"}) - return channel_info["hex"] \ No newline at end of file + channel_info = CHANNEL_COLORS_MAP.get( + extract_wavelength_from_config_name(channel), {"hex": 0xFFFFFF, "name": "gray"} + ) + return channel_info["hex"] diff --git a/software/control/utils_config.py b/software/control/utils_config.py index 2dfa6028..71cc8ccd 100644 --- a/software/control/utils_config.py +++ b/software/control/utils_config.py @@ -3,17 +3,31 @@ from typing import List, Optional from pathlib import Path import control.utils_channel as utils_channel -from control._def import (FOCUS_CAMERA_EXPOSURE_TIME_MS, FOCUS_CAMERA_ANALOG_GAIN, LASER_AF_RANGE, - LASER_AF_AVERAGING_N, LASER_AF_CROP_WIDTH, LASER_AF_CROP_HEIGHT, - LASER_AF_SPOT_DETECTION_MODE, DISPLACEMENT_SUCCESS_WINDOW_UM, - SPOT_CROP_SIZE, CORRELATION_THRESHOLD, PIXEL_TO_UM_CALIBRATION_DISTANCE, - LASER_AF_Y_WINDOW, LASER_AF_X_WINDOW, LASER_AF_MIN_PEAK_WIDTH, LASER_AF_MIN_PEAK_DISTANCE, - LASER_AF_MIN_PEAK_PROMINENCE, LASER_AF_SPOT_SPACING) +from control._def import ( + FOCUS_CAMERA_EXPOSURE_TIME_MS, + FOCUS_CAMERA_ANALOG_GAIN, + LASER_AF_RANGE, + LASER_AF_AVERAGING_N, + LASER_AF_CROP_WIDTH, + LASER_AF_CROP_HEIGHT, + LASER_AF_SPOT_DETECTION_MODE, + DISPLACEMENT_SUCCESS_WINDOW_UM, + SPOT_CROP_SIZE, + CORRELATION_THRESHOLD, + PIXEL_TO_UM_CALIBRATION_DISTANCE, + LASER_AF_Y_WINDOW, + LASER_AF_X_WINDOW, + LASER_AF_MIN_PEAK_WIDTH, + LASER_AF_MIN_PEAK_DISTANCE, + LASER_AF_MIN_PEAK_PROMINENCE, + LASER_AF_SPOT_SPACING, +) from control.utils import SpotDetectionMode class LaserAFConfig(BaseModel): """Pydantic model for laser autofocus configuration""" + x_offset: float = 0.0 y_offset: float = 0.0 width: int = LASER_AF_CROP_WIDTH @@ -21,10 +35,14 @@ class LaserAFConfig(BaseModel): pixel_to_um: float = 1 x_reference: float = 0.0 laser_af_averaging_n: int = LASER_AF_AVERAGING_N - displacement_success_window_um: float = DISPLACEMENT_SUCCESS_WINDOW_UM # if the displacement is within this window, we consider the move successful + displacement_success_window_um: float = ( + DISPLACEMENT_SUCCESS_WINDOW_UM # if the displacement is within this window, we consider the move successful + ) spot_crop_size: int = SPOT_CROP_SIZE # Size of region to crop around spot for correlation correlation_threshold: float = CORRELATION_THRESHOLD # Minimum correlation coefficient for valid alignment - pixel_to_um_calibration_distance: float = PIXEL_TO_UM_CALIBRATION_DISTANCE # Distance moved in um during calibration + pixel_to_um_calibration_distance: float = ( + PIXEL_TO_UM_CALIBRATION_DISTANCE # Distance moved in um during calibration + ) laser_af_range: float = LASER_AF_RANGE # Maximum reasonable displacement in um focus_camera_exposure_time_ms: float = FOCUS_CAMERA_EXPOSURE_TIME_MS focus_camera_analog_gain: float = FOCUS_CAMERA_ANALOG_GAIN @@ -36,7 +54,7 @@ class LaserAFConfig(BaseModel): min_peak_prominence: float = LASER_AF_MIN_PEAK_PROMINENCE # Minimum peak prominence spot_spacing: float = LASER_AF_SPOT_SPACING # Expected spacing between spots - @field_validator('spot_detection_mode', mode='before') + @field_validator("spot_detection_mode", mode="before") @classmethod def validate_spot_detection_mode(cls, v): """Convert string to SpotDetectionMode enum if needed""" @@ -48,49 +66,55 @@ def model_dump(self, serialize=False, **kwargs): """Ensure proper serialization of enums to strings""" data = super().model_dump(**kwargs) if serialize: - if 'spot_detection_mode' in data and isinstance(data['spot_detection_mode'], SpotDetectionMode): - data['spot_detection_mode'] = data['spot_detection_mode'].value + if "spot_detection_mode" in data and isinstance(data["spot_detection_mode"], SpotDetectionMode): + data["spot_detection_mode"] = data["spot_detection_mode"].value return data -class ChannelMode(BaseXmlModel, tag='mode'): + +class ChannelMode(BaseXmlModel, tag="mode"): """Channel configuration model""" - id: str = attr(name='ID') - name: str = attr(name='Name') - exposure_time: float = attr(name='ExposureTime') - analog_gain: float = attr(name='AnalogGain') - illumination_source: int = attr(name='IlluminationSource') - illumination_intensity: float = attr(name='IlluminationIntensity') - camera_sn: Optional[str] = attr(name='CameraSN', default=None) - z_offset: float = attr(name='ZOffset') - emission_filter_position: int = attr(name='EmissionFilterPosition', default=1) - selected: bool = attr(name='Selected', default=False) + + id: str = attr(name="ID") + name: str = attr(name="Name") + exposure_time: float = attr(name="ExposureTime") + analog_gain: float = attr(name="AnalogGain") + illumination_source: int = attr(name="IlluminationSource") + illumination_intensity: float = attr(name="IlluminationIntensity") + camera_sn: Optional[str] = attr(name="CameraSN", default=None) + z_offset: float = attr(name="ZOffset") + emission_filter_position: int = attr(name="EmissionFilterPosition", default=1) + selected: bool = attr(name="Selected", default=False) color: Optional[str] = None # Not stored in XML but computed from name def __init__(self, **data): super().__init__(**data) self.color = utils_channel.get_channel_color(self.name) -class ChannelConfig(BaseXmlModel, tag='modes'): + +class ChannelConfig(BaseXmlModel, tag="modes"): """Root configuration file model""" - modes: List[ChannelMode] = element(tag='mode') + + modes: List[ChannelMode] = element(tag="mode") + def get_attr_name(attr_name: str) -> str: """Get the attribute name for a given configuration attribute""" attr_map = { - 'ID': 'id', - 'Name': 'name', - 'ExposureTime': 'exposure_time', - 'AnalogGain': 'analog_gain', - 'IlluminationSource': 'illumination_source', - 'IlluminationIntensity': 'illumination_intensity', - 'CameraSN': 'camera_sn', - 'ZOffset': 'z_offset', - 'EmissionFilterPosition': 'emission_filter_position', - 'Selected': 'selected', - 'Color': 'color' + "ID": "id", + "Name": "name", + "ExposureTime": "exposure_time", + "AnalogGain": "analog_gain", + "IlluminationSource": "illumination_source", + "IlluminationIntensity": "illumination_intensity", + "CameraSN": "camera_sn", + "ZOffset": "z_offset", + "EmissionFilterPosition": "emission_filter_position", + "Selected": "selected", + "Color": "color", } return attr_map[attr_name] + def generate_default_configuration(filename: str) -> None: """Generate default configuration using Pydantic models""" default_modes = [ @@ -102,7 +126,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=0, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="4", @@ -112,7 +136,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=3, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="5", @@ -122,7 +146,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=11, illumination_intensity=100, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="6", @@ -132,7 +156,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=12, illumination_intensity=100, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="7", @@ -142,7 +166,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=13, illumination_intensity=100, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="8", @@ -152,7 +176,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=14, illumination_intensity=100, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="12", @@ -162,7 +186,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=15, illumination_intensity=100, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="9", @@ -172,7 +196,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=4, illumination_intensity=20, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), # Commented out modes for reference # ChannelMode( @@ -203,7 +227,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=1, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="3", @@ -213,7 +237,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=2, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="12", @@ -223,7 +247,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=7, illumination_intensity=20, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="13", @@ -233,7 +257,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=8, illumination_intensity=20, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="14", @@ -243,7 +267,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=0, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="15", @@ -253,7 +277,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=0, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="16", @@ -263,7 +287,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=0, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="21", @@ -273,7 +297,7 @@ def generate_default_configuration(filename: str) -> None: illumination_source=0, illumination_intensity=5, camera_sn="", - z_offset=0.0 + z_offset=0.0, ), ChannelMode( id="20", @@ -283,15 +307,15 @@ def generate_default_configuration(filename: str) -> None: illumination_source=6, illumination_intensity=0, camera_sn="", - z_offset=0.0 - ) + z_offset=0.0, + ), ] config = ChannelConfig(modes=default_modes) - xml_str = config.to_xml(pretty_print=True, encoding='utf-8') - + xml_str = config.to_xml(pretty_print=True, encoding="utf-8") + # Write to file path = Path(filename) if not path.parent.exists(): path.parent.mkdir(parents=True) - path.write_bytes(xml_str) \ No newline at end of file + path.write_bytes(xml_str) diff --git a/software/control/widgets.py b/software/control/widgets.py index 567e0702..6851d9ad 100644 --- a/software/control/widgets.py +++ b/software/control/widgets.py @@ -66,7 +66,8 @@ def __init__(self, title): def toggle_content(self, state): self.content_widget.setVisible(state) -''' + +""" # Planning to replace this with a better design class ConfigEditorForAcquisitions(QDialog): def __init__(self, configManager, only_z_offset=True): @@ -204,7 +205,8 @@ def load_config_from_file(self, only_z_offset=None): self.scroll_area_widget.setLayout(self.scroll_area_layout) self.scroll_area.setWidget(self.scroll_area_widget) self.init_ui(only_z_offset) -''' +""" + class ConfigEditor(QDialog): def __init__(self, config): @@ -388,7 +390,9 @@ def init_ui(self): exposure_layout = QHBoxLayout() exposure_layout.addWidget(QLabel("Focus Camera Exposure (ms):")) self.exposure_spinbox = QDoubleSpinBox() - self.exposure_spinbox.setRange(self.liveController.camera.EXPOSURE_TIME_MS_MIN, self.liveController.camera.EXPOSURE_TIME_MS_MAX) + self.exposure_spinbox.setRange( + self.liveController.camera.EXPOSURE_TIME_MS_MIN, self.liveController.camera.EXPOSURE_TIME_MS_MAX + ) self.exposure_spinbox.setValue(self.laserAutofocusController.laser_af_properties.focus_camera_exposure_time_ms) exposure_layout.addWidget(self.exposure_spinbox) @@ -415,52 +419,44 @@ def init_ui(self): self.spinboxes = {} # Averaging - self._add_spinbox(settings_layout, "Laser AF Averaging N:", - 'laser_af_averaging_n', 1, 100, 0) + self._add_spinbox(settings_layout, "Laser AF Averaging N:", "laser_af_averaging_n", 1, 100, 0) # Displacement window - self._add_spinbox(settings_layout, "Displacement Success Window (μm):", - 'displacement_success_window_um', 0.1, 10.0, 2) + self._add_spinbox( + settings_layout, "Displacement Success Window (μm):", "displacement_success_window_um", 0.1, 10.0, 2 + ) # Spot crop size - self._add_spinbox(settings_layout, "Spot Crop Size (pixels):", - 'spot_crop_size', 1, 500, 0) + self._add_spinbox(settings_layout, "Spot Crop Size (pixels):", "spot_crop_size", 1, 500, 0) # Correlation threshold - self._add_spinbox(settings_layout, "Correlation Threshold:", - 'correlation_threshold', 0.1, 1.0, 2) + self._add_spinbox(settings_layout, "Correlation Threshold:", "correlation_threshold", 0.1, 1.0, 2) # Calibration distance - self._add_spinbox(settings_layout, "Calibration Distance (μm):", - 'pixel_to_um_calibration_distance', 0.1, 20.0, 2) + self._add_spinbox( + settings_layout, "Calibration Distance (μm):", "pixel_to_um_calibration_distance", 0.1, 20.0, 2 + ) # AF Range - self._add_spinbox(settings_layout, "Laser AF Range (μm):", - 'laser_af_range', 1, 1000, 1) - + self._add_spinbox(settings_layout, "Laser AF Range (μm):", "laser_af_range", 1, 1000, 1) + # Y window - self._add_spinbox(settings_layout, "Y Window (pixels):", - 'y_window', 1, 500, 0) + self._add_spinbox(settings_layout, "Y Window (pixels):", "y_window", 1, 500, 0) # X window - self._add_spinbox(settings_layout, "X Window (pixels):", - 'x_window', 1, 500, 0) + self._add_spinbox(settings_layout, "X Window (pixels):", "x_window", 1, 500, 0) # Min peak width - self._add_spinbox(settings_layout, "Min Peak Width:", - 'min_peak_width', 1, 100, 1) + self._add_spinbox(settings_layout, "Min Peak Width:", "min_peak_width", 1, 100, 1) # Min peak distance - self._add_spinbox(settings_layout, "Min Peak Distance:", - 'min_peak_distance', 1, 100, 1) + self._add_spinbox(settings_layout, "Min Peak Distance:", "min_peak_distance", 1, 100, 1) # Min peak prominence - self._add_spinbox(settings_layout, "Min Peak Prominence:", - 'min_peak_prominence', 0.01, 1.0, 2) + self._add_spinbox(settings_layout, "Min Peak Prominence:", "min_peak_prominence", 0.01, 1.0, 2) # Spot spacing - self._add_spinbox(settings_layout, "Spot Spacing (pixels):", - 'spot_spacing', 1, 1000, 1) + self._add_spinbox(settings_layout, "Spot Spacing (pixels):", "spot_spacing", 1, 1000, 1) # Spot detection mode combo box spot_mode_layout = QHBoxLayout() @@ -496,8 +492,9 @@ def init_ui(self): self.analog_gain_spinbox.valueChanged.connect(self.update_analog_gain) self.apply_button.clicked.connect(self.apply_settings) - def _add_spinbox(self, layout, label: str, property_name: str, - min_val: float, max_val: float, decimals: int) -> None: + def _add_spinbox( + self, layout, label: str, property_name: str, min_val: float, max_val: float, decimals: int + ) -> None: """Helper method to add a labeled spinbox to the layout.""" box_layout = QHBoxLayout() box_layout.addWidget(QLabel(label)) @@ -525,7 +522,7 @@ def toggle_live(self, pressed): def update_exposure_time(self, value): self.signal_newExposureTime.emit(value) - + def update_analog_gain(self, value): self.signal_newAnalogGain.emit(value) @@ -537,13 +534,9 @@ def update_values(self): spinbox.setValue(current_value) # Update exposure and gain - self.exposure_spinbox.setValue( - self.laserAutofocusController.laser_af_properties.focus_camera_exposure_time_ms - ) - self.analog_gain_spinbox.setValue( - self.laserAutofocusController.laser_af_properties.focus_camera_analog_gain - ) - + self.exposure_spinbox.setValue(self.laserAutofocusController.laser_af_properties.focus_camera_exposure_time_ms) + self.analog_gain_spinbox.setValue(self.laserAutofocusController.laser_af_properties.focus_camera_analog_gain) + # Update spot detection mode current_mode = self.laserAutofocusController.laser_af_properties.spot_detection_mode index = self.spot_mode_combo.findData(current_mode) @@ -551,22 +544,22 @@ def update_values(self): self.spot_mode_combo.setCurrentIndex(index) def apply_settings(self): - updates={ - 'laser_af_averaging_n': int(self.spinboxes['laser_af_averaging_n'].value()), - 'displacement_success_window_um': self.spinboxes['displacement_success_window_um'].value(), - 'spot_crop_size': int(self.spinboxes['spot_crop_size'].value()), - 'correlation_threshold': self.spinboxes['correlation_threshold'].value(), - 'pixel_to_um_calibration_distance': self.spinboxes['pixel_to_um_calibration_distance'].value(), - 'laser_af_range': self.spinboxes['laser_af_range'].value(), - 'spot_detection_mode': self.spot_mode_combo.currentData(), - 'y_window': int(self.spinboxes['y_window'].value()), - 'x_window': int(self.spinboxes['x_window'].value()), - 'min_peak_width': self.spinboxes['min_peak_width'].value(), - 'min_peak_distance': self.spinboxes['min_peak_distance'].value(), - 'min_peak_prominence': self.spinboxes['min_peak_prominence'].value(), - 'spot_spacing': self.spinboxes['spot_spacing'].value(), - 'focus_camera_exposure_time_ms': self.exposure_spinbox.value(), - 'focus_camera_analog_gain': self.analog_gain_spinbox.value(), + updates = { + "laser_af_averaging_n": int(self.spinboxes["laser_af_averaging_n"].value()), + "displacement_success_window_um": self.spinboxes["displacement_success_window_um"].value(), + "spot_crop_size": int(self.spinboxes["spot_crop_size"].value()), + "correlation_threshold": self.spinboxes["correlation_threshold"].value(), + "pixel_to_um_calibration_distance": self.spinboxes["pixel_to_um_calibration_distance"].value(), + "laser_af_range": self.spinboxes["laser_af_range"].value(), + "spot_detection_mode": self.spot_mode_combo.currentData(), + "y_window": int(self.spinboxes["y_window"].value()), + "x_window": int(self.spinboxes["x_window"].value()), + "min_peak_width": self.spinboxes["min_peak_width"].value(), + "min_peak_distance": self.spinboxes["min_peak_distance"].value(), + "min_peak_prominence": self.spinboxes["min_peak_prominence"].value(), + "spot_spacing": self.spinboxes["spot_spacing"].value(), + "focus_camera_exposure_time_ms": self.exposure_spinbox.value(), + "focus_camera_analog_gain": self.analog_gain_spinbox.value(), } self.laserAutofocusController.set_laser_af_properties(updates) self.laserAutofocusController.initialize_auto() @@ -575,12 +568,14 @@ def apply_settings(self): def update_calibration_label(self): # Clear previous calibration label if it exists - if hasattr(self, 'calibration_label'): + if hasattr(self, "calibration_label"): self.calibration_label.deleteLater() # Create and add new calibration label self.calibration_label = QLabel() - self.calibration_label.setText(f"Calibration Result: {self.laserAutofocusController.laser_af_properties.pixel_to_um:.3f} pixels/um") + self.calibration_label.setText( + f"Calibration Result: {self.laserAutofocusController.laser_af_properties.pixel_to_um:.3f} pixels/um" + ) self.layout().addWidget(self.calibration_label) @@ -1090,18 +1085,13 @@ class ProfileWidget(QFrame): signal_profile_changed = Signal() - def __init__( - self, - configurationManager, - *args, - **kwargs - ): + def __init__(self, configurationManager, *args, **kwargs): super().__init__(*args, **kwargs) self.configurationManager = configurationManager - + self.setFrameStyle(QFrame.Panel | QFrame.Raised) self.setup_ui() - + def setup_ui(self): # Create widgets self.dropdown_profiles = QComboBox() @@ -1123,7 +1113,7 @@ def setup_ui(self): layout.addWidget(self.dropdown_profiles, 2) layout.addWidget(self.btn_loadProfile) layout.addWidget(self.btn_newProfile) - + self.setLayout(layout) def load_profile(self): @@ -1136,13 +1126,7 @@ def load_profile(self): def create_new_profile(self): """Create a new profile with current configurations.""" dialog = QInputDialog() - profile_name, ok = dialog.getText( - self, - "New Profile", - "Enter new profile name:", - QLineEdit.Normal, - "" - ) + profile_name, ok = dialog.getText(self, "New Profile", "Enter new profile name:", QLineEdit.Normal, "") if ok and profile_name: try: @@ -1192,7 +1176,9 @@ def __init__( self.streamHandler.set_display_fps(self.fps_display) self.triggerMode = TriggerMode.SOFTWARE - self.currentConfiguration = self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective)[0] + self.currentConfiguration = self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + )[0] self.add_components(show_trigger_options, show_display_options, show_autolevel, autolevel, stretch) self.setFrameStyle(QFrame.Panel | QFrame.Raised) @@ -1218,7 +1204,9 @@ def add_components(self, show_trigger_options, show_display_options, show_autole # line 2: choose microscope mode / toggle live mode self.dropdown_modeSelection = QComboBox() - for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.dropdown_modeSelection.addItems([microscope_configuration.name]) self.dropdown_modeSelection.setCurrentText(self.currentConfiguration.name) self.dropdown_modeSelection.setSizePolicy(sizePolicy) @@ -1392,7 +1380,9 @@ def refresh_mode_list(self): # Update the mode selection dropdown self.dropdown_modeSelection.blockSignals(True) self.dropdown_modeSelection.clear() - for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.dropdown_modeSelection.addItem(microscope_configuration.name) self.dropdown_modeSelection.blockSignals(False) @@ -1406,10 +1396,12 @@ def update_microscope_mode_by_name(self, current_microscope_mode_name): self.currentConfiguration = next( ( config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) if config.name == current_microscope_mode_name - ), - None, + ), + None, ) self.signal_live_configuration.emit(self.currentConfiguration) # update the microscope to the current configuration @@ -1426,13 +1418,17 @@ def update_trigger_mode(self): def update_config_exposure_time(self, new_value): if self.is_switching_mode == False: self.currentConfiguration.exposure_time = new_value - self.channelConfigurationManager.update_configuration(self.objectiveStore.current_objective, self.currentConfiguration.id, "ExposureTime", new_value) + self.channelConfigurationManager.update_configuration( + self.objectiveStore.current_objective, self.currentConfiguration.id, "ExposureTime", new_value + ) self.signal_newExposureTime.emit(new_value) def update_config_analog_gain(self, new_value): if self.is_switching_mode == False: self.currentConfiguration.analog_gain = new_value - self.channelConfigurationManager.update_configuration(self.objectiveStore.current_objective, self.currentConfiguration.id, "AnalogGain", new_value) + self.channelConfigurationManager.update_configuration( + self.objectiveStore.current_objective, self.currentConfiguration.id, "AnalogGain", new_value + ) self.signal_newAnalogGain.emit(new_value) def update_config_illumination_intensity(self, new_value): @@ -2374,7 +2370,9 @@ def add_components(self): self.entry_Nt.setFixedWidth(max_num_width) self.list_configurations = QListWidget() - for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.list_configurations.addItems([microscope_configuration.name]) self.list_configurations.setSelectionMode( QAbstractItemView.MultiSelection @@ -3533,7 +3531,9 @@ def add_components(self): self.combobox_z_stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.list_configurations = QListWidget() - for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.list_configurations.addItems([microscope_configuration.name]) self.list_configurations.setSelectionMode(QAbstractItemView.MultiSelection) @@ -4770,7 +4770,9 @@ def initControlWidgets(self, show_trigger_options, show_display_options, show_au # Microscope Configuration self.dropdown_modeSelection = QComboBox() - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.dropdown_modeSelection.addItem(config.name) self.dropdown_modeSelection.setCurrentText(self.live_configuration.name) self.dropdown_modeSelection.currentTextChanged.connect(self.update_microscope_mode_by_name) @@ -5029,7 +5031,9 @@ def update_microscope_mode_by_name(self, current_microscope_mode_name): self.live_configuration = next( ( config - for config in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective) + for config in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ) if config.name == current_microscope_mode_name ), None, @@ -5042,17 +5046,23 @@ def update_microscope_mode_by_name(self, current_microscope_mode_name): def update_config_exposure_time(self, new_value): self.live_configuration.exposure_time = new_value - self.channelConfigurationManager.update_configuration(self.objectiveStore.current_objective, self.live_configuration.id, "ExposureTime", new_value) + self.channelConfigurationManager.update_configuration( + self.objectiveStore.current_objective, self.live_configuration.id, "ExposureTime", new_value + ) self.signal_newExposureTime.emit(new_value) def update_config_analog_gain(self, new_value): self.live_configuration.analog_gain = new_value - self.channelConfigurationManager.update_configuration(self.objectiveStore.current_objective, self.live_configuration.id, "AnalogGain", new_value) + self.channelConfigurationManager.update_configuration( + self.objectiveStore.current_objective, self.live_configuration.id, "AnalogGain", new_value + ) self.signal_newAnalogGain.emit(new_value) def update_config_illumination_intensity(self, new_value): self.live_configuration.illumination_intensity = new_value - self.channelConfigurationManager.update_configuration(self.objectiveStore.current_objective, self.live_configuration.id, "IlluminationIntensity", new_value) + self.channelConfigurationManager.update_configuration( + self.objectiveStore.current_objective, self.live_configuration.id, "IlluminationIntensity", new_value + ) self.liveController.set_illumination(self.live_configuration.illumination_source, new_value) def update_resolution_scaling(self, value): @@ -5849,7 +5859,9 @@ def add_components(self, show_configurations): self.entry_tracking_interval.setValue(0) self.list_configurations = QListWidget() - for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective(self.objectiveStore.current_objective): + for microscope_configuration in self.channelConfigurationManager.get_channel_configurations_for_objective( + self.objectiveStore.current_objective + ): self.list_configurations.addItems([microscope_configuration.name]) self.list_configurations.setSelectionMode( QAbstractItemView.MultiSelection diff --git a/software/main_hcs.py b/software/main_hcs.py index 0b1a7de7..65ec35bf 100644 --- a/software/main_hcs.py +++ b/software/main_hcs.py @@ -34,12 +34,13 @@ def show_config(cfp, configpath, main_gui): config_widget = ConfigEditorBackwardsCompatible(cfp, configpath, main_gui) config_widget.exec_() -''' + +""" # Planning to replace this with a better design def show_acq_config(cfm): acq_config_widget = ConfigEditorForAcquisitions(cfm) acq_config_widget.exec_() -''' +""" if __name__ == "__main__": parser = argparse.ArgumentParser() @@ -75,14 +76,14 @@ def show_acq_config(cfm): win = gui.HighContentScreeningGui(is_simulation=args.simulation, live_only_mode=args.live_only) - ''' + """ # Planning to replace this with a better design acq_config_action = QAction("Acquisition Settings", win) acq_config_action.triggered.connect(lambda: show_acq_config(win.configurationManager)) - ''' + """ file_menu = QMenu("File", win) - #file_menu.addAction(acq_config_action) + # file_menu.addAction(acq_config_action) if not legacy_config: config_action = QAction("Microscope Settings", win)