Exemplo n.º 1
0
    def get_day_layout(self, day_text):
        day_label = QLabel(day_text)
        day_label.setFixedWidth(120)
        day_label.setFixedHeight(50)
        day_label.setFont(self.day_font)
        day_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)

        gen_day_button = QPushButton("Plan day")
        gen_day_button.setFont(self.general_font)
        gen_day_button.font().setBold(False)

        use_day_check = QCheckBox("Use: ")
        use_day_check.setLayoutDirection(QtCore.Qt.RightToLeft)
        use_day_check.setChecked(True)
        use_day_check.setFont(self.general_font)
        day_layout = QHBoxLayout()
        day_layout.addWidget(day_label)
        day_layout.addWidget(use_day_check)

        info_layout = QVBoxLayout()
        info_layout.addLayout(day_layout)
        info_layout.addWidget(gen_day_button)

        day_text_edit = QTextEdit()
        day_text_edit.setFont(self.general_font)

        #Create, fill and return the day layout
        day_layout = QHBoxLayout()
        day_layout.addLayout(info_layout)
        day_layout.addWidget(day_text_edit)

        return day_layout
Exemplo n.º 2
0
class CamView(AbstractView):
    def __init__(self,
                 name: str = "CAM_NONE",
                 log_handlers: [StreamHandler] = None):
        self._logger = getLogger(__name__)
        if log_handlers:
            for h in log_handlers:
                self._logger.addHandler(h)
        self._logger.debug("Initializing")
        super().__init__(name)
        """ Min size for cam window """
        self._subwindow_height = 222
        self._subwindow_width = 518

        self._initialization_bar_frame = EasyFrame()
        self._initialization_bar_frame.setMouseTracking(True)
        self._initialization_bar_frame.setMaximumHeight(70)
        self._initialization_bar_layout = QVBoxLayout(
            self._initialization_bar_frame)

        self._initialization_bar_label = QLabel(self._initialization_bar_frame)
        self._initialization_bar_label.setMouseTracking(True)
        self._initialization_bar = QProgressBar(self._initialization_bar_frame)
        self._initialization_bar.setMouseTracking(True)
        self._initialization_bar.setMaximumHeight(15)
        self._initialization_bar.setTextVisible(True)
        self._initialization_bar.setAlignment(Qt.AlignHCenter)

        self._initialization_bar_layout.addWidget(
            self._initialization_bar_label)
        self._initialization_bar_layout.addWidget(self._initialization_bar)

        self._cam_settings_frame = EasyFrame()
        self._cam_settings_layout = QGridLayout(self._cam_settings_frame)

        self._resolution_selector_label = QLabel(self._cam_settings_frame)
        self._resolution_selector_label.setAlignment(Qt.AlignLeft)

        self._resolution_selector = QComboBox(self._cam_settings_frame)
        self._resolution_selector.setMaximumHeight(22)

        self._cam_settings_layout.addWidget(self._resolution_selector_label, 0,
                                            0)
        self._cam_settings_layout.addWidget(self._resolution_selector, 0, 1)

        self._fps_selector_label = QLabel(self._cam_settings_frame)
        self._fps_selector_label.setAlignment(Qt.AlignLeft)

        self._fps_selector = QComboBox(self._cam_settings_frame)
        self._fps_selector.setMaximumHeight(22)

        self._cam_settings_layout.addWidget(self._fps_selector_label, 1, 0)
        self._cam_settings_layout.addWidget(self._fps_selector, 1, 1)

        self._show_feed_checkbox_label = QLabel(self._cam_settings_frame)
        self._show_feed_checkbox_label.setAlignment(Qt.AlignLeft)

        self._show_feed_checkbox = QCheckBox()
        self._show_feed_checkbox.setChecked(True)
        self._show_feed_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._show_feed_checkbox_label, 2,
                                            0)
        self._cam_settings_layout.addWidget(self._show_feed_checkbox, 2, 1)

        self._use_cam_checkbox_label = QLabel(self._cam_settings_frame)
        self._use_cam_checkbox_label.setAlignment(Qt.AlignLeft)

        self._use_cam_checkbox = QCheckBox()
        self._use_cam_checkbox.setChecked(True)
        self._use_cam_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._use_cam_checkbox_label, 3, 0)
        self._cam_settings_layout.addWidget(self._use_cam_checkbox, 3, 1)

        self._use_overlay_checkbox_label = QLabel(self._cam_settings_frame)
        self._use_overlay_checkbox_label.setAlignment(Qt.AlignLeft)

        self._use_overlay_checkbox = QCheckBox()
        self._use_overlay_checkbox.setChecked(True)
        self._use_overlay_checkbox.setLayoutDirection(Qt.RightToLeft)

        self._cam_settings_layout.addWidget(self._use_overlay_checkbox_label,
                                            4, 0)
        self._cam_settings_layout.addWidget(self._use_overlay_checkbox, 4, 1)

        self._image_display_frame = EasyFrame()
        self._image_display_layout = QVBoxLayout(self._image_display_frame)

        self._image_display_label = QLabel(self._image_display_frame)
        self._image_display_label.setAlignment(Qt.AlignHCenter)
        self._image_display = QLabel(self._image_display_frame)
        self._image_display.setAlignment(Qt.AlignCenter)
        self._image_display.setMouseTracking(True)
        self._image_display_layout.addWidget(self._image_display_label)
        self._image_display_layout.addWidget(self._image_display)

        spacer = QSpacerItem(1, 1, vData=QSizePolicy.Expanding)

        self._dev_sets_frame = EasyFrame()
        self._dev_sets_layout = QVBoxLayout(self._dev_sets_frame)

        self.config_button = ClickAnimationButton()
        self.config_button.clicked.connect(self._config_button_handler)

        self.layout().addWidget(self.config_button, 0, 0,
                                Qt.AlignTop | Qt.AlignRight)
        self.config_button.setFixedSize(30, 25)
        self.config_button.setStyleSheet(
            "background-color: rgba(200, 200, 200, 50%)")

        self._dev_sets_layout.addWidget(self._cam_settings_frame)
        self._dev_sets_layout.addItem(spacer)
        self.layout().addWidget(self._image_display, 0, 0)
        self.layout().addWidget(self._initialization_bar_frame, 0, 0)

        self._config_items = [
            self._resolution_selector,
            self._fps_selector,
            self._use_cam_checkbox,
            self._show_feed_checkbox,
            self._use_overlay_checkbox,
        ]

        config_win_w = 350
        config_win_h = len(self._config_items) * 30

        self.config_button.raise_()

        self._config_win = ConfigPopUp()
        self._config_win.setLayout(self._dev_sets_layout)
        self._config_win.setFixedSize(config_win_w, config_win_h)

        self._rec_label = QLabel()
        self._rec_label.setStyleSheet(
            "background-color: rgba(0, 0, 0, 0%); color: red; font: 20px")
        self._rec_label.hide()

        self.layout().addWidget(self._rec_label, 0, 0,
                                Qt.AlignBottom | Qt.AlignRight)

        self.layout().setMargin(0)

        self._window_changing = False
        self._showing_images = False
        self._hidden = False
        w = 320
        self._aspect_ratio = 9 / 16
        self.resize(w, self.heightForWidth(w))
        self._strings = dict()
        self._lang_enum = LangEnum.ENG
        self.setMinimumSize(self._subwindow_width, self._subwindow_height)
        self.old_size = QSize(self.width(), self.height())

        self._logger.debug("Initialized")

    def set_show_feed_button_handler(self, func) -> None:
        """
        Add handler for show camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._show_feed_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def set_resolution_selector_handler(self, func) -> None:
        """
        Add handler for resolution selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector.activated.connect(func)
        self._logger.debug("done")

    def set_fps_selector_handler(self, func) -> None:
        """
        Add handler for resolution selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.activated.connect(func)
        self._logger.debug("done")

    def set_use_cam_button_handler(self, func) -> None:
        """
        Add handler for use camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._use_cam_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def set_use_overlay_button_handler(self, func) -> None:
        """
        Add handler for use camera selector.
        :param func: The handler.
        :return None:
        """
        self._logger.debug("running")
        self._use_overlay_checkbox.toggled.connect(func)
        self._logger.debug("done")

    def _config_button_handler(self) -> None:
        """
        Show config pop up.
        :return None:
        """
        self._logger.debug("running")
        self.config_button.setStyleSheet(
            "background-color: rgba(200, 200, 200, 50%)")
        self._config_win.exec_()
        self._logger.debug("done")

    @property
    def language(self) -> LangEnum:
        """
        :return: The current lang enum being used.
        """
        return self._lang_enum

    @language.setter
    def language(self, lang: LangEnum) -> None:
        """
        Set the language for this view object.
        :param lang: The language to use.
        :return None:
        """
        self._logger.debug("running")
        self._lang_enum = lang
        self._strings = strings[lang]
        self._set_texts()
        self._set_tooltips()
        self._logger.debug("done")

    @property
    def resolution_list(self) -> list:
        """
        Get list of resolutions.
        :return list: The list of resolutions.
        """
        ret = list()
        return ret

    @resolution_list.setter
    def resolution_list(self, res_list: list) -> None:
        """
        Set list of resolutions available to res_list.
        :param res_list: The list of available resolutions.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector.clear()
        for item in res_list:
            self._resolution_selector.addItem(str(item))
        self._logger.debug("done")

    @property
    def resolution(self) -> str:
        """
        Get the current resolution selection.
        :return str: The current resolution.
        """
        return self._resolution_selector.currentText()

    @resolution.setter
    def resolution(self, res: str) -> None:
        """
        Set the current resolution selection.
        :param res: The resolution to set to.
        :return None:
        """
        self._resolution_selector.setCurrentIndex(
            self._resolution_selector.findText(res))

    @property
    def fps_list(self) -> list:
        """
        Get list of fps options.
        :return list: The list of fps options.
        """
        ret = list()
        return ret

    @fps_list.setter
    def fps_list(self, fps_list: list) -> None:
        """
        Set list of available fps to fps_list.
        :param fps_list:
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.clear()
        for item in fps_list:
            self._fps_selector.addItem(str(item))
        self._logger.debug("done")

    @property
    def fps(self) -> str:
        """
        Get the current fps selection.
        :return str: The current fps selection.
        """
        return self._fps_selector.currentText()

    @fps.setter
    def fps(self, fps: str) -> None:
        """
        Set the current fps selection.
        :param fps: The fps to set to.
        :return None:
        """
        self._logger.debug("running")
        self._fps_selector.setCurrentIndex(self._fps_selector.findText(fps))
        self._logger.debug("done")

    @property
    def use_feed(self) -> bool:
        """
        Get the current use_cam setting.
        :return bool: User selection for using cam.
        """
        return self._show_feed_checkbox.isChecked()

    @use_feed.setter
    def use_feed(self, useable: bool) -> None:
        """
        Set use_cam setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._show_feed_checkbox.setChecked(useable)
        self._logger.debug("Done")

    @property
    def use_cam(self) -> bool:
        """
        Get the current use_cam setting.
        :return bool: User selection for using cam.
        """
        return self._use_cam_checkbox.isChecked()

    @use_cam.setter
    def use_cam(self, useable: bool) -> None:
        """
        Set use_cam setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._use_cam_checkbox.setChecked(useable)
        self._logger.debug("Done")

    @property
    def use_overlay(self) -> bool:
        """
        Get the current use_overlay setting.
        :return bool: User selection for using overlay.
        """
        return self._use_overlay_checkbox.isChecked()

    @use_overlay.setter
    def use_overlay(self, useable: bool) -> None:
        """
        Set use_overlay setting.
        :param useable: The setting to set to.
        :return None:
        """
        self._logger.debug("running")
        self._use_overlay_checkbox.setChecked(useable)
        self._logger.debug("Done")

    def heightForWidth(self, w: int) -> int:
        return int(w * self._aspect_ratio)

    def widthForHeight(self, h: int) -> int:
        return int(h / self._aspect_ratio)

    def hideEvent(self, hideEvent: QHideEvent):
        """
        Track minimize event.
        :param hideEvent:
        :return None:
        """
        self._hidden = True

    def showEvent(self, showEvent: QShowEvent):
        """
        Track restore event.
        :param showEvent:
        :return None:
        """
        self._hidden = False

    def update_image(self, image: QPixmap = None, msg: str = None) -> None:
        """
        Update image viewer with new image.
        :param image: The new image to show.
        :param msg: The text to show if no image.
        :return None:
        """
        self._logger.debug("running")
        if not self._window_changing:
            if image is not None:
                temp_image_w = image.scaledToWidth(self.width() - 15)
                temp_image_h = image.scaledToHeight(self.height() - 35)
                if temp_image_w.height() > self.height() - 35:
                    self._image_display.setPixmap(temp_image_h)
                else:
                    self._image_display.setPixmap(temp_image_w)
            elif msg is not None:
                self._image_display.setText(msg)
        self._logger.debug("done")

    def show_images(self) -> None:
        """
        Show image display and hide initialization bar.
        :return None:
        """
        self._logger.debug("running")
        geo = self.geometry()
        self._showing_images = True
        self._initialization_bar_frame.hide()
        self._image_display.show()
        self.config_button.show()
        self.setStyleSheet("background-color: black")
        self.setGeometry(geo)
        self._logger.debug("done")

    def show_initialization(self) -> None:
        """
        Show initialization bar and hide image display.
        :return None:
        """
        self._logger.debug("running")
        self._showing_images = False
        self._image_display.hide()
        self.config_button.hide()
        self._initialization_bar_frame.show()
        self._logger.debug("done")

    def update_init_bar(self, progress: int) -> None:
        """
        set progress bar value to progress.
        :param progress: The value to set progress bar to.
        :return None:
        """
        self._logger.debug("running")
        if progress > 100:
            progress = 100
        elif progress < 0:
            progress = 0
        self._initialization_bar.setValue(progress)
        self._logger.debug("done")

    def set_config_active(self, is_active: bool) -> None:
        """
        Set whether this camera config options are usable.
        :param is_active: Usable.
        :return None:
        """
        self._logger.debug("running")
        if self._showing_images:
            if is_active:
                self._rec_label.hide()
            elif self.use_cam:
                self._rec_label.show()
        for item in self._config_items:
            item.setEnabled(is_active)
        self._logger.debug("done")

    def _set_texts(self) -> None:
        """
        Set the texts in this view object.
        :return None:
        """
        self._logger.debug("running")
        self._initialization_bar_label.setText(
            self._strings[StringsEnum.INITIALIZATION_BAR_LABEL])
        self._initialization_bar.setValue(0)
        self._image_display_label.setText(
            self._strings[StringsEnum.IMAGE_DISPLAY_LABEL])
        self._image_display.setText(self._strings[StringsEnum.IMAGE_DISPLAY])
        self._show_feed_checkbox_label.setText(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_LABEL])
        self._use_cam_checkbox_label.setText(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_LABEL])
        self._use_overlay_checkbox_label.setText(
            self._strings[StringsEnum.USE_OVERLAY_CHECKBOX_LABEL])
        self._resolution_selector_label.setText(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_LABEL])
        self._fps_selector_label.setText(
            self._strings[StringsEnum.FPS_SELECTOR_LABEL])
        self._config_win.setWindowTitle(
            self.get_name() + " " +
            self._strings[StringsEnum.CONFIG_TAB_LABEL])
        self.config_button.setText("...")
        self._rec_label.setText("rec ●")
        self._logger.debug("done")

    def _set_tooltips(self) -> None:
        """
        Set the tooltips in this view object.
        :return None:
        """
        self._logger.debug("running")
        self._resolution_selector_label.setToolTip(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP])
        self._resolution_selector.setToolTip(
            self._strings[StringsEnum.RESOLUTION_SELECTOR_TOOLTIP])
        self._fps_selector_label.setToolTip(
            self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP])
        self._fps_selector.setToolTip(
            self._strings[StringsEnum.FPS_SELECTOR_TOOLTIP])
        self._show_feed_checkbox_label.setToolTip(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP])
        self._show_feed_checkbox.setToolTip(
            self._strings[StringsEnum.SHOW_FEED_CHECKBOX_TOOLTIP])
        self._use_cam_checkbox_label.setToolTip(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP])
        self._use_cam_checkbox.setToolTip(
            self._strings[StringsEnum.USE_CAM_CHECKBOX_TOOLTIP])
        self._use_overlay_checkbox_label.setToolTip(
            self._strings[StringsEnum.USE_OVERLAY_TOOLTIP])
        self._use_overlay_checkbox.setToolTip(
            self._strings[StringsEnum.USE_OVERLAY_TOOLTIP])
        self._image_display.setToolTip(
            self._strings[StringsEnum.IMAGE_DISPLAY_TOOLTIP])
        self._logger.debug("done")
