Example #1
0
        def which_fiducial_to_delete(click_x):
            from gui.viewer import Viewer
            # first check if 'sticky' fiducial option is enabled for one of the fiducials
            sticky_fiducial = [
                item.isChecked() for item in
                Viewer.get().annotation_menu.sticky_fiducial_menu.actions()
            ]
            if any(sticky_fiducial):
                idx = np.argwhere(sticky_fiducial)[0]
                return AnnotationConfig.get().find_idx_by_name(
                    Viewer.get().annotation_menu.sticky_fiducial_menu.actions(
                    )[idx[0]].text())

            dist = np.inf
            fiducial_name, fiducial_idx = None, None
            for f_idx, f in enumerate(AnnotationConfig.get().fiducials):
                if f.annotation.x.size > 0:
                    closest_idx, _, _ = find_closest(f.annotation.x,
                                                     np.array([click_x]))
                    dist_new = abs(click_x - f.annotation.x[closest_idx])
                    if dist_new < dist:
                        dist = dist_new
                        fiducial_name, fiducial_idx = f.name, f_idx
            if not dist == np.inf:
                return fiducial_idx
Example #2
0
    def load(self, fullpath):
        try:
            hf = self._get_matfile_object(fullpath)
            assert all(s in hf.keys() for s in ['annotations', 'partitions']), r'h5 must have {} groups'.format(
                ['annotations', 'partitions'])

            assert all([s in hf['partitions'] for s in ['label', 'start', 'end']]), r'h5.partitions must have {} groups'.format(
                ['label', 'start', 'end'])
            labels = hf['partitions/label']
            labels = [n.decode('ascii', 'ignore') for n in labels]
            start = np.array(hf['partitions/start'])
            end = np.array(hf['partitions/end'])
            assert len(labels) == start.size & start.size == end.size, 'Every partition should have label, start and end'
            Partitions.add_all(labels, start, end)

            from logic.operation_mode.annotation import AnnotationConfig
            assert all([s in AnnotationConfig.all_fiducials() for s in hf['annotations']]), 'All h5.annotations must be in {} groups'.format(
                AnnotationConfig.all_fiducials())
            for f_name in hf['annotations'].keys():
                self._set_annotation_from_time(f_name, np.array(hf['annotations/' + f_name + '/ts']))
            from gui.viewer import Viewer
            try:  # when loaded during initialization
                Viewer.get().selectedDisplayPanel.plot_area.redraw_fiducials()  # to update and show loaded data
            except:
                pass

            try:  # can be removed after thorough testing
                if 'epoch' in hf.keys():
                    assert all(
                        [f in hf['epoch'] for f in
                         ['start', 'end', 'is_modified', 'label', 'all_labels', 'keys',
                          'default_label']]), 'Loaded file contains incorrect epoch mode data'

                    labels = [n.decode('ascii', 'ignore') for n in hf['epoch/label']]
                    epoch_data = pd.DataFrame(
                        {'start': hf['epoch/start'], 'end': hf['epoch/end'], 'is_modified': hf['epoch/is_modified'], 'label': labels})
                    keys = [n.decode('ascii', 'ignore') for n in hf['epoch/keys']]
                    all_labels = [n.decode('ascii', 'ignore') for n in hf['epoch/all_labels']]
                    description = [n.decode('ascii', 'ignore') for n in hf['epoch/description']]
                    default_label = hf['epoch/default_label'][0]
                    NONE_LABEL = hf['epoch/NONE_LABEL'][0]

                    EpochModeConfig.load_from_hdf5(epoch_data, keys, all_labels, default_label, NONE_LABEL, description=description)
            except Exception as e:
                Dialog().warningMessage('Epoch mode data cannot be loaded\r\n' +
                                        'The error was:\r\n' + str(e))

        except Exception as e:
            Dialog().warningMessage('Loading existing annotations failed\r\n' +
                                    'The error was:\r\n' + str(e))
