def __init__(self): super().__init__() self.resize(420, 400) self.show() plot = self.addPlot() # title="non-interactive") # prepare demonstration data: data = np.fromfunction( lambda i, j: (1 + 0.3 * np.sin(i)) * (i)**2 + (j)**2, (100, 100)) noisy_data = data * (1 + 0.2 * np.random.random(data.shape)) # Example: False color image with interactive level adjustment img = pg.ImageItem(image=noisy_data ) # create monochrome image from demonstration data plot.addItem(img) # add to PlotItem 'plot' cm = pg.colormap.get('CET-L9') # prepare a linear color map bar = pg.ColorBarItem(values=(0, 20_000), cmap=cm) # prepare interactive color bar # Have ColorBarItem control colors of img and appear in 'plot': bar.setImageItem(img, insert_in=plot) self.timer = pg.QtCore.QTimer(singleShot=True) self.timer.timeout.connect(self.export) self.timer.start(100)
def __init__(self, parent=None, lockAspect=False, raw=False): super().__init__(parent) self.ui = Ui_Form_static() self.ui.setupUi(self) # Some options for Raw Images self.raw = raw # Image pane setup self.image_layout = Qt.QtWidgets.QHBoxLayout(self.ui.imageFrame) self.image_layout.setContentsMargins(0, 0, 0, 0) self.image_layout.setSpacing(0) self.image_win = pg.GraphicsLayoutWidget() self.image_layout.addWidget(self.image_win) self.imageViewBox = RectViewBox(lockAspect=lockAspect) self.image_plot = self.image_win.addPlot(viewBox=self.imageViewBox) self.imageItem = pgXDImageItem(raw=self.raw) self.image_plot.addItem(self.imageItem) # Make Label Item for showing position self.make_pos_label() self.histogram = pg.ColorBarItem(width=15) # Have ColorBarItem control colors of img and appear in 'plot': self.histogram.setImageItem(self.imageItem, insert_in=self.image_plot) self.raw_image = np.zeros(0) self.displayed_image = np.zeros(0) self.show()
def __init__(self, parent: Optional[QtWidgets.QWidget] = None) -> None: super().__init__(parent) self.plot: pg.PlotItem = self.graphicsLayout.addPlot() cmap = pg.colormap.get('viridis', source='matplotlib') self.colorbar: pg.ColorBarItem = pg.ColorBarItem(interactive=True, values=(0, 1), cmap=cmap, width=15) self.graphicsLayout.addItem(self.colorbar) self.img: Optional[pg.ImageItem] = None self.scatter: Optional[pg.ScatterPlotItem] = None self.scatterZVals: Optional[np.ndarray] = None
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) gr_wid = pg.GraphicsLayoutWidget(show=True) self.setCentralWidget(gr_wid) self.setWindowTitle('pyqtgraph example: Correlation matrix display') self.resize(600, 500) self.show() corrMatrix = np.array([[1., 0.5184571, -0.70188642], [0.5184571, 1., -0.86094096], [-0.70188642, -0.86094096, 1.]]) columns = ["A", "B", "C"] pg.setConfigOption('imageAxisOrder', 'row-major') # Switch default order to Row-major correlogram = pg.ImageItem() # create transform to center the corner element on the origin, for any assigned image: tr = QtGui.QTransform().translate(-0.5, -0.5) correlogram.setTransform(tr) correlogram.setImage(corrMatrix) plotItem = gr_wid.addPlot( ) # add PlotItem to the main GraphicsLayoutWidget plotItem.invertY(True) # orient y axis to run top-to-bottom plotItem.setDefaultPadding(0.0) # plot without padding data range plotItem.addItem(correlogram) # display correlogram # show full frame, label tick marks at top and left sides, with some extra space for labels: plotItem.showAxes(True, showValues=(True, True, False, False), size=20) # define major tick marks and labels: ticks = [(idx, label) for idx, label in enumerate(columns)] for side in ('left', 'top', 'right', 'bottom'): plotItem.getAxis(side).setTicks( (ticks, [])) # add list of major ticks; no minor ticks plotItem.getAxis('bottom').setHeight( 10) # include some additional space at bottom of figure colorMap = pg.colormap.get( "CET-D1") # choose perceptually uniform, diverging color map # generate an adjustabled color bar, initially spanning -1 to 1: bar = pg.ColorBarItem(values=(-1, 1), colorMap=colorMap) # link color bar and color map to correlogram, and show it in plotItem: bar.setImageItem(correlogram, insert_in=plotItem)
def loadAnImage(self, image, colormap, cmap_limits, opacity = 1): """ load single image and colorbar to the widget. This function will be looped for multiple images later """ # get pg image item img = pg.ImageItem() # add image to the graphicsview widget self.canvas.addItem(img) # set the color map cmap = pg.ColorMap(pos=np.linspace(0, 1, len(colormap)), color=colormap) #image = np.squeeze(tf.imread(image_path)) # set image to the image item with cmap img.setImage(np.array(image), lut=cmap.getLookupTable(), opacity = opacity) # set colorbar for thresholding bar = pg.ColorBarItem( values=cmap_limits, cmap=cmap, limits=(0, None), orientation='vertical' ) bar.setImageItem(img) # set composition mode to plus for overlaying img.setCompositionMode(QtGui.QPainter.CompositionMode_Plus)
def _replot(self): logger.info('') self.kymographPlot.clear() self.kymographPlot.show() if self.ba is None: return myTif = self.ba.tifData #self.myImageItem = pg.ImageItem(myTif, axisOrder='row-major') # TODO: set height to micro-meters axisOrder = 'row-major' rect = [0, 0, self.ba.recordingDur, self.ba.tifData.shape[0]] # x, y, w, h if self.myImageItem is None: # first time build self.myImageItem = kymographImage(myTif, axisOrder=axisOrder, rect=rect) # redirect hover to self (to display intensity self.myImageItem.hoverEvent = self.hoverEvent else: # second time update myTif = self.ba.tifData self.myImageItem.setImage(myTif, axisOrder=axisOrder, rect=rect) self.kymographPlot.addItem(self.myImageItem) # color bar with contrast !!! if myTif.dtype == np.dtype('uint8'): bitDepth = 8 elif myTif.dtype == np.dtype('uint16'): bitDepth = 16 else: bitDepth = 16 logger.error(f'Did not recognize tif dtype: {myTif.dtype}') minTif = np.nanmin(myTif) maxTif = np.nanmax(myTif) #print(type(dtype), dtype) # <class 'numpy.dtype[uint16]'> uint16 cm = pg.colormap.get('Greens_r', source='matplotlib') # prepare a linear color map #values = (0, 2**bitDepth) values = (0, maxTif) limits = values logger.info( f'color bar bit depth is {bitDepth} with values is {values}') bar = pg.ColorBarItem( values=values, limits=limits, cmap=cm, orientation='horizontal') # prepare interactive color bar # Have ColorBarItem control colors of img and appear in 'plot': bar.setImageItem(self.myImageItem, insert_in=self.kymographPlot) kymographRect = self.ba.getKymographRect() if kymographRect is not None: xRoiPos = kymographRect[0] yRoiPos = kymographRect[3] top = kymographRect[1] right = kymographRect[2] bottom = kymographRect[3] widthRoi = right - xRoiPos + 1 #heightRoi = bottom - yRoiPos + 1 heightRoi = top - yRoiPos + 1 ''' else: # TODO: Put this logic into function in bAbfText pos, size = self.ba.defaultTifRoi() xRoiPos = 0 # startSeconds yRoiPos = 0 # pixels widthRoi = myTif.shape[1] heightRoi = myTif.shape[0] tifHeightPercent = myTif.shape[0] * 0.2 #print('tifHeightPercent:', tifHeightPercent) yRoiPos += tifHeightPercent heightRoi -= 2 * tifHeightPercent ''' # TODO: get this out of replot, recreating the ROI is causing runtime error pos = (xRoiPos, yRoiPos) size = (widthRoi, heightRoi) if self.myLineRoi is None: self.myLineRoi = pg.ROI(pos=pos, size=size, parent=self.myImageItem) self.myLineRoi.addScaleHandle((0, 0), (1, 1), name='topleft') # at origin self.myLineRoi.addScaleHandle((0.5, 0), (0.5, 1)) # top center self.myLineRoi.addScaleHandle((0.5, 1), (0.5, 0)) # bottom center self.myLineRoi.addScaleHandle((0, 0.5), (1, 0.5)) # left center self.myLineRoi.addScaleHandle((1, 0.5), (0, 0.5)) # right center self.myLineRoi.addScaleHandle((1, 1), (0, 0), name='bottomright') # bottom right self.myLineRoi.sigRegionChangeFinished.connect( self.kymographChanged) else: self.myLineRoi.setPos(pos, finish=False) self.myLineRoi.setSize(size, finish=False) # background kymograph ROI backgroundRect = self.ba.getKymographBackgroundRect( ) # keep this in the backend if backgroundRect is not None: xRoiPos = backgroundRect[0] yRoiPos = backgroundRect[1] right = backgroundRect[2] bottom = backgroundRect[3] widthRoi = right - xRoiPos + 1 heightRoi = bottom - yRoiPos + 1 # TODO: get this out of replot, recreating the ROI is causing runtime error self.myLineRoiBackground = pg.ROI(pos=(xRoiPos, yRoiPos), size=(widthRoi, heightRoi), parent=self.myImageItem) # update min/max labels # TODO: also display min max within roi ??? self.tifMinLabel.setText(f'Min:{minTif}') self.tifMaxLabel.setText(f'Max:{maxTif}') self._updateRoiMinMax(kymographRect)
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) gr_wid = pg.GraphicsLayoutWidget(show=True) self.setCentralWidget(gr_wid) self.setWindowTitle('pyqtgraph example: Interactive color bar') self.resize(800, 700) self.show() ## Create image items data = np.fromfunction( lambda i, j: (1 + 0.3 * np.sin(i)) * (i)**2 + (j)**2, (100, 100)) noisy_data = data * (1 + 0.2 * np.random.random(data.shape)) noisy_transposed = noisy_data.transpose() #--- add non-interactive image with integrated color ------------------ p1 = gr_wid.addPlot(title="non-interactive") # Basic steps to create a false color image with color bar: i1 = pg.ImageItem(image=data) p1.addItem(i1) p1.addColorBar(i1, colorMap='CET-L9', values=(0, 30_000)) # , interactive=False) # p1.setMouseEnabled(x=False, y=False) p1.disableAutoRange() p1.hideButtons() p1.setRange(xRange=(0, 100), yRange=(0, 100), padding=0) p1.showAxes(True, showValues=(True, False, False, True)) #--- add interactive image with integrated horizontal color bar ------- i2 = pg.ImageItem(image=noisy_data) p2 = gr_wid.addPlot(1, 0, 1, 1, title="interactive") p2.addItem(i2, title='') # inserted color bar also works with labels on the right. p2.showAxis('right') p2.getAxis('left').setStyle(showValues=False) p2.getAxis('bottom').setLabel('bottom axis label') p2.getAxis('right').setLabel('right axis label') bar = pg.ColorBarItem(values=(0, 30_000), colorMap='CET-L4', label='horizontal color bar', limits=(0, None), rounding=1000, orientation='h', pen='#8888FF', hoverPen='#EEEEFF', hoverBrush='#EEEEFF80') bar.setImageItem(i2, insert_in=p2) #--- multiple images adjusted by a separate color bar ------------------------ i3 = pg.ImageItem(image=noisy_data) p3 = gr_wid.addPlot(0, 1, 1, 1, title="shared 1") p3.addItem(i3) i4 = pg.ImageItem(image=noisy_transposed) p4 = gr_wid.addPlot(1, 1, 1, 1, title="shared 2") p4.addItem(i4) cmap = pg.colormap.get('CET-L8') bar = pg.ColorBarItem( # values = (-15_000, 15_000), limits=(-30_000, 30_000), # start with full range... rounding=1000, width=10, colorMap=cmap) bar.setImageItem([i3, i4]) bar.setLevels(low=-5_000, high=15_000) # ... then adjust to retro sunset. # manually adjust reserved space at top and bottom to align with plot bar.getAxis('bottom').setHeight(21) bar.getAxis('top').setHeight(31) gr_wid.addItem(bar, 0, 2, 2, 1) # large bar spanning both rows
def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) args, _ = parser.parse_known_args() if args.samplerate == None: self.samplerate = \ int(sd.query_devices(args.input_device)['default_samplerate']) else: self.samplerate = int(args.samplerate) print(f"INFO -- Sampling rate at {self.samplerate} Hz") self.threadpool = QtCore.QThreadPool() self.q = queue.Queue() self.setFixedSize(args.width, args.height) self.mainbox = QtWidgets.QWidget() self.setCentralWidget(self.mainbox) self.layout = QtWidgets.QGridLayout() self.mainbox.setLayout(self.layout) # Widgets self.spec_plot = SpectrogramWidget() self.wave_plot = WaveFormWidget() for i, widget in enumerate([self.spec_plot, self.wave_plot]): self.layout.addWidget(widget, i, 0) # Initialize x and y self.length = self.samplerate * args.duration self.y = np.random.rand(self.length, len(args.channels)) self.x = np.linspace(0, args.duration, num=self.length) self.zcr = librosa.feature.zero_crossing_rate(self.y.mean(axis=1))[0] # Wave Plot self.waveline_1 = self.wave_plot.plot(x=self.x, y=self.y[:, 0], pen=pg.mkPen('g', width=0.5), name='channel_1') self.waveline_2 = self.wave_plot.plot(x=self.x, y=self.y[:, 1], pen=pg.mkPen('y', width=0.5), name='channel_2') self.waveline_3 = self.wave_plot.plot(x=np.linspace( 0, args.duration, self.zcr.shape[0]), y=self.zcr, pen=pg.mkPen('r', width=2), name='zcr') # Spectrogram self.fmax = int( librosa.core.fft_frequencies(sr=self.samplerate, n_fft=args.n_fft)[-1]) D = librosa.stft(y=self.y.mean(axis=1), n_fft=args.n_fft, center=False) self.specdata = librosa.amplitude_to_db(np.abs(D), ref=np.max) # M = librosa.feature.melspectrogram( # y=self.y.mean(axis=1), # sr=self.samplerate, # n_fft=args.n_fft, # n_mels=args.n_mels) # self.specdata = librosa.power_to_db(S=M, ref=np.max) self.F0 = librosa.yin(y=self.y.mean(axis=1), sr=self.samplerate, frame_length=2048, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C5'), center=False) self.spec_image = pg.ImageItem(item=self.specdata.T) self.spec_plot.addItem(item=self.spec_image) self.f0_line = self.spec_plot.plot(x=np.linspace( 0, args.duration, self.F0.shape[0]), y=self.F0, pen=pg.mkPen('r', width=2), name='f0') self.bar = pg.ColorBarItem(values=(librosa.note_to_hz('C2'), librosa.note_to_hz('C5')), cmap=pg.colormap.get('CET-L9')) self.bar.setImageItem(self.spec_image) # Start audio stream and animations self.start_stream() if args.input_device == 'Virtual Input (VB-Audio Virtual Cable), Windows DirectSound': self.play_media(media_url=args.media_url, type='stream', volume=100) self.animate() self.show()
def __init__(self, array, y_scale, y_spacing, chan_map, nav_trace, x_scale=1, load_channels='all', max_zoom=120.0, units='V'): """ Scroller GUI loading a minimal amount of timeseries to display. X-units are currently assumed to be seconds. Parameters ---------- array : array-like Array-like access to a mapped array (i.e. can index with array[i, range] slices). y_scale : float Scale the raw samples to units. y_spacing : float Spacing for the channel traces (in units) chan_map : ChannelMap Matrix map of the channels. nav_trace : array-like (1D) Navigation trace that is the same length as the channel timeseries. If not given, then mean of channels is used. **THIS MAY BE A COSTLY COMPUTATION** x_scale : float (optional) X-axis scale (e.g. sampling interval) load_channels : sequence | 'all' Order of (subset of) channels to load. Otherwise load all in array. units : str Y-axis units """ nchan = array.shape[0] if isinstance(load_channels, str) and load_channels.lower() == 'all': load_channels = range(nchan) self.chan_map = chan_map elif len(load_channels) == len(chan_map): self.chan_map = chan_map elif len(load_channels) < len(chan_map): # "load_channels" indexes an array of recording channels # that may include grounded channels or other junk. raise NotImplementedError('cannot yet subset data channels') # new_cm = ChannelMap( [chan_map[i] for i in load_channels], # chan_map.geometry, # col_major=chan_map.col_major ) # self.chan_map = new_cm else: raise ValueError('cannot map the listed channels') self.array = array self.y_scale = y_scale if isinstance(load_channels, str) and load_channels == 'all': load_channels = list(range(len(array))) self.load_channels = load_channels # The main window + layout self.win = pg.GraphicsLayoutWidget(border=(10, 10, 10)) layout = self.win.ci # Adding columns to layout: just titles on the top row layout.addLabel('Array heatmap') layout.addLabel('Zoomed plot') layout.addLabel('|') # Next row has 1) the heatmap image with the colorbar widget layout.nextRow() sub_layout = layout.addLayout(colspan=1) self.img = pg.ImageItem( image=np.random.randn(*self.chan_map.geometry) * y_spacing) # * 1e6 / 2) cmap = pg.colormap.get('coolwarm', source='matplotlib') p_img = sub_layout.addPlot() self.p_img = p_img p_img.getViewBox().setAspectLocked() p_img.addItem(self.img) p_img.hideAxis('bottom') p_img.hideAxis('left') mid_x, top_y = self.chan_map.geometry[1] / 2.0, self.chan_map.geometry[ 0] + 2.0 # add a text label on top of the box ("anchor" has text box is centered on its x, y position) self.frame_text = pg.TextItem('empty', anchor=(0.5, 0.5), color=(255, 255, 255)) self.frame_text.setPos(mid_x, top_y) # self.vb_img.addItem(self.frame_text) p_img.getViewBox().addItem(self.frame_text) p_img.getViewBox().autoRange() # colorbar self.cb = pg.ColorBarItem(limits=None, cmap=cmap, hoverBrush='#EEEEFF80', rounding=10e-6, values=(-y_spacing, y_spacing)) self.cb.getAxis('left').setLabel('') self.cb.getAxis('right').setLabel('Voltage', units='V') self.cb.setImageItem(self.img) sub_layout.addItem(self.cb) # 2) the stacked traces plot (colspan 2) axis = PlainSecAxis(orientation='bottom') self.p1 = layout.addPlot(colspan=2, row=1, col=1, axisItems={'bottom': axis}) self.p1.enableAutoRange(axis='y', enable=True) self.p1.setAutoVisible(y=False) self.p1.setLabel('left', 'Amplitude', units=units) self.p1.setLabel('bottom', 'Time') # Next layout row has the navigator plot (colspan 3) layout.nextRow() # The navigator plot axis = HMSAxis(orientation='bottom') self.p2 = layout.addPlot(row=2, col=0, colspan=3, axisItems={'bottom': axis}) self.p2.setLabel('left', 'Amplitude', units=units) self.p2.setLabel('bottom', 'Time') self.region = pg.LinearRegionItem() self.region.setZValue(10) initial_pts = 5000 self.region.setRegion([0, initial_pts * x_scale]) # Add the LinearRegionItem to the ViewBox, # but tell the ViewBox to exclude this # item when doing auto-range calculations. self.p2.addItem(self.region, ignoreBounds=True) self.p1.setAutoVisible(y=True) self.p1.setXRange(0, initial_pts * x_scale) self.p1.vb.setLimits(maxXRange=max_zoom) # Multiple curve set that calls up data on-demand self.curve_manager = CurveManager(plot=self.p1) curves = PlotCurveCollection(array, load_channels, x_scale, y_scale, y_spacing) curves.setPen(color='w', width=1) self.curve_manager.add_new_curves(curves, 'all', set_source=True) # Set the heatmap to track these curves self.curve_manager.heatmap_name = 'all' # Selected curve & label set that calls up data on-demand labels = ['({}, {})'.format(i, j) for i, j in zip(*chan_map.to_mat())] selected_curves = LabeledCurveCollection(curves, labels, clickable=True) self.curve_manager.add_new_curves(selected_curves, 'selected') for text in selected_curves.texts: self.p1.addItem(text) # Add mean trace to bottom plot self.nav_trace = pg.PlotCurveItem(x=np.arange(len(nav_trace)) * x_scale, y=nav_trace) self.p2.addItem(self.nav_trace) self.p2.setXRange(0, min(5e4, len(nav_trace)) * x_scale) self.p2.setYRange(*np.percentile(nav_trace, [1, 99])) # Set bidirectional plot interaction # need to hang onto references? self._db_cnx1 = DebounceCallback.connect(self.region.sigRegionChanged, self.update_zoom_callback) self._db_cnx2 = DebounceCallback.connect(self.p1.sigXRangeChanged, self.update_region_callback) # Do navigation jumps (if shift key is down) self.p2.scene().sigMouseClicked.connect(self.jump_nav) # Do fine interaction in zoomed plot with vertical line self.vline = pg.InfiniteLine(angle=90, movable=False) self.p1.addItem(self.vline) self.p1.scene().sigMouseMoved.connect(self.fine_nav) # final adjustments to rows: args are (row, stretch) self.win.centralWidget.layout.setRowStretchFactor(0, 0.5) self.win.centralWidget.layout.setRowStretchFactor(1, 5) self.win.centralWidget.layout.setRowStretchFactor(2, 2.5) # a callable frame filter may be set on this object to affect frame display self.frame_filter = None # set up initial frame self.set_mean_image()
def updateplot(self): self.mainloop() if not self.ui.drawingCheck.checkState() == QtCore.Qt.Checked: return for li in range(self.nlines): maxchan=li-HaasoscopeLibQt.num_chan_per_board*HaasoscopeLibQt.num_board if maxchan>=0: # these are the slow ADC channels self.lines[li].setData(d.xydataslow[maxchan][0],d.xydataslow[maxchan][1]) else: self.lines[li].setData(d.xydata[li][0],d.xydata[li][1]) if d.dologicanalyzer: for li in np.arange(d.num_logic_inputs): self.lines[d.logicline1+li].setData(d.xydatalogic[li][0],d.xydatalogic[li][1]) if d.dofft: self.fftui.fftline.setPen(self.linepens[d.fftchan]) self.fftui.fftline.setData(d.fftfreqplot_xdata,d.fftfreqplot_ydata) self.fftui.ui.plot.setTitle("FFT plot of channel "+str(d.fftchan)) self.fftui.ui.plot.setLabel('bottom', d.fftax_xlabel) self.fftui.ui.plot.setRange(xRange=(0.0, d.fftax_xlim)) now = time.time() dt = now - self.fftui.fftlastTime if dt>3.0 or self.fftyrange<d.fftfreqplot_ydatamax*1.1: self.fftui.fftlastTime = now self.fftui.ui.plot.setRange(yRange=(0.0, d.fftfreqplot_ydatamax*1.1)) self.fftyrange = d.fftfreqplot_ydatamax * 1.1 if not self.fftui.isVisible(): # closed the fft window d.dofft = False self.ui.fftCheck.setCheckState(QtCore.Qt.Unchecked) if d.recorddata: if self.firstpersist: self.image1 = pg.ImageItem(image=d.recorded2d,opacity=0.5) self.persistui.ui.plot.addItem(self.image1) self.persistui.ui.plot.setTitle("Persist plot of channel "+str(d.recorddatachan)) self.cmap = pg.colormap.get('CET-D8') self.firstpersist=False else: self.image1.setImage(image=d.recorded2d,opacity=0.5) self.image1.setRect(QtCore.QRectF(d.min_x,d.min_y,d.max_x-d.min_x,d.max_y-d.min_y)) self.persistui.ui.plot.setLabel('bottom', d.xlabel) self.bar = pg.ColorBarItem(interactive=False, values= (0, np.max(d.recorded2d)), cmap=self.cmap) self.bar.setImageItem(self.image1) if not self.persistui.isVisible(): # closed the fft window d.recorddata = False self.ui.persistCheck.setCheckState(QtCore.Qt.Unchecked) if self.ui.decodeCheck.checkState() == QtCore.Qt.Checked: # delete all previous labels for label in self.decodelabels: self.ui.plot.removeItem(label) if d.downsample>=0: resulttext,resultstart,resultend = d.decode() #print(resulttext,resultstart, d.min_x, d.max_x, d.xscale, d.xscaling) item=0 while item<len(resulttext): label = pg.TextItem(resulttext[item]) label.setColor(self.linepens[d.selectedchannel].color()) x=d.min_x+resultstart[item]*1e9/d.xscaling label.setPos( QtCore.QPointF(x, -1) ) #print(x) self.ui.plot.addItem(label) self.decodelabels.append(label) item=item+1 else: print("can't decode when downsample is <0... go slower!") now = time.time() dt = now - self.lastTime + 0.00001 self.lastTime = now if self.fps is None: self.fps = 1.0/dt else: s = np.clip(dt*3., 0, 1) self.fps = self.fps * (1-s) + (1.0/dt) * s self.ui.plot.setTitle('%0.2f fps' % self.fps) app.processEvents()