class ConditionDialog(QDialog): """ Create a new binary column on a set of localizations by drawing a threshold on a 1D histogram of some attribute for those localizations. For example, threshold only spots with low intensity (I0) or something. init ---- locs : pandas.DataFrame parent : root QWidget """ def __init__(self, locs, parent=None): super(ConditionDialog, self).__init__(parent=parent) self.locs = locs self.initUI() def initUI(self): """ Initialize user interface. """ L = QGridLayout(self) self.resize(500, 300) widget_align = Qt.AlignLeft # Available columns for recondition: all numeric columns self.columns = list(filter( lambda c: self.locs[c].dtype in ['float64', 'float32', \ 'uint8', 'uint16', 'int64'], self.locs.columns)) # For the default, choose `I0` if available; otherwise # choose the first column init_col = 'I0' if ('I0' in self.columns) else self.columns[0] self.load_col(init_col) # Main plot self.PlotWidget = PlotWidget(name="Create Boolean attribute") L.addWidget(self.PlotWidget, 0, 0, alignment=widget_align) # Histogram self.curve = self.PlotWidget.plot(self.bin_c, self.H, clickable=True) # User threshold, as a LinearRegionItem from pyqtgraph self.LinearRegion = LinearRegionItem([self.hmin, (self.hmax-self.hmin)*0.25+self.hmin]) self.PlotWidget.addItem(self.LinearRegion) # Drop-down menu to select the column self.M_select_col = LabeledQComboBox(self.columns, "Attribute", init_value=init_col, parent=self) self.M_select_col.assign_callback(self.M_select_col_callback) L.addWidget(self.M_select_col, 1, 0, alignment=widget_align) # Accept the current threshold self.B_accept = QPushButton("Accept", parent=self) L.addWidget(self.B_accept, 2, 0, alignment=widget_align) self.B_accept.clicked.connect(self.B_accept_callback) self.update_histogram() def load_col(self, col): """ Get data from a specific column in the locs dataframe. args ---- col : str """ self.data = np.asarray(self.locs[col]) # Histogram limits self.hmin = self.data.min() self.hmax = np.percentile(self.data, 99.9) # Binning scheme n_bins = 5000 bin_size = (self.hmax - self.hmin) / n_bins self.bin_edges = np.arange(self.hmin, self.hmax, bin_size) # Bin the data according to the binning scheme self.H, _edges = np.histogram(self.data, bins=self.bin_edges) self.bin_c = self.bin_edges[:-1] + (self.bin_edges[1]-self.bin_edges[0])/2.0 def update_histogram(self): """ Update the main histogram with data from a new column """ self.PlotWidget.clear() self.curve = self.PlotWidget.plot(self.bin_c, self.H) self.curve.setPen('w') # Set default values for linear rect region self.LinearRegion.setRegion((self.hmin, np.percentile(self.data, 50))) self.PlotWidget.addItem(self.LinearRegion) self.curve.updateItems() def M_select_col_callback(self): """ Select the current attribute to filter on. """ col = self.M_select_col.currentText() self.load_col(col) self.update_histogram() def B_accept_callback(self): """ Set the return value and exit from the dialog. """ self.return_val = ( self.LinearRegion.getRegion(), self.M_select_col.currentText(), ) self.accept()
class arrayNormaliserNode(Node): nodeName = 'arrayNormaliser' sigUpdatePlot = QtCore.Signal(object) def __init__(self, name): Node.__init__(self, name, terminals={ 'dataIn': { 'io': 'in' }, 'dataOut': { 'io': 'out' }, 'plotItems': { 'io': 'out' } }) color = (220, 220, 25, 255) self.plotDataItem = PlotDataItem(stepMode=True, fillLevel=0, pen={ 'color': color, 'width': 2 }) self.plotRegion = LinearRegionItem([0, 1], movable=True) self.plotRegion.sigRegionChangeFinished.connect(self.regionChanged) self.sigUpdatePlot.connect(self.updatePlot) def updatePlot(self, xy): self.plotDataItem.setData(*xy) def regionChanged(self): self.regionLimits = self.plotRegion.getRegion() self.update() def process(self, dataIn, display=True): if len(dataIn.shape) != 1: data = dataIn[:, -1] else: data = dataIn self.extremeLimits = np.nanmin(data), np.nanmax(data) # if not self.plotWidget.closed: # the plotWidget attribute is never removed but it is invalidated when the widget is closed y, x = np.histogram(data, bins=100) # self.plotWidget.clear() self.sigUpdatePlot.emit((x, y)) # self.plotWidget.addItem(self.plotRegion) if hasattr(self, 'regionLimits'): mi, ma = self.regionLimits else: mi, ma = self.extremeLimits # if hasattr(self, 'plotRegion'): # self.plotRegion.setRegion((mi, ma)) dataOut = (data - mi) / (ma - mi) # print (dataOut) return { 'dataOut': dataOut, 'plotItems': [self.plotRegion, self.plotDataItem] }
class PlotBC(Smooth1DPlot): sigBackgroundChanged = pyqtSignal() def __init__(self, profile: BasicProfile, parent=None): super().__init__(profile, parent) self._status = BaseLineStatus.no_baseline self.baseline_plot = self.image_view.plot_item.plot() self._init_roi() self._baseline_setup_widget = BaseLineSetup( self, self._status, **self.profile.get_parameters()) self.profile.sigDataUpdated.connect(self.update_plot) @property def y(self): if self._status == BaseLineStatus.baseline_subtracted and self.profile.baseline is not None: return self.profile.y - self.profile.baseline else: return self.profile.y def update_data(self, *args, **kwargs): self.profile.update_data(*args, **kwargs) def is_shown(self, shown: bool): self.profile.is_shown = shown def _init_toolbars(self): super()._init_toolbars() baseline_toolbar = BlackToolBar('Baseline Correction') self.addToolBar(baseline_toolbar) baseline_button = RoundedPushButton(parent=baseline_toolbar, icon=Icon('baseline'), radius=30) baseline_button.clicked.connect(self.open_baseline_setup) baseline_toolbar.addWidget(baseline_button) def _init_roi(self): self._roi = LinearRegionItem() self._roi.hide() self._roi.setBrush(QColor(255, 255, 255, 50)) self.image_view.plot_item.addItem(self._roi) def open_baseline_setup(self): if self.y is None: return setup = self._baseline_setup_widget if self.profile.x_range is None: self._set_default_bounds() self._roi.setRegion(self.profile.x_range) if self.profile.baseline is None: self._set_status(BaseLineStatus.no_baseline) # elif self._status == BaseLineStatus.no_baseline: # self._set_status(BaseLineStatus.baseline_subtracted) # else: # self._set_status(self._status) # self.plot() setup.set_parameters(self.profile.get_parameters()) setup.calculate_signal.connect(self._on_calculate_baseline) setup.subtract_signal.connect(self._on_subtracting_baseline) setup.restore_signal.connect(self._on_restoring_data) setup.close_signal.connect(self._on_closing_setup) setup.show() self._roi.show() # def show_baseline(self): # if (self.profile.baseline is None or self._status == BaseLineStatus.baseline_calculated or # self._status == BaseLineStatus.baseline_restored): # return # self._on_restoring_data() def update_plot(self): self.sigma_slider.set_value(self.profile.sigma, True) if self.profile.baseline is None: self.clear_baseline() else: self._set_status(BaseLineStatus.baseline_subtracted) self.plot() def plot_baseline(self): if self.profile.baseline is not None: self.baseline_plot.setData(self.profile.x, self.profile.baseline, pen=get_pen(width=4, color='red', style=Qt.DashDotLine)) def _set_default_bounds(self): if self.x is None: self.profile.x_range = (0, 1) else: self.profile.x_range = (self.x.min(), self.x.max()) def _update_bounds(self): self.profile.x_range = self._roi.getRegion() def _set_status(self, status: 'BaseLineStatus'): self._status = status self._baseline_setup_widget.set_status(status) def _on_calculate_baseline(self, params: dict): self.profile.set_parameters(**params) self._update_bounds() try: self.profile.update_baseline() except Exception as err: logger.exception(err) show_error( 'Failed calculating baseline. Change roi region or parameters and try again.', error_title='Baseline calculation error') return self._set_status(BaseLineStatus.baseline_calculated) self.plot_baseline() def _on_subtracting_baseline(self): self.baseline_plot.clear() self._set_status(BaseLineStatus.baseline_subtracted) self.plot() def _on_restoring_data(self): self._set_status(BaseLineStatus.baseline_restored) self.plot_baseline() self.plot() def _on_closing_setup(self): self._baseline_setup_widget.hide() self._roi.hide() self.clear_baseline() if self._status != BaseLineStatus.baseline_subtracted: self._set_status(BaseLineStatus.no_baseline) self.profile.clear_baseline(clear_range=False) self.sigBackgroundChanged.emit() def clear_baseline(self): self.baseline_plot.clear()
class GraphicWidgetLogic(Ui_GraphicWindow): def __init__(self, GraphicWidgetLogic): Ui_GraphicWindow.__init__(self) self.FS = 48000 self.x = 0 self.y = 0 self.freq = 0 self.amp = 0 self.flag = "PURE" # se inicializa el sistema de visualizado avanzado def initializeBinds(self): # añadir plots self.pushButtonPlay.clicked.connect(self.play) self.pushButton.clicked.connect(self.showFFT) setConfigOption('leftButtonPan', False) self.x = 0 self.y = 0 self.zoomedPlot = self.graphicsView.addPlot(row=1, col=0) self.fullPlot = self.graphicsView.addPlot(row=2, col=0) self.graphicsView.setBackground(background="w") # self.zoomedPlot.vb.setBackgroundColor("w") # self.fullPlot.vb.setBackgroundColor("w") self.penB = mkPen('b') self.penR = mkPen('r') self.region = LinearRegionItem() self.region.setZValue(10) self.vb = self.zoomedPlot.vb self.region.setRegion([1000, 2000]) self.fullPlot.addItem(self.region, ignoreBounds=True) # pg.dbg() self.zoomedPlot.setAutoVisible(y=True) self.vLine = InfiniteLine(angle=90, movable=False) self.hLine = InfiniteLine(angle=0, movable=False) self.zoomedPlot.addItem(self.vLine, ignoreBounds=True) self.zoomedPlot.addItem(self.hLine, ignoreBounds=True) # signal para capturar evento de raton # proxy = SignalProxy(self.zoomedPlot.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) self.zoomedPlot.scene().sigMouseMoved.connect(self.mouseMoved) self.region.sigRegionChanged.connect(self.update) self.zoomedPlot.sigRangeChanged.connect(self.updateRegion) def play(self): sd.play(self.y, self.FS, blocking=True) def showFFT(self): self.FFTwindow = QtWidgets.QWidget() self.ui = GraphicWidgetLogicSpectrumLogic(self) self.ui.setupUi(self.FFTwindow) self.ui.initializeBinds() self.ui.PlotFFT(self.x, self.y, self.flag, self.amp) self.FFTwindow.activateWindow() self.FFTwindow.show() self.FFTwindow.raise_() def updateRegion(self, window, viewRange): rgn = viewRange[0] self.region.setRegion(rgn) def update(self): self.region.setZValue(10) minX, maxX = self.region.getRegion() self.zoomedPlot.setXRange(minX, maxX, padding=0) def mouseMoved(self, evt): pos = Point(evt.x(), evt.y()) if self.zoomedPlot.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) index = float(evt.x()) # if index > 0 : # self.dataLabel.setText("<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y1=%0.1f</span>, <span style='color: green'>y2=%0.1f</span>" % int(index), self.x[index], self.y[index]) self.vLine.setPos(mousePoint.x()) self.hLine.setPos(mousePoint.y()) def PlotSin(self, amp, freq, phase, flag="PURE"): print(self.flag) self.flag = flag self.amp = amp self.freq = freq self.x = arange(0, 1, 1 / self.FS) self.y = (amp / 10) * sin(2 * pi * freq * self.x + (phase * pi)) self.fullPlot.plot(self.x, self.y, pen=self.penR) self.zoomedPlot.plot(self.x, self.y, pen=self.penB) def plotSawtooth(self, amp, freq): self.amp = amp self.freq = freq self.Fs: int = 44100 self.x = arange(0, 1, 1 / self.Fs) self.y = (amp / 10) * sawtooth(2 * pi * freq * self.x) self.fullPlot.plot(self.x, self.y, pen=self.penR) self.zoomedPlot.plot(self.x, self.y, pen=self.penB) def plotSquare(self, amp, freq): self.amp = amp self.freq = freq self.Fs: int = 44100 self.x = arange(0, 1, 1 / self.Fs) self.y = (amp / 10) * square(2 * pi * freq * self.x) self.fullPlot.plot(self.x, self.y, pen=self.penR) self.zoomedPlot.plot(self.x, self.y, pen=self.penB) def plotGpulse(self, amp, freq): self.amp = amp self.freq = freq self.Fs: int = 44100 self.x = arange(0, 1, 1 / self.Fs) self.y = (amp / 10) * gausspulse((self.x, freq)) self.fullPlot.plot(self.x, self.y, pen=self.penR) self.zoomedPlot.plot(self.x, self.y, pen=self.penB) def plotHarmonic(self, x_array, y_array): self.x = x_array self.y = y_array self.fullPlot.plot(x_array, y_array, pen=self.penR) self.zoomedPlot.plot(x_array, y_array, pen=self.penB)
class HistogramItem(GraphicsWidget): """ This is a graphicsWidget which provides controls for adjusting the display of an image. Includes: - Image histogram - Movable region over histogram to select black/white levels Parameters ---------- image : ImageItem or None If *image* is provided, then the control will be automatically linked to the image and changes to the control will be immediately reflected in the image's appearance. fillHistogram : bool By default, the histogram is rendered with a fill. For performance, set *fillHistogram* = False. """ sigLevelsChanged = pyqtSignal(object) sigLevelChangeFinished = pyqtSignal(object) def __init__(self, image=None, fillHistogram=True, bounds: tuple = None): GraphicsWidget.__init__(self) self.imageItem = lambda: None # fake a dead weakref self.layout = QGraphicsGridLayout() self.setLayout(self.layout) self.layout.setContentsMargins(1, 1, 1, 1) self.layout.setSpacing(0) self.vb = ViewBox(parent=self) # self.vb.setMaximumHeight(152) # self.vb.setMinimumWidth(45) self.vb.setMouseEnabled(x=True, y=False) self.region = LinearRegionItem([0, 1], 'vertical', swapMode='block', bounds=bounds) self.region.setZValue(1000) self.vb.addItem(self.region) self.region.lines[0].addMarker('<|', 0.5) self.region.lines[1].addMarker('|>', 0.5) self.region.sigRegionChanged.connect(self.regionChanging) self.region.sigRegionChangeFinished.connect(self.regionChanged) self.axis = AxisItem('bottom', linkView=self.vb, maxTickLength=-10, parent=self) self.layout.addItem(self.axis, 1, 0) self.layout.addItem(self.vb, 0, 0) self.range = None self.vb.sigRangeChanged.connect(self.viewRangeChanged) self.plot = PlotCurveItem(pen=(200, 200, 200, 100)) # self.plot.rotate(90) self.vb.addItem(self.plot) self.fillHistogram(fillHistogram) self._showRegions() self.autoHistogramRange() if image is not None: self.setImageItem(image) def fillHistogram(self, fill=True, level=0.0, color=(100, 100, 200)): if fill: self.plot.setFillLevel(level) self.plot.setBrush(color) else: self.plot.setFillLevel(None) def paint(self, p, *args): rgn = self.getLevels() self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[0])) self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[1])) def setHistogramRange(self, mn, mx, padding=0.1): """Set the Y range on the histogram plot. This disables auto-scaling.""" self.vb.enableAutoRange(self.vb.XAxis, False) self.vb.setYRange(mn, mx, padding) def autoHistogramRange(self): """Enable auto-scaling on the histogram plot.""" self.vb.enableAutoRange(self.vb.XYAxes) def setImageItem(self, img): """Set an ImageItem to have its levels and LUT automatically controlled by this HistogramLUTItem. """ self.imageItem = weakref.ref(img) img.sigImageChanged.connect(self.imageChanged) self.regionChanged() self.imageChanged(autoLevel=True) def viewRangeChanged(self): self.update() def regionChanged(self): if self.imageItem() is not None: self.imageItem().setLevels(self.getLevels()) self.sigLevelChangeFinished.emit(self) def regionChanging(self): if self.imageItem() is not None: self.imageItem().setLevels(self.getLevels()) self.sigLevelsChanged.emit(self) self.update() def imageChanged(self, autoLevel=False): if self.imageItem() is None: return self.plot.setVisible(True) # plot one histogram for all image data h = self.imageItem().getHistogram() if h[0] is None: return self.plot.setData(*h) if autoLevel: mn = h[0][0] mx = h[0][-1] self.region.setRegion([mn, mx]) else: mn, mx = self.imageItem().levels self.region.setRegion([mn, mx]) def getLevels(self): """ Return the min and max levels. """ return self.region.getRegion() def setLevels(self, min=None, max=None): """ Set the min/max (bright and dark) levels. """ assert None not in (min, max) self.region.setRegion((min, max)) def _showRegions(self): self.region.setVisible(True) def saveState(self): return { 'levels': self.getLevels(), } def restoreState(self, state): self.setLevels(*state['levels'])