Example #3
0
    def clear_annotations_in_this_partition(p: SinglePartition):
        """
        batch removing annotations which fall within a partition.
        good to have if it is needed to clean large artifact region from spurious fiducials
        """
        try:
            from logic.operation_mode.annotation import AnnotationConfig
            from gui.viewer import Viewer
            aConf = AnnotationConfig.get()
            for f in aConf.fiducials:
                ann = f.annotation
                remove_idx = np.arange(bisect.bisect_right(ann.x, p.start), bisect.bisect_left(ann.x, p.end))
                nn = max(remove_idx.shape)
                result = QtWidgets.QMessageBox.question(Viewer.get(), "Confirm Delete Annotations...",
                                                        "Are you sure you want to delete {nn} {name} annotations ?".format(nn=nn, name=ann.name),
                                                        QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                if result == QtWidgets.QMessageBox.Yes:
                    ann.x = np.delete(ann.x, remove_idx)
                    ann.y = np.delete(ann.y, remove_idx)
                    ann.idx = np.delete(ann.idx, remove_idx)
                    Viewer.get().selectedDisplayPanel.plot_area.redraw_fiducials()
            Partitions.update_all_bounds()

        except Exception as e:
            Dialog().warningMessage('Deleting annotations failed with\r\n' + str(e))
Example #4
0
    def redraw_fiducials(self):
        if self.selected_view() is None:
            return
        main_view = PlotArea.get_main_view()
        if main_view is None:
            return
        main_track = main_view.renderer.track
        vb = main_view.renderer.vb

        for item in vb.temporary_items:
            vb.removeItem(item)
        vb.temporary_items.clear()
        x_min, x_max = self.main_vb.viewRange()[0]
        if Mode.mode in [
                Modes.annotation, Modes.browse, Modes.partition, Modes.epoch
        ]:  # NB: change to disable drawing annotations in other modes
            if Mode.mode == Modes.epoch and EpochModeConfig.get(
            ).toggle_fiducials == False:
                return  # if EpochMode and Fiducials are switched off
            if hasattr(main_track, 'aConf'):
                aConf = AnnotationConfig.get()
                for a in aConf:
                    points_x, points_y = a.annotation.find_annotation_between_two_ts(
                        x_min, x_max)
                    if points_x.size > 0 and points_y.size > 0:
                        loadedFiducials = pg.PlotDataItem(
                            points_x,
                            points_y,
                            symbol=a.symbol,
                            symbolSize=a.symbol_size,
                            pen=None,
                            symbolPen=a.symbol_pen,
                            name=a.name)
                        vb.addItem(loadedFiducials)
                        vb.temporary_items.append(loadedFiducials)
Example #5
0
 def _set_annotation_from_idx(self, fiducial_name, idx: np.ndarray):
     idx = idx.astype(int)
     assert self.tracks is not None and self.main_track_label is not None, 'tracks are not set or main_track_label is not specified'
     assert self.aConf_is_loaded(), 'annotation configuration is not loaded at the moment you try to set annotation'
     assert fiducial_name in [s.name for s in self.tracks[self.main_track_label].aConf.fiducials]
     from logic.operation_mode.annotation import AnnotationConfig
     aConf = AnnotationConfig.get()
     aConf.fiducials[aConf.find_idx_by_name(fiducial_name)].set_annotation_from_idx(idx, self.tracks[self.main_track_label])
Example #6
0
 def _set_annotation_from_time(self, fiducial_name, ts):
     assert self.tracks is not None and self.main_track_label is not None
     assert self.aConf_is_loaded()
     assert fiducial_name in [s.name for s in self.tracks[self.main_track_label].aConf.fiducials], '{} fiducial is not listed in {}'.format(
         fiducial_name, self.annotation_config_file.stem)
     from logic.operation_mode.annotation import AnnotationConfig
     aConf = AnnotationConfig.get()
     aConf.fiducials[aConf.find_idx_by_name(fiducial_name)].set_annotation_from_time(ts, self.tracks[self.main_track_label])
Example #7
0
 def _save_as_csv(self, *, filename: str, save_idx: bool):
     from logic.operation_mode.annotation import AnnotationConfig
     aConf = AnnotationConfig.get()
     fullpath = pathlib.Path(self.output_folder, 'annotation_' + filename).as_posix()
     aConf.to_csv(fullpath, save_idx=save_idx)
     fullpath = pathlib.Path(self.output_folder, 'partition_' + filename).as_posix()
     Partitions.to_csv(fullpath)
     fullpath = pathlib.Path(self.output_folder, 'epoch_' + filename).as_posix()
     EpochModeConfig.to_csv(fullpath)
     qInfo('{} saved'.format(fullpath))
Example #8
0
 def which_fiducial_to_add(last_keypress_event_key):
     from gui.viewer import Viewer
     # first check if 'sticky' fiducial option is enabled for one of the fiducials
     sticky_fiducial = [
         item.isChecked() for item in
         Viewer.get().annotation_menu.sticky_fiducial_menu.actions()
     ]
     if any(sticky_fiducial):
         idx = np.argwhere(sticky_fiducial)[0]
         return AnnotationConfig.get().find_idx_by_name(
             Viewer.get().annotation_menu.sticky_fiducial_menu.actions(
             )[idx[0]].text())
     # if 'sticky' fiducial option is off, check what key was pressed the last
     default_fiducial_idx = 0  # default: first fiducial
     if last_keypress_event_key is not None:
         qInfo('Last pressed: ' + str(last_keypress_event_key[1]))
         for fiducial_idx, f in enumerate(
                 AnnotationConfig.get().fiducials):
             if f.key.lower() == last_keypress_event_key[1].lower():
                 return fiducial_idx
         return default_fiducial_idx
     else:
         return default_fiducial_idx
Example #9
0
    def load_annotation_config_from_csv(self, fileName=None):
        fn = fileName or self.fileName
        if not fn:
            fn, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Load AnnotationConfig", get_project_root().as_posix(),
                                                          " (*.csv);; All Files (*)", options=QtWidgets.QFileDialog.Options())

        if fn:
            from gui import PALMS
            with open(fn, "r") as csv:
                settings_init = pd.read_csv(csv)
                fiducials = []
                for _, row_data in settings_init.iterrows():
                    try:
                        assert all([k in row_data for k in PALMS.config['annotationConfig_columns']])
                    except:
                        Dialog().warningMessage('Columns in chosen {file} file do not match aConfColumns from config.py. Try again! '
                                                ''.format(file=fn))
                        return
                    fiducials.append(SingleFiducialConfig(row_data))

            aConf = AnnotationConfig.get()
            aConf.reset_fiducials_config(fiducials)
            self.show()
