class Viewer: """ abstraction layer on viewer that dispatches visualisation to specific components and implements widgets for DataSet functionality """ def __init__(self, dataset): self.dataset = dataset self.napari_viewer = None self.plots = None self.blik_widget = None def show(self, napari_viewer=None, **kwargs): self.ensure_ready(napari_viewer=napari_viewer) for db in self.dataset: db.init_depictor(**kwargs) if self.dataset.volumes: self.show_volume(list(self.dataset.volumes.keys())[0]) if self.dataset.plots: self.plots.show() @property def shown(self): if self.napari_viewer and self.volume_selector: return self.dataset.volumes[self.volume_selector.currentText()] return None def ensure_ready(self, napari_viewer=None): if napari_viewer is not None: self._init_viewer(napari_viewer) self._init_plots() self._init_blik_widget() self._hook_keybindings() # check if viewer exists and is still open try: self.napari_viewer.window.qt_viewer.actions() except (AttributeError, RuntimeError): self._init_viewer() self._init_plots() self._init_blik_widget() self._hook_keybindings() def _init_viewer(self, napari_viewer=None): if napari_viewer is not None: self.napari_viewer = napari_viewer else: self.napari_viewer = napari.Viewer(title='napari - Blik') self.napari_viewer.scale_bar.unit = '0.1nm' self.napari_viewer.scale_bar.visible = True # TODO: workaround until layer issues are fixed (napari #2110) self.napari_viewer.window.qt_viewer.destroyed.connect(self.dataset.purge_gui) def _init_plots(self): self.plots = GraphicsLayoutWidget() self._plots_napari_widget = self.napari_viewer.window.add_dock_widget(self.plots, name='Blik - Plots', area='bottom') # use napari hide and show methods self.plots.show = self._plots_napari_widget.show self.plots.hide = self._plots_napari_widget.hide self.plots.hide() def _init_blik_widget(self): self.blik_widget = QWidget() layout = QVBoxLayout() self.blik_widget.setLayout(layout) self.volume_selector = QComboBox(self.blik_widget) self.volume_selector.addItems(self.dataset.volumes.keys()) self.volume_selector.currentTextChanged.connect(self.show_volume) layout.addWidget(self.volume_selector) self.plots_toggler = QPushButton('Show / Hide Plots') self.plots_toggler.clicked.connect(self.toggle_plots) layout.addWidget(self.plots_toggler) self._blik_napari_widget = self.napari_viewer.window.add_dock_widget(self.blik_widget, name='Blik', area='left') # use napari hide and show methods self.blik_widget.show = self._blik_napari_widget.show self.blik_widget.hide = self._blik_napari_widget.hide def _hook_keybindings(self): self.napari_viewer.bind_key('PageUp', self.previous_volume) self.napari_viewer.bind_key('PageDown', self.next_volume) def update_blik_widget(self): if self.blik_widget is not None: current_text = self.volume_selector.currentText() with block_signals(self.volume_selector): self.volume_selector.clear() self.volume_selector.addItems(self.dataset.volumes.keys()) self.volume_selector.setCurrentText(current_text) self.show() def clear_shown(self): for layer in self.napari_viewer.layers.copy(): if layer in self.dataset.napari_layers: self.napari_viewer.layers.remove(layer) self.plots.clear() def show_volume(self, volume): if volume is None: return self.volume_selector.setCurrentText(volume) datablocks = self.dataset.omni + self.dataset.volumes[volume] layers = [] plots = [] for db in datablocks: for dep in db.depictors: if hasattr(dep, 'layers'): if not dep.layers: dep.depict() layers.extend(dep.layers) elif hasattr(dep, 'plot'): if not dep.plot.curves: dep.depict() plots.append(dep.plot) layers = sorted(layers, key=lambda l: isinstance(l, napari.layers.Image), reverse=True) self.clear_shown() self.napari_viewer.layers.extend(layers) for plt in plots: self.plots.addItem(plt) def previous_volume(self, viewer=None): idx = self.volume_selector.currentIndex() previous_idx = (idx - 1) % self.volume_selector.count() self.volume_selector.setCurrentIndex(previous_idx) def next_volume(self, viewer=None): idx = self.volume_selector.currentIndex() next_idx = (idx + 1) % self.volume_selector.count() self.volume_selector.setCurrentIndex(next_idx) def toggle_plots(self): if self.plots.isVisible(): self.plots.hide() else: self.plots.show()
class EEGViewer(QThread): """docstring for EEGViewer""" StoppedState = 0 PausedState = 1 RunningState = 2 def __init__(self, mode='single', rows=4): super(EEGViewer, self).__init__() self.mode = mode self.rows = rows self.view = GraphicsLayoutWidget() self.view.setAntialiasing(True) self.view.setWindowTitle('EEG Viewer') self.state = self.StoppedState self.position = 0 self.maxPosition = 0 self.plotItem = list() self.plotTrace = dict() # Holders self.wait = 0 self.wsize = 0 self.hsize = 0 self.color = dict() self.window = list([0, 0]) self.channel = list() def widget(self): return self.view def show(self): self.view.show() def hide(self): self.view.hide() def getState(self): return self.state def isVisible(self): return self.view.isVisible() def setSize(self, width, height): self.view.resize(width, height) def configure(self, channel, color, wsize, fs=0): # Link params nCh = len(channel) self.wait = 1 / (fs * nCh) if fs > 0 else 0 self.wsize = wsize self.hsize = wsize / 2 self.color = color self.channel = channel self.window = np.array([0, wsize]) # Remove previous items and traces self.view.clear() self.plotItem.clear() self.plotTrace.clear() # Create new canvas if self.mode == 'single': self.singleLayout() else: self.multipleLayout() def singleLayout(self): canvas = self.view.addPlot(0, 0) canvas.disableAutoRange() canvas.setClipToView(True) canvas.setLimits(yMin=0, yMax=1) canvas.setDownsampling(mode='subsample') canvas.showGrid(x=True, y=True, alpha=0.25) for ch in self.channel: pen = mkPen(color=self.color[ch], width=2) self.plotTrace[ch] = canvas.plot(pen=pen) self.plotItem.append(canvas) def multipleLayout(self): col = 0 rowLimit = self.rows for i, ch in enumerate(self.channel): pen = mkPen(color=self.color[ch], width=2) canvas = self.view.addPlot(i % rowLimit, col) canvas.disableAutoRange() canvas.setClipToView(True) canvas.setLimits(yMin=0, yMax=1) canvas.setDownsampling(mode='subsample') canvas.showGrid(x=True, y=True, alpha=0.25) self.plotItem.append(canvas) self.plotTrace[ch] = canvas.plot(pen=pen) if (i + 1) % rowLimit == 0: col += 1 def plotData(self, D): for ch in self.channel: self.plotTrace[ch].setData(D[ch].values) self.position = 0 self.maxPosition = D.index.size def addMark(self, position, label=None): for canvas in self.plotItem: pen = mkPen(color='g', width=2.5, style=Qt.DashLine) hpen = mkPen(color='r', width=2.5, style=Qt.DashLine) mark = canvas.addLine(x=position, pen=pen, label=label, labelOpts={'position': 0.9}, movable=True, hoverPen=hpen) return mark def setPosition(self, position): self.window[0] = position - self.hsize self.window[1] = position + self.hsize self.position = position self.update() def update(self): for plot in self.plotItem: plot.setRange(xRange=self.window) self.position += 1 if self.position < self.maxPosition else 0 def play(self): self.state = self.RunningState self.start() def pause(self): self.state = self.PausedState def toggle(self): self.state = self.PausedState if self.state == self.RunningState else self.RunningState def stop(self): self.state = self.StoppedState self.quit() self.setPosition(0) def run(self): while True: if self.state == self.RunningState: self.setPosition(self.position) elif self.state == self.PausedState: pass else: break sleep(self.wait)