Exemplo n.º 3
0
class extractPeaksDialog(QDialog):
    def __init__(self, *args, **kwargs):
        super(extractPeaksDialog, self).__init__(*args, **kwargs)

        self.peaksScraped = False
        self.small = 3
        self.failures_nulled = False
        self.rundownThreshold = 0.5  # to assess whether responses are running down (by factor 2 or more)
        self.makeDialog()

    def makeDialog(self):
        """Create the controls for the dialog"""

        self.setWindowTitle("Extract peaks according to reference pattern")
        layout = QGridLayout()
        w = QWidget()
        w.setLayout(layout)

        self.resize(500, 400)
        vbox = QVBoxLayout()
        vbox.addWidget(w)
        self.setLayout(vbox)

        self.N_ROI_label = QLabel('Extracting peaks')

        #will be altered as soon as data loads
        self.skipRB = QCheckBox('Skip ROIs with SNR less than')
        self.skipRB.setChecked(False)
        self.skipRB.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.skipRB.stateChanged.connect(self.maskLowSNR)

        self.skipSB = pg.SpinBox(value=3, step=.2, bounds=[1, 10], delay=0)
        self.skipSB.setFixedSize(60, 25)
        self.skipSB.valueChanged.connect(self.maskLowSNR)

        psr_label = QLabel('Search range around peak (data points)')
        self.psrSB = pg.SpinBox(value=3,
                                step=2,
                                bounds=[1, 7],
                                delay=0,
                                int=True)
        self.psrSB.setFixedSize(60, 25)

        #will be altered as soon as data loads
        self.noiseRB = QCheckBox('Treat peaks as failures when < SD x')
        self.noiseRB.setChecked(False)
        self.noiseRB.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.noiseRB.stateChanged.connect(self.setFailures)
        self.noiseRB.setDisabled(True)

        self.noiseSB = pg.SpinBox(value=1.5, step=.1, bounds=[.2, 10], delay=0)
        self.noiseSB.setFixedSize(60, 25)
        self.noiseSB.valueChanged.connect(self.setFailures)
        self.noiseSB.setDisabled(True)

        self.peaksLabel = QLabel('No peaks set to be failures.')

        _doScrapeBtn = QPushButton('Extract responses')
        _doScrapeBtn.clicked.connect(self.scrapePeaks)

        self.getRundownBtn = QPushButton('Calculate rundown')
        self.getRundownBtn.clicked.connect(self.getRundown)
        self.getRundownBtn.setDisabled(True)

        _cancelBtn = QPushButton('Cancel')
        _cancelBtn.clicked.connect(self.reject)

        self.acceptBtn = QPushButton('Accept and Return')
        self.acceptBtn.clicked.connect(self.prepareAccept)
        self.acceptBtn.setDisabled(True)

        layout.addWidget(self.N_ROI_label, 0, 0, 1, 2)

        layout.addWidget(self.skipRB, 1, 0, 1, 3)
        layout.addWidget(self.skipSB, 1, 2, 1, 1)

        layout.addWidget(psr_label, 2, 0, 1, 2)
        layout.addWidget(self.psrSB, row=2, col=2)

        layout.addWidget(self.noiseRB, 3, 0, 1, 3)
        layout.addWidget(self.noiseSB, 3, 2, 1, 1)
        layout.addWidget(self.peaksLabel, 4, 0, 1, -1)

        layout.addWidget(_doScrapeBtn, 5, 0)
        layout.addWidget(self.getRundownBtn, 5, 1)
        layout.addWidget(_cancelBtn, 6, 1)
        layout.addWidget(self.acceptBtn, 6, 2)

        self.setLayout(layout)

    def setExternalParameters(self, extPa):
        """extPa is a dictionary of external parameters that can be passed"""
        if 'Max' in extPa:
            self.selecter.setMaximum(extPa['Max'])
            print("Changing spinbox max to : {}".format(extPa['Max']))
        if 'Min' in extPa:
            self.selecter.setMinimum(extPa['Min'])
            print("Changing spinbox min to : {}".format(extPa['Min']))
        if 'tPeaks' in extPa:
            self.tPeaks = extPa['tPeaks']

    def prepGuiParameters(self):
        """Take parameters specified by GUI"""

        #True if box is checked, otherwise False
        self.ignore = self.skipRB.isChecked()
        self.psr = self.psrSB.value() // 2  #floor division to get ears

    def addDataset(self, data):
        """Bring in external dataset for analysis"""

        self.tracedata = data.traces  # each dataframe in this dictionary could have a different set of ROI
        self.name = data.DSname + "_expk"
        tdk = self.tracedata.keys()
        tdk_display = ", ".join(str(k) for k in tdk)
        N_ROI = np.array([len(self.tracedata[d].columns) for d in tdk])
        N_Peaks = len(self.tPeaks)
        self.total_peaks = (N_ROI * N_Peaks).sum()
        self.N_ROI_label.setText(
            "Extracting {} peaks from {} ROIs (total {})\n over the sets named {}"
            .format(N_Peaks, N_ROI, self.total_peaks, tdk_display))

        _printable = "{}\n{}\n".format(tdk_display,
                                       [self.tracedata[d].head() for d in tdk])
        print("Added data of type {}:\n{}\n".format(type(self.tracedata),
                                                    _printable))
        self.maskLowSNR()

    def getRundown(self, silent=False):
        rtext = ""
        self.rundownCount = 0
        for _condi, _pkdf in self.pk_extracted_by_condi.items():

            _Np = len(_pkdf.index)
            _NROI = len(_pkdf.columns)
            ten_percent = int(_Np / 10)
            rtext += "{} condition, 10% of peaks count is {} peaks\n".format(
                _condi, ten_percent)
            # look at first 5 peaks
            _firsttenpc = _pkdf.iloc[0:ten_percent].describe().loc["mean"]
            # look at last 5 peaks
            _lasttenpc = _pkdf.iloc[-1 - ten_percent:-1].describe().loc["mean"]

            _tdf = self.tracedata[_condi]
            _max = _tdf.max()
            _SD = _tdf.std()

            _bestSNR = _max / _SD
            _startSNR = _firsttenpc / _SD
            _endSNR = _lasttenpc / _SD
            #print ("ff, lf : {} {}".format(_firstfive, _lastfive))

            _rundownRatio = _lasttenpc.div(_firsttenpc).sort_values()
            self.rundownCount += _rundownRatio[
                _rundownRatio < self.rundownThreshold].count()

            _rd_SNR = pd.concat([_rundownRatio, _bestSNR, _startSNR, _endSNR],
                                axis=1)
            _rd_SNR.columns = [
                'Rundown', 'Best SNR', 'Initial SNR', 'Final SNR'
            ]

            rtext += "Rundown (amplitude ratio: last 10% / first 10%) and signal to noise ratio (start, end)\nfor {} ROIs (ROIs with worst rundown first):\n{}\n\n".format(
                _NROI,
                _rd_SNR.round(2).to_string())

        rtext += "Total number of traces with rundown worse than threshold ({}): {}\n".format(
            self.rundownThreshold, self.rundownCount)

        print(rtext)

        if not silent:
            ###Make a pop up window of these results
            qmb = QDialog()
            qmb.setWindowTitle('Rundown {}'.format(self.name))
            qmb.setGeometry(800, 600, 600, 600)
            self.rundownText = QtGui.QTextEdit()
            font = QtGui.QFont()
            font.setFamily('Courier')
            font.setFixedPitch(True)
            font.setPointSize(12)
            self.rundownText.setCurrentFont(font)
            self.rundownText.setText(rtext)
            self.rundownText.setReadOnly(True)

            #add buttons, make it the right size
            qmb.layout = QVBoxLayout()
            qmb.layout.addWidget(self.rundownText)
            qmb.setLayout(qmb.layout)
            qmb.exec_()

    def scrapePeaks(self):
        """Some peak-finding function with output filtering based on SNR"""

        self.prepGuiParameters()
        self.pk_extracted_by_condi = {}

        for _condi in self.tracedata.keys():
            maxVal = len(self.tPeaks)

            ROI_df = self.tracedata[_condi]
            #print (ROI_df)

            peaksList = []
            progMsg = "Get {0} peaks, {1} set..".format(maxVal, _condi)
            with pg.ProgressDialog(progMsg, 0, maxVal) as dlg:
                dlg.setMinimumWidth(300)
                for t in self.tPeaks:
                    dlg += 1
                    idx = np.searchsorted(ROI_df.index, t)
                    # avoid falling off start or end of columns
                    e = max(idx - self.psr, 0)
                    # zero biased so add one.
                    l = min(idx + self.psr + 1, len(ROI_df.index))
                    print(t, e, idx, l, ROI_df.iloc[e:l])

                    p = ROI_df.iloc[e:l].max().to_frame().transpose()
                    peaksList.append(p)

                #stick rows together (all have same zero index...)
                peaksdf = pd.concat(peaksList)

                # Overwrite index with the original peak positions
                # (somewhat inexact because of the 'range')
                peaksdf.index = self.tPeaks
                self.pk_extracted_by_condi[_condi] = peaksdf

        # yes, output may be modified below
        self.peaksScraped = True
        self.acceptBtn.setEnabled(True)
        self.getRundownBtn.setEnabled(True)
        self.noiseRB.setEnabled(True)
        self.noiseSB.setEnabled(True)
        self.excludedListedByCondi = {}

        if self.ignore:

            # freshly excludedList peaks from traces with low SNR
            self.maskLowSNR()
            self.splitAllowedExcluded()

    def splitAllowedExcluded(self):
        # the cut-off value
        _cut = self.excludeSNRcut

        #split peak data into sets from high and low SNR
        for s in self.pk_extracted_by_condi.keys():
            wls = self.allowedLists[s]
            bls = self.excludedLists[s]
            pk = self.pk_extracted_by_condi[s]
            allowedListed = pk[wls.sort_values(ascending=False).index]
            excludedListed = pk[bls.sort_values(ascending=False).index]

            self.pk_extracted_by_condi[s] = allowedListed
            self.excludedListedByCondi[s + "_SNR<" +
                                       str(_cut)] = excludedListed

    def prepareAccept(self):

        # substitute failures (destructively)
        if self.failures_nulled:
            self.pk_extracted_by_condi = self.pk_extracted_with_failures

        # divide peak results into Allowed list and Excluded list based on SNR
        self.splitAllowedExcluded()

        self.accept()

    def setFailures(self):
        self.failures_nulled = True
        # setting failures modifies the output destructively and must retain original!!!
        self.pk_extracted_with_failures = self.pk_extracted_by_condi.copy(
        )  #is that enough?
        if self.noiseRB.isChecked == False:
            self.noiseSB.setDisabled(True)
            return
        else:
            self.noiseSB.setEnabled(True)

        # in allowedList traces
        self.noiseCut = self.noiseSB.value()
        print("Self.noisecut {}".format(self.noiseCut))
        _numberCut = 0
        for _condi in self.tracedata:
            _peaksDF = self.pk_extracted_with_failures[_condi]
            _df = self.tracedata[_condi]
            #print (_df)
            _noise = _df.std()
            #print ("NOISE: ", _noise)
            _peaksDF = _peaksDF.where(_peaksDF > _noise * self.noiseCut, 0)
            #print ("peaksdf",_peaksDF )
            _bycol = _peaksDF.isin([0.0]).sum()
            #print ("bycol {} sum {}".format(_bycol, _bycol.sum()))
            _numberCut += _bycol.sum()
            self.pk_extracted_with_failures[_condi] = _peaksDF

        # Provide some indication of total peaks altered interactively
        self.peaksLabel.setText(
            "{} peaks set as failures ({: .1f}% of total).".format(
                _numberCut, 100 * _numberCut / self.total_peaks))

    def maskLowSNR(self):
        """split the peak output according to SNR of parent traces"""
        """moving the spinbox for SNR Cutoff also comes here"""
        print('maskLowSNR')
        if self.skipRB.isChecked == False:
            self.skipSB.setDisabled(True)
            return
        else:
            self.skipSB.setEnabled(True)

        self.excludeSNRcut = self.skipSB.value()

        # use selective region (LR?)
        # or just the whole trace?

        #store allowedLists and excludedLists as values with the set as key.
        self.allowedLists = {}
        self.excludedLists = {}
        self.allowedCount = 0
        self.excludedCount = 0

        for _condi, _tdf in self.tracedata.items():

            #_df = self.tracedata[_condi]

            # find SNR from column-wise Max / SD
            _max = _tdf.max()
            _SD = _tdf.std()
            snr = _max / _SD
            #print ("max {}, sd {}, snr {}".format(_max, _SD, snr))
            # add histogram of SNR values with 'SNRcut'-off drawn?

            self.allowedLists[_condi] = snr.where(
                snr >= self.excludeSNRcut).dropna()
            self.excludedLists[_condi] = snr.where(
                snr < self.excludeSNRcut).dropna()

            self.allowedCount += len(self.allowedLists[_condi])
            self.excludedCount += len(self.excludedLists[_condi])

            #print ("allowedList: "+_condi, self.allowedLists[_condi])
            #print ("excludedList: "+_condi, self.excludedLists[_condi])

        #update dialog
        skipLabelText = "Skipping {0} traces out of {1} for low SNR.".format(
            self.excludedCount, self.allowedCount + self.excludedCount)
        self.skipRB.setText(skipLabelText)