Example #10
0
    def save(self, **kwargs):
        # TODO: popup warning when rewriting existing files
        try:
            from gui.viewer import Viewer
            filename = kwargs.get('filename', self.fullpath.stem)

            try:
                filename = self.outputfile_prefix + filename
            except Exception as e:
                qInfo('Output file prefix could not be added')

            fullpath = pathlib.Path(self.output_folder, filename + '.h5')
            OVERWRITE = kwargs.get('OVERWRITE', Viewer.get().settings_menu.save_overwrite_action.isChecked())
            if fullpath.is_file():  # don't overwrite files
                if not OVERWRITE:
                    path, filename = os.path.split(fullpath)
                    filename = os.path.splitext(filename)[0]
                    newfilename = filename + '_' + strftime("%Y_%m_%d_%H_%M_%S", gmtime()) + fullpath.suffix
                    fullpath = pathlib.Path(path, newfilename)
                    qInfo('Existing file found. Not overwriting')
                else:
                    qInfo('Existing file OVERWRITTEN!')

            from logic.operation_mode.annotation import AnnotationConfig
            aConf = AnnotationConfig.get()
            hf = h5py.File(fullpath, 'w')

            group_annotations = hf.create_group('annotations')
            for f_idx, f in enumerate(aConf.fiducials):
                group_annotations.create_group(f.name)
                group_annotations.create_dataset(f.name + '/ts', data=f.annotation.x)
                group_annotations.create_dataset(f.name + '/idx', data=f.annotation.idx)
                group_annotations.create_dataset(f.name + '/amp', data=f.annotation.y)

            group_partitions = hf.create_group('partitions')
            asciiList = [n.encode("ascii", "ignore") for n in Partitions.all_labels()]
            group_partitions.create_dataset('label', data=asciiList)
            group_partitions.create_dataset('start', data=Partitions.all_startpoints())
            group_partitions.create_dataset('end', data=Partitions.all_endpoints())

            group_epoch = hf.create_group('epoch')
            group_epoch.create_dataset('start', data=EpochModeConfig.get().window_data['start'].values)
            group_epoch.create_dataset('end', data=EpochModeConfig.get().window_data['end'].values)
            group_epoch.create_dataset('is_modified', data=EpochModeConfig.get().window_data['is_modified'].values)
            asciiList = [n.encode("ascii", "ignore") for n in EpochModeConfig.get().window_data['label'].values]
            group_epoch.create_dataset('label', data=asciiList)
            asciiList = [n.encode("ascii", "ignore") for n in EpochModeConfig.get().keys]
            group_epoch.create_dataset('keys', data=asciiList)

            asciiList = [n.encode("ascii", "ignore") for n in EpochModeConfig.get().labels]
            group_epoch.create_dataset('all_labels', data=asciiList)

            asciiList = [n.encode("ascii", "ignore") for n in EpochModeConfig.get().description]
            group_epoch.create_dataset('description', data=asciiList)

            dt = h5py.special_dtype(vlen=str)
            group_epoch.create_dataset('default_label', (1,), dtype=dt)
            group_epoch['default_label'][:] = EpochModeConfig.get().default_label
            group_epoch.create_dataset('NONE_LABEL', (1,), dtype=dt)
            group_epoch['NONE_LABEL'][:] = EpochModeConfig.get().NONE_LABEL

            group_meta = hf.create_group('meta')
            dt = h5py.special_dtype(vlen=str)
            group_meta.create_dataset('timestamp', (1,), dtype=dt)
            group_meta['timestamp'][:] = strftime("%Y_%m_%d_%H_%M_%S", gmtime())

            group_meta.create_dataset('filename', (1,), dtype=dt)
            group_meta['filename'][:] = self.fullpath.stem
            group_meta.create_dataset('filepath', (1,), dtype=dt)
            group_meta['filepath'][:] = self.fullpath.parent.as_posix()
            group_meta.create_dataset('main_track_label', (1,), dtype=dt)
            group_meta['main_track_label'][:] = self.main_track_label

            if Viewer.get().settings_menu.save_tracks_action.isChecked():
                group_tracks = hf.create_group('tracks')
                for label, track in Database.get().tracks.items():
                    group_tracks.create_dataset(label + '/ts', data=track.ts)
                    group_tracks.create_dataset(label + '/amp', data=track.value)
                    group_tracks.create_dataset(label + '/offset', data=track.offset)
                    group_tracks.create_dataset(label + '/fs', data=track.fs)

            hf.close()
            qInfo('{} saved'.format(fullpath.as_posix()))
        except Exception as e:
            try:
                hf.close()
            except:
                pass
            self._save_as_csv(filename=self.fullpath.stem, save_idx=False)
            Dialog().warningMessage('Default save crashed\r\n' +
                                    e.__repr__() +
                                    '\r\nSaved using deprecated method, as CSV files.')
