示例#1
0
    def zoomChanged(self):
        try:  # this is to avoid redrawing if it is already zoomed out to max
            newRange = self.main_window.selectedView.renderer.vb.targetRange(
            )[0]
            viewRange = self.main_window.selectedView.renderer.vb.viewRange(
            )[0]
            # newRange = self.main_vb.viewRange()[0]
            if newRange[-1] >= Database.get().get_longest_track_duration(
            ) and newRange[0] <= 0:  # TODO what if offset not 0
                if self.FLAG_full_zoom_out:
                    return
                else:
                    self.FLAG_full_zoom_out = True
            else:
                self.FLAG_full_zoom_out = False
        except:
            pass

        if self.main_vb.geometry():
            try:
                pixel_width = self.main_vb.viewPixelSize()[0]
                self.main_vb.setLimits(xMin=-pixel_width)
                for vb in self.vbs.values():
                    vb.setLimits(xMin=-pixel_width)
                self.redraw_fiducials()
                if self.display_panel is not None and len(
                        self.display_panel.panel.views) > 0:
                    self.setYRange()
                EpochModeConfig.get().redraw_epochs()
            except Exception as e:
                Dialog().warningMessage(
                    'Exception occured\r\n'
                    'Using more than one frame may have caused this!\r\n' +
                    str(e))
示例#2
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))
示例#3
0
 def keyPressEvent(self, event):
     """
     #TODO: what else can be parametrized with keypresses?
     """
     if Mode.is_epoch_mode():
         # print((event.key(), event.text()))
         from logic.operation_mode.epoch_mode import EpochModeConfig
         EpochModeConfig.get().process_keypress(event.text())
     else:
         # save last pressed button to later decide which fiducial is to be marked
         self.last_keypress_event_key = (event.key(), event.text())
         qInfo('Key pressed: {}'.format(event.text()))
         event.accept()
示例#4
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))
示例#5
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)
示例#6
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.')
示例#7
0
 def set_epochMode_config(self):
     from logic.operation_mode.epoch_mode import EpochModeConfig
     if not self.epoch_config_file is None:
         EpochModeConfig.initialize_epoch_mode_settings_from_csv(csv=self.epoch_config_file.as_posix())
     else:
         EpochModeConfig()
示例#8
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