Source code for pdsspect.selection

"""Window to pick selection type/color, load/export ROIs and clear ROIS"""
import os

import numpy as np
from qtpy import QtWidgets, QtCore

from .pdsspect_image_set import PDSSpectImageSetViewBase


[docs]class SelectionController(object): """Controller for :class:`Selection` Parameters ---------- image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model view : :class:`Selection` View to control Attributes ---------- image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model view : :class:`Selection` View to control """ def __init__(self, image_set, view): self.image_set = image_set self.view = view
[docs] def change_current_color_index(self, index): """Change the current color index to a new index Parameters ---------- index : :obj:`int` The new color index """ self.image_set.current_color_index = index for subset in self.image_set.subsets: subset.current_color_index = index
[docs] def change_selection_index(self, index): """Change the selection index to a new index Parameters ---------- index : :obj:`int` The new selection index """ self.image_set.selection_index = index for subset in self.image_set.subsets: subset.selection_index = index
[docs] def change_alpha(self, new_alpha): """Change the alpha value to a new alpha value Parameters ---------- new_alpha : :obj:`float` Value between 0 and 100 """ new_alpha /= 100. self.image_set.alpha = new_alpha for subset in self.image_set.subsets: subset.alpha = new_alpha
[docs] def clear_current_color(self): """Clear all the ROIs with the currently selcted color""" self.image_set.delete_rois_with_color(self.image_set.color) for subset in self.image_set.subsets: subset.delete_rois_with_color(subset.color)
[docs] def clear_all(self): """Clear all ROIs""" self.image_set.delete_all_rois() for subset in self.image_set.subsets: subset.delete_all_rois()
[docs] def add_ROI(self, coordinates, color, image_set=None): """Add ROI with the given coordinates and color Parameters ---------- coordinates : :class:`numpy.ndarray` or :obj:`tuple` Either a ``(m x 2)`` array or a tuple of two arrays If an array, the first column are the x coordinates and the second are the y coordinates. If a tuple of arrays, the first array are x coordinates and the second are the corresponding y coordinates. color : :obj:`str` The name a color in :attr:`~pdsspect.pdsspect_image_set.PDSSpectImageSet.colors` """ image_set = self.image_set if image_set is None else image_set image_set.add_coords_to_roi_data_with_color( coordinates=coordinates, color=color )
def set_simultaneous_roi(self, state): self.image_set.simultaneous_roi = state
[docs]class Selection(QtWidgets.QWidget, PDSSpectImageSetViewBase): """Window to make/clear/load/export ROIs and choose selection mode/color Parameters ---------- image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model parent : None Parent of the view Attributes ---------- image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model parent : None Parent of the view controller : :class:`SelectionController` View controller type_label : :class:`QtWidgets.QLabel <PySide.QtGui.QLabel>` Label for the selection menu selection_menu : :class:`QtWidgets.QComboBox <PySide.QtGui.QComboBox>` Drop down menu of selection types type_layout : :class:`QtWidgets.QHBoxLayout <PySide.QtGui.QHBoxLayout>` Horizontal box layout for selection color_label : :class:`QtWidgets.QLabel <PySide.QtGui.QLabel>` Label for the :attr:`color_menu` color_menu : :class:`QtWidgets.QComboBox <PySide.QtGui.QComboBox>` Drop down menu for color selection color_layout : :class:`QtWidgets.QHBoxLayout <PySide.QtGui.QHBoxLayout>` Horizontal box layout for color selection opacity_label : :class:`QtWidgets.QLabel <PySide.QtGui.QLabel>` Label for the :attr:`opacity_slider` opacity_slider : :class:`QtWidgets.QSlider <PySide.QtGui.QSlider>` Slider to determine opacity for ROIs opacity_layout : :class:`QtWidgets.QHBoxLayout <PySide.QtGui.QHBoxLayout>` Horizontal box layout for opacity slider clear_current_color_btn : :class:`QtWidgets.QPushButton\ <PySide.QtGui.QPushButton>` Button to clear all ROIs will the current color clear_all_btn : :class:`QtWidgets.QPushButton <PySide.QtGui.QPushButton>` Button to clear all ROIs export_btn : :class:`QtWidgets.QPushButton <PySide.QtGui.QPushButton>` Export ROIs to ``.npz`` file load_btn : :class:`QtWidgets.QPushButton <PySide.QtGui.QPushButton>` Load ROIs from ``.npz`` file simultaneous_roi_box : :class:`QtWidgets.QPushButton\ <PySide.QtGui.QPushButton>` When checked, new ROIs appear in every window main_layout : :class:`QtWidgets.QVBoxLayout <PySide.QtGui.QVBoxLayout>` Vertical Box layout for main layout """ def __init__(self, image_set, parent=None): super(Selection, self).__init__() self.image_set = image_set self.parent = parent self.controller = SelectionController(image_set, self) self.type_label = QtWidgets.QLabel('Type:') self.selection_menu = QtWidgets.QComboBox() for selection_type in self.image_set.selection_types: self.selection_menu.addItem(selection_type) self.selection_menu.setCurrentIndex(self.image_set.selection_index) self.selection_menu.currentIndexChanged.connect( self.change_selection_type ) self.type_layout = QtWidgets.QHBoxLayout() self.type_layout.addWidget(self.type_label) self.type_layout.addWidget(self.selection_menu) self.color_label = QtWidgets.QLabel('Color:') self.color_menu = QtWidgets.QComboBox() for color in self.image_set.colors: self.color_menu.addItem(color) self.color_menu.setCurrentIndex(image_set.current_color_index) self.color_menu.currentIndexChanged.connect(self.change_color) self.color_layout = QtWidgets.QHBoxLayout() self.color_layout.addWidget(self.color_label) self.color_layout.addWidget(self.color_menu) self.opacity_label = QtWidgets.QLabel('Opacity:') self.opacity_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.opacity_slider.setRange(0.0, 100.) self.opacity_slider.setValue(self.image_set.alpha * 100.) self.opacity_slider.valueChanged.connect(self.change_alpha) self.opacity_layout = QtWidgets.QHBoxLayout() self.opacity_layout.addWidget(self.opacity_label) self.opacity_layout.addWidget(self.opacity_slider) self.clear_current_color_btn = QtWidgets.QPushButton( 'Clear Current Color' ) self.clear_current_color_btn.clicked.connect(self.clear_current_color) self.clear_all_btn = QtWidgets.QPushButton('Clear All') self.clear_all_btn.clicked.connect(self.clear_all) self.export_btn = QtWidgets.QPushButton("Export ROIs") self.export_btn.clicked.connect(self.open_save_dialog) self.load_btn = QtWidgets.QPushButton("Load ROIs") self.load_btn.clicked.connect(self.show_open_dialog) self.simultaneous_roi_box = QtWidgets.QCheckBox( 'Select ROIs simultaneously' ) self.simultaneous_roi_box.stateChanged.connect( self.select_simultaneous_roi ) self.main_layout = QtWidgets.QVBoxLayout() self.main_layout.addLayout(self.type_layout) self.main_layout.addLayout(self.color_layout) self.main_layout.addLayout(self.opacity_layout) self.main_layout.addWidget(self.clear_current_color_btn) self.main_layout.addWidget(self.clear_all_btn) self.main_layout.addWidget(self.export_btn) self.main_layout.addWidget(self.load_btn) self.main_layout.addWidget(self.simultaneous_roi_box) self.setLayout(self.main_layout)
[docs] def change_color(self, index): """Change the color when color selected in :attr:`color_menu`""" self.controller.change_current_color_index(index)
[docs] def change_selection_type(self, index): """Change selection type when selected in :attr:`selection_menu`""" self.controller.change_selection_index(index)
[docs] def change_alpha(self, new_alpha): """Change alpha value when :attr:`opacity_slider` value changes""" self.controller.change_alpha(new_alpha)
[docs] def clear_current_color(self): """Clear all ROIs with current color""" self.controller.clear_current_color()
[docs] def clear_all(self): """Clear all ROIs""" self.controller.clear_all()
[docs] def export(self, save_file): """Export ROIS to the given filename Parameters ---------- save_file : :obj:`str` File with ``.npz`` extension to save ROIs """ exported_rois = self.image_set.get_rois_masks_to_export() exported_rois['files'] = np.array(self.image_set.filenames) exported_rois['shape'] = self.image_set.shape exported_rois['views'] = len(self.image_set._subsets) + 1 np.savez(save_file, **exported_rois)
[docs] def open_save_dialog(self): """Open save file dialog and save rois to given filename""" save_file, _ = QtWidgets.QFileDialog.getSaveFileName( parent=self, caption='Export ROIs', filter='*.npz', ) if save_file != '': self.export(save_file)
def _check_pdsspect_selection_is_file(self, filepath): base, ext = os.path.splitext(filepath) if ext != '.npz': raise RuntimeError( '%s is not a pdsspect selection file' % filepath ) def _check_files_in_selection_file_compatible(self, files): for file in files: if os.path.basename(file) not in self.image_set.filenames: raise RuntimeError('%s not an opened image' % file) def _check_shape_is_the_same(self, shape): if not np.array_equal(self.image_set.shape, shape): raise RuntimeError( 'Cannot open import ROIs because the shapes are not the same' )
[docs] def load_selections(self, selected_files): """Load ROIs from selected files Parameters ---------- selected_files : :obj:`list` of :obj:`str` Paths to files storing ROIs """ for selected_file in selected_files: self._check_pdsspect_selection_is_file(selected_file) arr_dict = np.load(selected_file) self._check_files_in_selection_file_compatible(arr_dict['files']) self._check_shape_is_the_same(arr_dict['shape']) num_load_views = arr_dict['views'] num_current_views = len(self.image_set._subsets) + 1 has_multiple_views = all( (num_load_views > 1, num_current_views > 1) ) if has_multiple_views: if num_load_views < num_current_views: num_views = num_load_views else: num_views = num_current_views else: num_views = 0 for color in self.image_set.colors: coords = np.column_stack(np.where(arr_dict[color])) if coords.size > 0: self.controller.add_ROI(coords, color) for num_view in range(num_views - 1): subset = self.image_set._subsets[num_view] name = color + str(num_view + 2) coords = np.column_stack(np.where(arr_dict[name])) if coords.size > 0: self.controller.add_ROI(coords, color, subset)
[docs] def show_open_dialog(self): """Open file dialog to select ``.npz`` files to load ROIs""" selected_files, _ = QtWidgets.QFileDialog.getOpenFileNames( parent=self, caption='Open ROIs', filter='Selections(*.npz)', ) self.load_selections(selected_files)
def select_simultaneous_roi(self, state): self.controller.set_simultaneous_roi( self.simultaneous_roi_box.isChecked() )