Example #11
0
 def set_annotation_config(self):
     # TODO: bind this to button load csv in annotationConfigDialog
     assert self.annotation_config_file is not None and self.tracks is not None
     from logic.operation_mode.annotation import AnnotationConfig
     self.tracks[self.main_track_label].aConf = AnnotationConfig.from_csv(csv=self.annotation_config_file.as_posix())
Example #12
0
 def show(self):
     self.aConf_to_table(AnnotationConfig.get())
     super().show()
Example #13
0
 def update_aConf(self, **kwargs):
     aConf = AnnotationConfig.get()
     fiducials = self.table_to_fiducials()
     aConf.reset_fiducials_config(fiducials)
     self.table.clear()
     self.aConf_to_table(aConf)
Example #14
0
    def viewPopup(self, point):
        if isinstance(self.sender(), QtWidgets.QHeaderView):
            row = self.sender().logicalIndexAt(point)
        elif isinstance(self.sender(), QtWidgets.QLabel):
            row = self.rowFromWidget(self.sender())
        else:
            logging.error(f'do not know how to handle getting index of ',
                          f'{self.sender()} object')
            self.main_window.application.viewer.status(
                f'do not know how to handle getting index of ',
                f'{self.sender()} object')
            raise TypeError
        view = self.panel.views[row]
        menu = QtWidgets.QMenu(self.verticalHeader())
        menu.clear()
        move_menu = menu.addMenu('&Move View')
        link_menu = menu.addMenu("&Link Track")
        copy_menu = menu.addMenu("Copy View")

        derive_menu = menu.addMenu("Add derived tracks")

        linkAction = QtWidgets.QAction('Create Link in this Panel', self)
        linkAction.triggered.connect(
            partial(self.display_panel.linkTrack, view,
                    self.main_window.model.panels.index(self.panel)))
        link_menu.addAction(linkAction)
        link_menu.addSeparator()
        link_menu.setEnabled(False)

        copyAction = QtWidgets.QAction("Duplicate View in this Panel", self)
        copyAction.triggered.connect(
            partial(self.display_panel.copyView, view,
                    self.main_window.model.panels.index(self.panel)))
        copy_menu.addAction(copyAction)
        copy_menu.addSeparator()
        copy_menu.setEnabled(False)

        addDerivativeAction = QtWidgets.QAction('1st derivative', self)
        addDerivativeAction.triggered.connect(
            partial(self.display_panel.addDerivative, view,
                    self.main_window.model.panels.index(self.panel), 1))
        # TODO: derivative filters GUI
        derive_menu.addAction(addDerivativeAction)

        addDerivativeAction = QtWidgets.QAction('2nd derivative', self)
        addDerivativeAction.triggered.connect(
            partial(self.display_panel.addDerivative, view,
                    self.main_window.model.panels.index(self.panel), 2))
        derive_menu.addAction(addDerivativeAction)

        menu.addSeparator()

        try:
            addRRintervalMenu = menu.addMenu('RR-intevals')
            from logic.operation_mode.annotation import AnnotationConfig
            RRintervalMenu_actions = []
            for f in AnnotationConfig.all_fiducials():
                f_idx = AnnotationConfig.get().find_idx_by_name(f)
                if AnnotationConfig.get(
                ).fiducials[f_idx].annotation.x.size > 2:
                    action = QtWidgets.QAction(f,
                                               self,
                                               checkable=False,
                                               enabled=True)
                    action.triggered.connect(
                        partial(
                            self.main_window.application.add_view_from_track,
                            AnnotationConfig.get().fiducials[f_idx].annotation.
                            create_RRinterval_track(),
                            self.main_window.model.panels.index(self.panel)))
                    RRintervalMenu_actions.append(action)
                    addRRintervalMenu.addAction(action)
        except Exception as e:
            Dialog().warningMessage('Creating RR interval plot failed\r\n'
                                    'The error was:\r\n' + str(e))

        # TODO: load another track
        # TODO: move existing view

        db = Database.get()
        add_menu = menu.addMenu("Add tracks from DB")
        add_menu.setEnabled(False)
        if db is not None and db.ntracks() > 0:
            add_menu.setEnabled(True)
            for label, track in db.tracks.items():
                plot_signal_action = QtWidgets.QAction(label, self)
                plot_signal_action.triggered.connect(
                    partial(self.main_window.application.add_view_from_track,
                            track,
                            self.main_window.model.panels.index(self.panel)))
                add_menu.addAction(plot_signal_action)
                if label not in self.allViewsTrackLabels():
                    plot_signal_action.setEnabled(True)
                else:
                    plot_signal_action.setEnabled(False)

        menu.addSeparator()
        process_action = QtWidgets.QAction('Processor Config', self)
        process_action.triggered.connect(
            partial(self.main_window.application.viewer.processorConfig.show,
                    self.selectedView()))
        menu.addAction(process_action)
        process_action.setEnabled(False)

        menu.addSeparator()
        invertAction = QtWidgets.QAction('&Invert Track', self)
        invertAction.triggered.connect(self.main_window.invertView)
        invertAction.setEnabled(False)
        menu.addAction(invertAction)

        menu.addSeparator()
        deleteAction = QtWidgets.QAction('&Delete Track', self)
        deleteAction.triggered.connect(self.main_window.guiDelView)
        menu.addAction(deleteAction)

        for index, panel in enumerate(self.main_window.model.panels):
            if panel is self.panel:
                continue
            linkAction = QtWidgets.QAction(f'Link to Panel {index + 1}', self)
            linkAction.triggered.connect(
                partial(self.display_panel.linkTrack, view, index))
            link_menu.addAction(linkAction)

            moveAction = QtWidgets.QAction(f'Move To Panel {index + 1}', self)
            moveAction.triggered.connect(
                partial(self.display_panel.moveView, view, index))
            move_menu.addAction(moveAction)

            copyAction = QtWidgets.QAction(f'Copy to Panel {index + 1}', self)
            copyAction.triggered.connect(
                partial(self.display_panel.copyView, view, index))
            copy_menu.addAction(copyAction)

        moveAction = QtWidgets.QAction(f'Move to New Panel', self)
        moveAction.triggered.connect(
            partial(self.display_panel.moveView, view, -1))

        linkAction = QtWidgets.QAction(f'Link to New Panel', self)
        linkAction.triggered.connect(
            partial(self.display_panel.linkTrack, view, -1))

        copyAction = QtWidgets.QAction(f'Copy to New Panel', self)
        copyAction.triggered.connect(
            partial(self.display_panel.copyView, view, -1))

        move_menu.addSeparator()
        link_menu.addSeparator()
        copy_menu.addSeparator()
        move_menu.addAction(moveAction)
        link_menu.addAction(linkAction)
        copy_menu.addAction(copyAction)
        menu.popup(QtGui.QCursor.pos())
