예제 #1
0
class BaseLine(object):
    @property
    def status(self):
        return self._status

    @property
    def roi(self):
        return self._roi

    @property
    def baseline(self):
        if self._status == BaseLineStatus.baseline_subtracted:
            return self._baseline
        else:
            return

    @property
    def parent(self):
        return self._parent()

    def __init__(self, parent: PlotWithBaseLineCorrection):
        self._parent = weakref.ref(parent)
        self._baseline = None
        self._x_axis = None
        self._x1 = None
        self._x2 = None
        self._smoothness_param = None
        self._asymmetry_param = None
        self._baseline_setup_widget = None
        self.baseline_plot = None
        self._status = BaseLineStatus.no_baseline
        self.__init_parameters__()
        self.__init_roi__()

    def clear(self):
        self._baseline = None
        self._set_status(BaseLineStatus.no_baseline)
        self._remove_baseline_from_plot()

    def open_setup(self):
        self.set_axis(self.parent.x)
        self._baseline_setup_widget = setup = BaseLineSetup(
            self._status, **self.get_parameters())
        if None in (self._x1, self._x2):
            self.set_default_bounds()
        self.roi.show()
        setup.calculate_signal.connect(self._on_calculate_baseline)
        setup.subtract_signal.connect(self._on_subtracting_baseline)
        setup.restore_signal.connect(self._on_restoring_data)
        setup.close_signal.connect(self._on_closing_setup)
        setup.show()

    def _set_status(self, status: 'BaseLineStatus'):
        self._status = status
        if self._baseline_setup_widget:
            self._baseline_setup_widget.set_status(status)

    def _on_calculate_baseline(self, params: dict):
        self.set_parameters(**params)
        self.update_bounds()
        try:
            self.get_baseline_correction(self.parent.smoothed_y)
        except Exception as err:
            logger.exception(err)
            show_error(
                'Failed calculating baseline. Change roi region or parameters and try again.',
                'Baseline calculation error')
        self._plot_baseline()
        self._set_status(BaseLineStatus.baseline_calculated)

    def _on_subtracting_baseline(self):
        self._remove_baseline_from_plot()
        self._set_status(BaseLineStatus.baseline_subtracted)
        self.parent.update_smoothed_y()
        self.parent.plot()

    def _on_restoring_data(self):
        self._set_status(BaseLineStatus.baseline_restored)
        self._plot_baseline()
        self.parent.update_smoothed_y()
        self.parent.plot()

    def _on_closing_setup(self):
        self._baseline_setup_widget = None
        self.roi.hide()
        if (self.status == BaseLineStatus.baseline_calculated
                or self.status == BaseLineStatus.baseline_restored):
            self._remove_baseline_from_plot()
            self.clear()

    def _plot_baseline(self):
        if not self.baseline_plot:
            self.baseline_plot = self.parent.image_view.plot_item.plot()
        pen = QPen(QColor('red'))
        pen.setStyle(Qt.DashDotLine)
        pen.setWidth(4)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.RoundJoin)
        pen.setCosmetic(True)
        self.baseline_plot.setData(self._x_axis, self._baseline, pen=pen)

    def _remove_baseline_from_plot(self):
        if self.baseline_plot:
            self.parent.image_view.plot_item.removeItem(self.baseline_plot)
            self.baseline_plot = None

    def __init_parameters__(self):
        # not necessary
        params = read_config('Baseline correction')
        self.set_parameters(**params)

    def __init_roi__(self):
        self._roi = LinearRegionItem()
        self._roi.hide()
        self._roi.setBrush(QColor(255, 255, 255, 50))
        self.parent.image_view.plot_item.addItem(self.roi)

    def update_bounds(self):
        self._x1, self._x2 = self.roi.getRegion()

    def set_parameters(self, **kwargs):
        if 'smoothness_param' in kwargs:
            self._smoothness_param = kwargs['smoothness_param']
        if 'asymmetry_param' in kwargs:
            self._asymmetry_param = kwargs['asymmetry_param']

    def get_parameters(self):
        params = dict()
        if self._asymmetry_param is not None:
            params['asymmetry_param'] = self._asymmetry_param
        if self._smoothness_param is not None:
            params['smoothness_param'] = self._smoothness_param
        return params

    def set_axis(self, x: np.ndarray):
        self._x_axis = x
        self.set_default_bounds()

    def set_bounds(self, x1: float, x2: float):
        self._x1, self._x2 = x1, x2
        self.roi.setRegion((x1, x2))

    def set_default_bounds(self):
        if self._x_axis is None:
            self.set_bounds(0, 1)
        else:
            self.set_bounds(self._x_axis.min(), self._x_axis.max())

    def get_baseline_correction(self, y: np.ndarray):
        if (self._x_axis is None or y.size != self._x_axis.size
                or None in (self._x1, self._x2, self._smoothness_param,
                            self._asymmetry_param)):
            return
        x1, x2 = self._get_coords()
        baseline = baseline_correction(y[x1:x2], self._smoothness_param,
                                       self._asymmetry_param)
        self._baseline = np.zeros_like(y)
        self._baseline[x1:x2] = baseline
        return self.baseline

    def _get_coords(self):
        scale_factor = self._x_axis.size / (self._x_axis.max() -
                                            self._x_axis.min())
        x_min = self._x_axis.min()
        min_ind, max_ind = 0, self._x_axis.size
        x1 = int((self._x1 - x_min) * scale_factor)
        x2 = int((self._x2 - x_min) * scale_factor)
        x1 = min((max((x1, min_ind)), max_ind))
        x2 = min((max((x2, min_ind)), max_ind))
        xs = (x1, x2)
        return min(xs), max(xs)
