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))
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()
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)
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.')
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