Example #15
0
    def mousePressEvent(self, event: QtGui.QMouseEvent):
        """
        The following only has effect if the main track is selected in the track table view on the right
        Annotation mode:
            **LeftMouseButton** places a new fiducial. By default it is the first fiducial as set in the annotationConfig,
            unless before that a keyboard button was pressed corresponding to another fiducial or "sticky fiducial" mode is on.
            **RightMouseButton** removes the nearest fiducial (default), unless "sticky fiducial" mode is on. Keyboard has no effect
        Partition mode:
            **CTRL + LeftMouseButton** creates a new partition which takes 2% of the whole track duration or less to avoid overlapping
            partiotions;
            **CTRL + RightMouseButton** removes partition under the click
            **SHIFT + LeftMouseButton** to drag partition borders or move the partition. Repositioning is possible within the limits of
            neighboring partition. Moving the partition fully inside another one or reducing its size to 1 sample deletes the partition.
            #NOTE: creating partition of desired size directly by click and drag might not be that convenient and harder to implement
        Epoch mode:

        # NB: when adding\removing mouse click operations also adapt self.mouseReleaseEvent() and self.mouseMoveEvent()
        """
        def which_fiducial_to_add(last_keypress_event_key):
            from gui.viewer import Viewer
            # first check if 'sticky' fiducial option is enabled for one of the fiducials
            sticky_fiducial = [
                item.isChecked() for item in
                Viewer.get().annotation_menu.sticky_fiducial_menu.actions()
            ]
            if any(sticky_fiducial):
                idx = np.argwhere(sticky_fiducial)[0]
                return AnnotationConfig.get().find_idx_by_name(
                    Viewer.get().annotation_menu.sticky_fiducial_menu.actions(
                    )[idx[0]].text())
            # if 'sticky' fiducial option is off, check what key was pressed the last
            default_fiducial_idx = 0  # default: first fiducial
            if last_keypress_event_key is not None:
                qInfo('Last pressed: ' + str(last_keypress_event_key[1]))
                for fiducial_idx, f in enumerate(
                        AnnotationConfig.get().fiducials):
                    if f.key.lower() == last_keypress_event_key[1].lower():
                        return fiducial_idx
                return default_fiducial_idx
            else:
                return default_fiducial_idx

        def which_fiducial_to_delete(click_x):
            from gui.viewer import Viewer
            # first check if 'sticky' fiducial option is enabled for one of the fiducials
            sticky_fiducial = [
                item.isChecked() for item in
                Viewer.get().annotation_menu.sticky_fiducial_menu.actions()
            ]
            if any(sticky_fiducial):
                idx = np.argwhere(sticky_fiducial)[0]
                return AnnotationConfig.get().find_idx_by_name(
                    Viewer.get().annotation_menu.sticky_fiducial_menu.actions(
                    )[idx[0]].text())

            dist = np.inf
            fiducial_name, fiducial_idx = None, None
            for f_idx, f in enumerate(AnnotationConfig.get().fiducials):
                if f.annotation.x.size > 0:
                    closest_idx, _, _ = find_closest(f.annotation.x,
                                                     np.array([click_x]))
                    dist_new = abs(click_x - f.annotation.x[closest_idx])
                    if dist_new < dist:
                        dist = dist_new
                        fiducial_name, fiducial_idx = f.name, f_idx
            if not dist == np.inf:
                return fiducial_idx

        try:
            from gui.viewer import Viewer
            Viewer.get().selectFrame(self.display_panel.parent(
            ))  # first select the frame where the click was made

            if Mode.is_epoch_mode():
                EpochModeConfig.get().process_mouseclick(event)
                return

            vb = self.vbs[self.selected_view()]
            click_x = vb.mapSceneToView(event.pos()).x()
            if self.selected_view().track.label is Database.get(
            ).main_track_label:  # TODO: do this check properly and uniformly everywhere
                if Mode.is_annotation_mode():
                    if AnnotationConfig.get().is_valid():
                        if event.button(
                        ) == QtCore.Qt.LeftButton:  # Left click to mark
                            fiducial_idx = which_fiducial_to_add(
                                self.last_keypress_event_key)
                            AnnotationConfig.get().fiducials[
                                fiducial_idx].annotation.signal_annotate.emit(
                                    click_x)
                        elif event.button(
                        ) == pg.QtCore.Qt.RightButton:  # right click to delete
                            fiducial_idx = which_fiducial_to_delete(click_x)
                            if fiducial_idx is not None:
                                AnnotationConfig.get().fiducials[
                                    fiducial_idx].annotation.signal_delete_annotation.emit(
                                        click_x)
                            else:
                                qInfo('No annotation found to be deleted')
                        self.last_keypress_event_key = None  # need to press extra key every time to annotate secondary fiducial

                elif Mode.is_partition_mode():
                    if event.button() == QtCore.Qt.LeftButton:
                        if event.modifiers() == QtCore.Qt.ControlModifier:
                            self.create_new_partition(event)
                        else:
                            super().mousePressEvent(event)
                            qInfo(
                                'CTRL+Left: create region; SHIFT+Left: move region'
                            )  # event.accept()
                    elif event.button() == QtCore.Qt.RightButton:
                        if event.modifiers() == QtCore.Qt.ControlModifier:
                            p = Partitions.find_partition_by_point(click_x)
                            if p is not None:
                                p.region_deleted()  # event.accept()
                        elif event.modifiers() == QtCore.Qt.ShiftModifier:
                            p = Partitions.find_partition_by_point(click_x)
                            if p is not None:
                                self.partition_context_menu(event)
                            else:
                                qInfo(
                                    'No partition found...CTRL+Right: delete region; SHIFT+Right: region context menu'
                                )
                        else:
                            super().mousePressEvent(event)
                            qInfo(
                                'CTRL+Right: delete region; SHIFT+Right: region context menu'
                            )
                    else:
                        super().mousePressEvent(event)
                elif Mode.mode == Modes.browse:
                    super().mousePressEvent(event)

            else:
                if not self.is_main_view_in_current_panel(
                ):  # click on a panel, without the main track
                    Dialog().warningMessage(
                        'Selected display panel does not contain the main track ({}).\r\n'
                        .format(Database.get().main_track_label) +
                        'Try clicking on another display panel')
                else:  # click on a correct panel, but the main track is not selected
                    Dialog().warningMessage(
                        'Selected signal is not the main one.\r\n'
                        'Click on the '
                        '{}'
                        ' track in the control area on the right.'.format(
                            Database.get().main_track_label))
                return
        except Exception as e:
            Dialog().warningMessage('Mouse click processing failed\r\n'
                                    'What unusual did you do?\r\n' + str(e))
            return