예제 #2
0
class PlotBC(Smooth1DPlot):
    sigBackgroundChanged = pyqtSignal()

    def __init__(self, profile: BasicProfile, parent=None):
        super().__init__(profile, parent)
        self._status = BaseLineStatus.no_baseline
        self.baseline_plot = self.image_view.plot_item.plot()
        self._init_roi()
        self._baseline_setup_widget = BaseLineSetup(
            self, self._status, **self.profile.get_parameters())
        self.profile.sigDataUpdated.connect(self.update_plot)

    @property
    def y(self):
        if self._status == BaseLineStatus.baseline_subtracted and self.profile.baseline is not None:
            return self.profile.y - self.profile.baseline
        else:
            return self.profile.y

    def update_data(self, *args, **kwargs):
        self.profile.update_data(*args, **kwargs)

    def is_shown(self, shown: bool):
        self.profile.is_shown = shown

    def _init_toolbars(self):
        super()._init_toolbars()

        baseline_toolbar = BlackToolBar('Baseline Correction')
        self.addToolBar(baseline_toolbar)

        baseline_button = RoundedPushButton(parent=baseline_toolbar,
                                            icon=Icon('baseline'),
                                            radius=30)
        baseline_button.clicked.connect(self.open_baseline_setup)
        baseline_toolbar.addWidget(baseline_button)

    def _init_roi(self):
        self._roi = LinearRegionItem()
        self._roi.hide()
        self._roi.setBrush(QColor(255, 255, 255, 50))
        self.image_view.plot_item.addItem(self._roi)

    def open_baseline_setup(self):
        if self.y is None:
            return
        setup = self._baseline_setup_widget

        if self.profile.x_range is None:
            self._set_default_bounds()
        self._roi.setRegion(self.profile.x_range)

        if self.profile.baseline is None:
            self._set_status(BaseLineStatus.no_baseline)
        # elif self._status == BaseLineStatus.no_baseline:
        #     self._set_status(BaseLineStatus.baseline_subtracted)
        # else:
        #     self._set_status(self._status)

        # self.plot()

        setup.set_parameters(self.profile.get_parameters())

        setup.calculate_signal.connect(self._on_calculate_baseline)
        setup.subtract_signal.connect(self._on_subtracting_baseline)
        setup.restore_signal.connect(self._on_restoring_data)
        setup.close_signal.connect(self._on_closing_setup)
        setup.show()
        self._roi.show()

    # def show_baseline(self):
    #     if (self.profile.baseline is None or self._status == BaseLineStatus.baseline_calculated or
    #             self._status == BaseLineStatus.baseline_restored):
    #         return
    #     self._on_restoring_data()

    def update_plot(self):
        self.sigma_slider.set_value(self.profile.sigma, True)

        if self.profile.baseline is None:
            self.clear_baseline()
        else:
            self._set_status(BaseLineStatus.baseline_subtracted)
        self.plot()

    def plot_baseline(self):
        if self.profile.baseline is not None:
            self.baseline_plot.setData(self.profile.x,
                                       self.profile.baseline,
                                       pen=get_pen(width=4,
                                                   color='red',
                                                   style=Qt.DashDotLine))

    def _set_default_bounds(self):
        if self.x is None:
            self.profile.x_range = (0, 1)
        else:
            self.profile.x_range = (self.x.min(), self.x.max())

    def _update_bounds(self):
        self.profile.x_range = self._roi.getRegion()

    def _set_status(self, status: 'BaseLineStatus'):
        self._status = status
        self._baseline_setup_widget.set_status(status)

    def _on_calculate_baseline(self, params: dict):
        self.profile.set_parameters(**params)
        self._update_bounds()
        try:
            self.profile.update_baseline()
        except Exception as err:
            logger.exception(err)
            show_error(
                'Failed calculating baseline. Change roi region or parameters and try again.',
                error_title='Baseline calculation error')
            return
        self._set_status(BaseLineStatus.baseline_calculated)
        self.plot_baseline()

    def _on_subtracting_baseline(self):
        self.baseline_plot.clear()
        self._set_status(BaseLineStatus.baseline_subtracted)
        self.plot()

    def _on_restoring_data(self):
        self._set_status(BaseLineStatus.baseline_restored)
        self.plot_baseline()
        self.plot()

    def _on_closing_setup(self):
        self._baseline_setup_widget.hide()
        self._roi.hide()
        self.clear_baseline()
        if self._status != BaseLineStatus.baseline_subtracted:
            self._set_status(BaseLineStatus.no_baseline)
            self.profile.clear_baseline(clear_range=False)
        self.sigBackgroundChanged.emit()

    def clear_baseline(self):
        self.baseline_plot.clear()