diff --git a/magmap/gui/visualizer.py b/magmap/gui/visualizer.py index 72be1fbe4..1a85637ab 100644 --- a/magmap/gui/visualizer.py +++ b/magmap/gui/visualizer.py @@ -261,7 +261,6 @@ class Visualization(HasTraits): # File selection _filename = File # file browser - _ignore_filename = False # ignore file update trigger _channel_names = Instance(TraitsList) _channel = List # selected channels, 0-based @@ -792,10 +791,11 @@ def __init__(self): self._drawn_offset = self._curr_offset() # setup interface for image + self._ignore_filename = False # ignore file update trigger + self._reset_filename = True # reset when updating loaded image if config.filename: # show image filename in file selector without triggering update - self._ignore_filename = True - self._filename = config.filename + self.update_filename(config.filename, True, False) # create figs after applying Matplotlib style and theme rc_params = None @@ -829,6 +829,10 @@ def __init__(self): self._imgadj_max_ignore_update = False # set up rest of registered images during image setup + + # dictionary of registered image suffix without ext to suffix with + # ext of a matching existing file + self._reg_img_names: OrderedDict[str, str] = OrderedDict() self._main_img_names_avail = TraitsList() self._main_img_names = TraitsList() self._labels_img_names = TraitsList() @@ -1541,23 +1545,25 @@ def _setup_for_image(self): else [config.roi_size]) # find matching registered images to populate dropdowns - main_img_names_avail = [] + self._reg_img_names = OrderedDict() for reg_name in config.RegNames: # check for potential registered image files reg_path = sitk_io.read_sitk(sitk_io.reg_out_path( config.filename, reg_name.value), dryrun=True)[1] if reg_path: - # add to list of available suffixes - main_img_names_avail.append( - f"{os.path.splitext(reg_name.value)[0]}" - f"{os.path.splitext(reg_path)[1]}") - self._labels_img_names.selections = list(main_img_names_avail) + # add to list of available suffixes, storing the found + # extension to load directly and save to same ext + name = libmag.get_filename_without_ext(reg_name.value) + self._reg_img_names[name] = ( + f"{name}{libmag.splitext(reg_path)[1]}") + self._labels_img_names.selections = list(self._reg_img_names.keys()) self._labels_img_names.selections.insert(0, "") # set any registered names based on loaded images, defaulting to # image5d and no labels main_suffixes = [self._MAIN_IMG_NAME_DEFAULT] labels_suffix = self._labels_img_names.selections[0] + main_img_names_avail = list(self._reg_img_names.keys()) if config.reg_suffixes: # use registered suffixes without ext, using first suffix # of each type @@ -1566,15 +1572,17 @@ def _setup_for_image(self): if not libmag.is_seq(suffixes): suffixes = [suffixes] for suffix in suffixes: - if suffix in main_img_names_avail: + suffix_stem = libmag.get_filename_without_ext(suffix) + if suffix_stem in main_img_names_avail: # move from available to selected suffixes lists - main_suffixes.append(suffix) - main_img_names_avail.remove(suffix) + main_suffixes.append(suffix_stem) + main_img_names_avail.remove(suffix_stem) suffix = config.reg_suffixes[config.RegSuffixes.ANNOTATION] if suffix: - suffix = libmag.get_if_within(suffix, 0, "") - if suffix in self._labels_img_names.selections: - labels_suffix = suffix + suffix_stem = libmag.get_filename_without_ext( + libmag.get_if_within(suffix, 0, "")) + if suffix_stem in self._labels_img_names.selections: + labels_suffix = suffix_stem # show main image lists in two dropdowns, where selecting a suffix # from one list immediately moves it to the other @@ -1610,15 +1618,26 @@ def _setup_for_image(self): self._rois_selections.selections = list(self._rois_dict.keys()) self.rois_check_list = _ROI_DEFAULT - def update_filename(self, filename): + def update_filename( + self, filename: str, ignore: bool = False, reset: bool = True): """Update main image filename, triggering image load. Args: - filename (str): Path to image file to load. + filename: Path to image file to load. + ignore: Set to :attr:`_ignore_filename` flag; deafults to False. + True to av + reset: Set the :attr:`_reset_filename` flag; defaults to False. + True to reset additional image parameters such as registered + image suffixes. """ - # reset path so that new path triggers an image load + # if old and new filename are the same, no update will be triggered, + # so need to set to non-image first self._filename = "" + + # update filename, triggering Trait change + self._reset_filename = reset + self._ignore_filename = ignore self._filename = filename def open_image(self, filename, new_window=True): @@ -1653,10 +1672,17 @@ def _image_path_updated(self): will not be loaded for now. """ if self._ignore_filename or not self._filename: - # ignore if only updating widget value, without triggering load + # avoid triggering file load, eg if only updating widget value; + # reset flags self._ignore_filename = False + self._reset_filename = True return - + + if self._reset_filename: + # reset registered suffixes + config.reg_suffixes = dict.fromkeys(config.RegSuffixes, None) + self._reset_filename = True + # load image if possible without allowing import, deconstructing # filename from the selected imported image filename, offset, size, reg_suffixes = importer.deconstruct_img_name( @@ -1694,11 +1720,14 @@ def _reload_images(self): if len(atlas_suffixes) == 1: # reduce to str if only one element atlas_suffixes = atlas_suffixes[0] - reg_suffixes[config.RegSuffixes.ATLAS] = atlas_suffixes + reg_suffixes[config.RegSuffixes.ATLAS] = self._reg_img_names.get( + atlas_suffixes) if self._labels_img_names.selections.index(self._labels_img_name) != 0: # add if not the empty first selection - reg_suffixes[config.RegSuffixes.ANNOTATION] = self._labels_img_name + reg_suffixes[ + config.RegSuffixes.ANNOTATION] = self._reg_img_names.get( + self._labels_img_name) config.reg_suffixes.update(reg_suffixes) if self._labels_ref_path: @@ -1706,9 +1735,7 @@ def _reload_images(self): cli.setup_labels([self._labels_ref_path]) # re-setup image - filename = self._filename - self._filename = "" - self._filename = filename + self.update_filename(self._filename, reset=False) @on_trait_change("_channel") def update_channel(self): diff --git a/magmap/io/importer.py b/magmap/io/importer.py index 152c2f484..be1086f8a 100644 --- a/magmap/io/importer.py +++ b/magmap/io/importer.py @@ -349,7 +349,7 @@ def deconstruct_img_name(np_filename, sep="_", keep_subimg=False): suffix = suffix.value suffix_noext = libmag.get_filename_without_ext(suffix) suffixi = np_filename.rfind(suffix_noext) - if suffixi != -1 and os.path.splitext(np_filename)[0].endswith( + if suffixi != -1 and libmag.splitext(np_filename)[0].endswith( suffix_noext): # strip suffix and any ending separator to get base path filename = np_filename[:suffixi] diff --git a/magmap/io/libmag.py b/magmap/io/libmag.py index f7a29fdb4..4c396e8d4 100644 --- a/magmap/io/libmag.py +++ b/magmap/io/libmag.py @@ -240,9 +240,8 @@ def match_ext(path, path_to_match): return path_to_match -def get_filename_without_ext(path): - """Get filename without extension with support for extensions with - multiple periods through :meth:`splitext`. +def get_filename_without_ext(path: str) -> str: + """Wrapper to :meth:`splitext` for getting only the filename. Args: path: Full path. @@ -252,7 +251,7 @@ def get_filename_without_ext(path): no extension exists. """ name = os.path.basename(path) - name_split = os.path.splitext(name) + name_split = splitext(name) if len(name_split) > 1: return name_split[0] return name