Source code for pdsspect.roi_plot

"""Parent classes for any widget that plots data"""
from qtpy import QT_VERSION
from qtpy import QtWidgets, QtCore
from matplotlib.figure import Figure

from .pdsspect_image_set import PDSSpectImageSetViewBase

qt_ver = int(QT_VERSION[0])
if qt_ver == 4:
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
elif qt_ver == 5:
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg


[docs]class ROIPlotModel(object): """Model for ROI Plot and accompanying widget Parameters ---------- image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model Attributes ---------- selected_colors : :obj:`list` Colors to display in the histogram latex_units : :obj:`list` of 3 :obj:`str` The latex strings of :attr:`.pdsspect_image_set.PDSSpectImageSet.accepted_units` """ latex_units = ['nm', '\mu m', '\AA'] def __init__(self, image_set): self._views = [] self._image_set = image_set self.selected_colors = [] self._view_index = 0
[docs] def register(self, view): """Register view with the model""" if view not in self._views: self._views.append(view)
[docs] def unregister(self, view): """Unregister view with the model""" if view in self._views: self._views.remove(view)
def set_data(self): for view in self._views: view.set_data() @property def image_sets(self): """:obj:`list` : All the image sets, including the current one""" return [self._image_set] + self._image_set.subsets @property def image_set(self): """:class:`~.pdsspect_image_set.PDSSpectImageSet` : Image set that corresponds with the current view """ return self.image_sets[self._view_index] @property def has_multiple_views(self): """:obj:`bool` : True if there are multiple views, False otherwise""" return len(self.image_sets) > 1 @property def view_index(self): """:obj:`int` : The index of the view to display the ROI data If there are not multiple views, view_index is automatically ``-1``. """ if not self.has_multiple_views: return -1 else: return self._view_index @view_index.setter def view_index(self, new_index): self._view_index = new_index if self._view_index == self.image_set.current_image_index: self.image_index = -1 self.set_data()
[docs] def add_selected_color(self, color): """Select a color and inform views to display new color Parameters ---------- color : :obj:`str` The color to add """ self.selected_colors.append(color) self.set_data()
[docs] def remove_selected_color(self, color): """Remove a selected color and inform views to not display the color Parameters ---------- color : :obj:`str` The color to remove """ self.selected_colors.remove(color) self.set_data()
@property def unit(self): """:obj:`str` : Latex version of :attr:`.pdsspect_image_set.PDSSpectImageSet.unit`""" index = self.image_set.accepted_units.index(self.image_set.unit) return self.latex_units[index]
[docs]class ROIPlotController(object): """Controller for ROI plot and accompanying widget Parameters ---------- model : :class:`ROIPlotModel` The model view : :class:`QtWidgets.QWidget <PySide.QtGui.QWidget>` The view Attributes ---------- model : :class:`ROIPlotModel` The model view : :class:`QtWidgets.QWidget <PySide.QtGui.QWidget>` The view """ def __init__(self, model, view): self.model = model self.view = view
[docs] def color_state_changed(self, color): """Select or remove the color when a checkbox color changes Parameters ---------- color : :obj:`str` The name of the checkbox whose state changed """ if color not in self.model.selected_colors: self.select_color(color) else: self.remove_color(color)
[docs] def select_color(self, color): """Selected a given color Parameters ---------- color : :obj:`str` The color to select """ self.model.add_selected_color(color)
[docs] def remove_color(self, color): """Remove a given color Parameters ---------- color : :obj:`str` The color to remove """ self.model.remove_selected_color(color)
[docs] def set_view_index(self, index): """Set the index of the view Parameters ---------- index : :obj:`int` Index of the view """ self.model.view_index = index
[docs]class ColorCheckBox(QtWidgets.QCheckBox): """Custom checkbox that emits its color (:obj:`str`) when toggled Parameters ---------- color : :obj:`str` The color to name the checkbox Attributes ---------- color : :obj:`str` The color to name the checkbox stateChanged : :obj:`QtCore.Signal` Signal that emits a string when check box changes its state Read more about `Signals here <http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html>`_ """ stateChanged = QtCore.Signal(str) def __init__(self, color): super(ColorCheckBox, self).__init__(color) self.color = color
[docs] def nextCheckState(self): """Adjust checkbox's toggle & emit color when checkbox is clicked""" self.setChecked(not self.isChecked()) self.stateChanged.emit(self.color)
[docs]class ViewCheckBox(QtWidgets.QCheckBox): """Custom checkbox that emits its index (:obj:`int`) when toggled Parameters ---------- index : :obj:`int` The index of the view Attributes ---------- index : :obj:`int` The index of the view stateChanged : :obj:`QtCore.Signal` Signal that emits the box itself when check box changes its state Read more about `Signals here <http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html>`_ """ stateChanged = QtCore.Signal(object) def __init__(self, index): view_number = index + 1 name = 'view ' + str(view_number) super(ViewCheckBox, self).__init__(name) self.name = name self.view_number = view_number self.index = index def set_check_state(self): self.setChecked(not self.isChecked()) self.stateChanged.emit(self)
[docs] def nextCheckState(self): """Adjust checkbox's toggle & emit checkbox when checkbox is clicked""" if not self.isChecked(): self.set_check_state()
[docs]class ROIPlotWidget(QtWidgets.QWidget, PDSSpectImageSetViewBase): """Widget to hold the histogram and checkboxs Checkboxes are created in :meth:`create_color_checkbox` which is why they do not appear in the :meth:`__init__` method. Parameters ---------- model : :class:`ROIPlotModel` The model Attributes ---------- model : :class:`ROIPlotModel` The model controller : :class:`ROIPlotController` The controller checkbox_layout : :class:`QtWidgets.QVBoxLayout <PySide.QtGui.QVBoxLayout>` Place the checkboxes vertically main_layout : :class:`QtWidgets.QGridLayout <PySide.QtGui.QGridLayout>` Place in grid layout so histogram stretches while boxes are stationary roi_plot : :class:`ROIPlot` The plot of ROI data save_btn : :class:`QtWidgets.QPushButton <PySide.QtGui.QPushButton>` Save the plot as an image red_checkbox : :class:`ColorCheckBox` Red checkbox that displays red ROI data when checked brown_checkbox : :class:`ColorCheckBox` Brown checkbox that displays brown ROI data when checked lightblue_checkbox : :class:`ColorCheckBox` Lightblue checkbox that displays lightblue ROI data when checked lightcyan_checkbox : :class:`ColorCheckBox` Lightcyan checkbox that displays lightcyan ROI data when checked darkgreen_checkbox : :class:`ColorCheckBox` Darkgreen checkbox that displays darkgreen ROI data when checked yellow_checkbox : :class:`ColorCheckBox` Yellow checkbox that displays yellow ROI data when checked pink_checkbox : :class:`ColorCheckBox` Pink checkbox that displays pink ROI data when checked teal_checkbox : :class:`ColorCheckBox` Teal checkbox that displays teal ROI data when checked goldenrod_checkbox : :class:`ColorCheckBox` Goldenrod checkbox that displays goldenrod ROI data when checked sienna_checkbox : :class:`ColorCheckBox` Sienna checkbox that displays sienna ROI data when checked darkblue_checkbox : :class:`ColorCheckBox` Darkblue checkbox that displays darkblue ROI data when checked crimson_checkbox : :class:`ColorCheckBox` Crimson checkbox that displays crimson ROI data when checked maroon_checkbox : :class:`ColorCheckBox` Maroon checkbox that displays maroon ROI data when checked purple_checkbox : :class:`ColorCheckBox` Purple checkbox that displays purple ROI data when checked """ def __init__(self, model): super(ROIPlotWidget, self).__init__() self.model = model self.model.register(self) self.controller = ROIPlotController(model, self) self.roi_plot = None self._create_roi_plot() self.checkbox_layout = QtWidgets.QVBoxLayout() for color in self.model.image_set.colors[:-1]: self.create_color_checkbox(color) self.save_btn = QtWidgets.QPushButton('Save Plot') self.save_btn.clicked.connect(self.save_plot) self.view_boxes_layout = QtWidgets.QHBoxLayout() self.main_layout = QtWidgets.QGridLayout() self._set_layout() if self.model.has_multiple_views: self.add_view() else: self._register_set_at_index(0) def _create_roi_plot(self): self.roi_plot = None def _register_set_at_index(self, index): self.model.image_sets[index].register(self.roi_plot) self.model.image_sets[index].register(self) def _set_layout(self): pass
[docs] def create_color_checkbox(self, color): """Create a checkbox with the given color Parameters ---------- color : :obj:`str` The color to name the checkbox """ name = color + '_checkbox' color_checkbox = ColorCheckBox(color) color_checkbox.stateChanged.connect(self.check_color) setattr(self, name, color_checkbox) self.checkbox_layout.addWidget(color_checkbox)
[docs] def check_color(self, checkbox_color): """Called when the state a checkbox is changed Parameters ---------- checkbox_color : :obj:`str` The color label of the check box """ self.controller.color_state_changed(checkbox_color)
[docs] def add_view(self, index=None): """Add a view box to the widget Parameters ---------- index : :obj:`int` [Default None] The index to add the view to """ if self.view_boxes_layout.count() == 0 and index is None: for index, image_set in enumerate(self.model.image_sets): self.add_view(index) return if index is None: index = len(self.model.image_sets) - 1 view_box = ViewCheckBox(index) view_box.stateChanged.connect(self.check_view_checkbox) self.view_boxes_layout.addWidget(view_box) self._register_set_at_index(index) box = self.view_boxes_layout.itemAt(self.model._view_index).widget() box.setChecked(True) self.check_view_checkbox(box)
[docs] def check_view_checkbox(self, view_checkbox): """Check the view box at the given index Parameters ---------- view_checkbox : :class:`ViewCheckBox` The view check box whose state changed """ index = view_checkbox.index for item_index in range(self.view_boxes_layout.count()): if item_index != index: box = self.view_boxes_layout.itemAt(item_index).widget() box.setChecked(False) if view_checkbox.isChecked(): self.controller.set_view_index(index)
def set_data(self): pass
[docs] def save_plot(self): """Save the plot as an image""" save_file, _ = QtWidgets.QFileDialog.getSaveFileName(parent=self) if save_file != '': self.roi_plot._figure.savefig( save_file, facecolor='black', edgecolor='black', )
[docs]class ROIPlot(FigureCanvasQTAgg, PDSSpectImageSetViewBase): """Plot of the data in each ROI color Parameters ---------- model : :class:`ROIPlotModel` The model image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model Attributes ---------- model : :class:`ROIPlotModel` The model image_set : :class:`~.pdsspect_image_set.PDSSpectImageSet` pdsspect model """ def __init__(self, model): self.model = model self.image_set = model.image_set fig = Figure(figsize=(6, 4), dpi=100, facecolor='black') fig.subplots_adjust( left=0.15, right=0.95, top=0.95, bottom=0.15, wspace=0.0, hspace=0.0, ) super(ROIPlot, self).__init__(fig) self._figure = fig policy = self.sizePolicy() policy.setHeightForWidth(True) self.setSizePolicy(policy) self.setMinimumSize(self.size()) self._ax = fig.add_subplot(111) self._ax.set_facecolor('black') self._ax.spines['bottom'].set_color('w') self._ax.spines['left'].set_color('w') self._ax.tick_params(axis='x', colors='w', labelsize=8) self._ax.tick_params(axis='y', colors='w', labelsize=8) self.set_data()
[docs] def set_roi_data(self): """Set data when ROI is created/destroyed or checkbox is toggled""" self.set_data()