def test_signal_proxy_no_slot_start(qapp): """Test the connect mode of SignalProxy without slot at start`""" sender = Sender(parent=qapp) receiver = Receiver(parent=qapp) proxy = SignalProxy(sender.signalSend, delay=0.0, rateLimit=0.6) assert proxy.blockSignal is True assert proxy is not None assert sender is not None assert receiver is not None sender.signalSend.emit() proxy.flush() qapp.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 10) assert receiver.counter == 0 # Start a connect proxy.connectSlot(receiver.slotReceive) assert proxy.blockSignal is False sender.signalSend.emit() proxy.flush() qapp.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 10) assert receiver.counter > 0 # An additional connect should raise an AssertionError with pytest.raises(AssertionError): proxy.connectSlot(receiver.slotReceive)
class DataInspectorTool(Qt.QWidgetAction, BaseConfigurableClass): """ This tool inserts an action in the menu of the :class:`pyqtgraph.PlotItem` to which it is attached. When activated, the data inspection mode is entered (a :class:`DataInspectorLine` is added and it follows the mouse, allowing the user to inspect the coordinates of existing curves). It is implemented as an Action, and provides a method to attach it to a PlotItem. """ def __init__(self, parent=None): BaseConfigurableClass.__init__(self) Qt.QWidgetAction.__init__(self, parent) self._cb = Qt.QCheckBox() self._cb.setText("Data Inspector") self._cb.toggled.connect(self._onToggled) self.setDefaultWidget(self._cb) self.plot_item = None self.enable = False self.data_inspector = DataInspectorLine() self.registerConfigProperty(self.isChecked, self.setChecked, "checked") def attachToPlotItem(self, plot_item): """ Use this method to add this tool to a plot :param plot_item: (PlotItem) :param y2: (Y2ViewBox) instance of the Y2Viewbox attached to plot_item if the axis change controls are to be used """ self.plot_item = plot_item menu = plot_item.getViewBox().menu menu.addAction(self) def _onToggled(self): if not self.enable: self.data_inspector.attachToPlotItem(self.plot_item) # Signal Proxy which connect the movement of the mouse with # the onMoved method in the data inspector object self.proxy = SignalProxy( self.plot_item.scene().sigMouseMoved, rateLimit=60, slot=self._followMouse, ) self.enable = True # auto-close the menu so that the user can start inspecting self.plot_item.getViewBox().menu.close() else: self.proxy.disconnect() self.data_inspector.dettach() self.enable = False def _followMouse(self, evt): mouse_pos = evt[0] inspector_x = self.plot_item.vb.mapSceneToView(mouse_pos).x() self.data_inspector.setPos(inspector_x)
def __init__(self, x=None, y1=None, y2=None, set_range=None): super(MyPW, self).__init__() self.plotItem.autoBtn = ButtonItem.ButtonItem( pixmaps.getPixmap('default'), 14, self.plotItem) self._rescale = lambda: None # self.plotItem.autoBtn.clicked.connect(self._rescale) self.plotItem.vb.menu.clear() self.vmenu = QtGui.QMenu() defaultview = QtGui.QAction("Default View", self.vmenu) defaultview.triggered.connect(set_range) self.vmenu.addAction(defaultview) self.plotItem.ctrlMenu = [defaultview] # mouse tracking label self.x = x self.y1 = y1 self.y2 = y2 # delete default view, get rid of Export self.plotItem.hideButtons() self.plotItem.scene().contextMenu = None # get rid of 'Export' self.proxy = SignalProxy(self.plotItem.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
def add_cross_hair_to_chart(self): """ method for adding cross hair to the charts """ proxy_mouse_moved_1 = SignalProxy(self.graphics_view_1.scene().sigMouseMoved, rateLimit=60, slot=self.mouse_moved) proxy_mouse_moved_2 = SignalProxy(self.graphics_view_2.scene().sigMouseMoved, rateLimit=60, slot=self.mouse_moved) self.graphics_view_1.proxy = proxy_mouse_moved_1 self.graphics_view_2.proxy = proxy_mouse_moved_2 if self.graphics_view_3: proxy_mouse_moved_3 = SignalProxy(self.graphics_view_3.scene().sigMouseMoved, rateLimit=60, slot=self.mouse_moved) self.graphics_view_3.proxy = proxy_mouse_moved_3
def __init__(self, spool): QtCore.QObject.__init__(self) self.spool = spool self.scene = None self.frame = None self.quadtree = None self.covariance = None self.aps = None self.log = SceneLogModel(self) self._ = SignalProxy(self._sigQuadtreeChanged, rateLimit=10, delay=0, slot=lambda: self.sigQuadtreeChanged.emit()) self._log_handler = logging.Handler() self._log_handler.setLevel(logging.DEBUG) self._log_handler.emit = self.sigLogRecord.emit logging.root.addHandler(self._log_handler) self._download_status = None if pyrocko_download_callback: pyrocko_download_callback(self.download_progress) self.qtproxy = QSceneQuadtreeProxy(self) self.worker_thread = QtCore.QThread() self.moveToThread(self.worker_thread) self.worker_thread.start()
def __init__(self): QtCore.QObject.__init__(self) self.scene = None self.frame = None self.quadtree = None self.covariance = None self.log = SceneLogModel(self) self._ = SignalProxy(self._sigQuadtreeChanged, rateLimit=5, delay=0, slot=lambda: self.sigQuadtreeChanged.emit(object)) self._log_handler = logging.Handler() self._log_handler.setLevel(logging.DEBUG) self._log_handler.emit = self.sigLogRecord.emit logging.root.addHandler(self._log_handler) self.qtproxy = QSceneQuadtreeProxy(self) self.worker_thread = QtCore.QThread() self.moveToThread(self.worker_thread) self.worker_thread.start()
def test_signal_proxy_slot(qapp): """Test the normal work mode of SignalProxy with `signal` and `slot`""" sender = Sender(parent=qapp) receiver = Receiver(parent=qapp) proxy = SignalProxy(sender.signalSend, delay=0.0, rateLimit=0.6, slot=receiver.slotReceive) assert proxy.blockSignal is False assert proxy is not None assert sender is not None assert receiver is not None sender.signalSend.emit() proxy.flush() qapp.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 10) assert receiver.counter > 0
def enableCrosshair(self, is_enabled, starting_x_pos, starting_y_pos, vertical_angle=90, horizontal_angle=0, vertical_movable=False, horizontal_movable=False): """ Enable the crosshair to be drawn on the ViewBox. Parameters ---------- is_enabled : bool True is to draw the crosshair, False is to not draw. starting_x_pos : float The x coordinate where to start the vertical crosshair line. starting_y_pos : float The y coordinate where to start the horizontal crosshair line. vertical_angle : float The angle to tilt the vertical crosshair line. Default at 90 degrees. horizontal_angle The angle to tilt the horizontal crosshair line. Default at 0 degrees. vertical_movable : bool True if the vertical line can be moved by the user; False is not. horizontal_movable False if the horizontal line can be moved by the user; False is not. """ if is_enabled: self.vertical_crosshair_line = InfiniteLine( pos=starting_x_pos, angle=vertical_angle, movable=vertical_movable) self.horizontal_crosshair_line = InfiniteLine( pos=starting_y_pos, angle=horizontal_angle, movable=horizontal_movable) self.plotItem.addItem(self.vertical_crosshair_line) self.plotItem.addItem(self.horizontal_crosshair_line) self.crosshair_movement_proxy = SignalProxy( self.plotItem.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) else: if self.vertical_crosshair_line: self.plotItem.removeItem(self.vertical_crosshair_line) if self.horizontal_crosshair_line: self.plotItem.removeItem(self.horizontal_crosshair_line) if self.crosshair_movement_proxy: # self.crosshair_movement_proxy.disconnect() proxy = self.crosshair_movement_proxy proxy.block = True try: proxy.signal.disconnect(proxy.signalReceived) proxy.sigDelayed.disconnect(proxy.slot) except: pass
def _onToggled(self): if not self.enable: self.data_inspector.attachToPlotItem(self.plot_item) # Signal Proxy which connect the movement of the mouse with # the onMoved method in the data inspector object self.proxy = SignalProxy( self.plot_item.scene().sigMouseMoved, rateLimit=60, slot=self._followMouse, ) self.enable = True # auto-close the menu so that the user can start inspecting self.plot_item.getViewBox().menu.close() else: self.proxy.disconnect() self.data_inspector.dettach() self.enable = False
def _connect_plot_signals(self, index): dockwidget = self._plot_dockwidgets[index].widget() self._fsd.sigFitsUpdated.connect( dockwidget.fit_comboBox.setFitFunctions) dockwidget.fit_pushButton.clicked.connect( functools.partial(self.fit_clicked, index)) x_lim_callback = functools.partial(self.x_limits_changed, index) dockwidget.x_lower_limit_DoubleSpinBox.valueChanged.connect( x_lim_callback) dockwidget.x_upper_limit_DoubleSpinBox.valueChanged.connect( x_lim_callback) y_lim_callback = functools.partial(self.y_limits_changed, index) dockwidget.y_lower_limit_DoubleSpinBox.valueChanged.connect( y_lim_callback) dockwidget.y_upper_limit_DoubleSpinBox.valueChanged.connect( y_lim_callback) dockwidget.x_label_lineEdit.editingFinished.connect( functools.partial(self.x_label_changed, index)) dockwidget.x_unit_lineEdit.editingFinished.connect( functools.partial(self.x_unit_changed, index)) dockwidget.y_label_lineEdit.editingFinished.connect( functools.partial(self.y_label_changed, index)) dockwidget.y_unit_lineEdit.editingFinished.connect( functools.partial(self.y_unit_changed, index)) dockwidget.x_auto_PushButton.clicked.connect( functools.partial(self.x_auto_range_clicked, index)) dockwidget.y_auto_PushButton.clicked.connect( functools.partial(self.y_auto_range_clicked, index)) dockwidget.save_pushButton.clicked.connect( functools.partial(self.save_clicked, index)) dockwidget.remove_pushButton.clicked.connect( functools.partial(self.remove_clicked, index)) self._pg_signal_proxys[index][0] = SignalProxy( dockwidget.plot_PlotWidget.sigXRangeChanged, delay=0.2, slot=lambda args: self._pyqtgraph_x_limits_changed(index, args[1])) self._pg_signal_proxys[index][1] = SignalProxy( dockwidget.plot_PlotWidget.sigYRangeChanged, delay=0.2, slot=lambda args: self._pyqtgraph_y_limits_changed(index, args[1]))
def __init__(self, task, rate_limit=0.01, parent=None): super().__init__(parent=parent) self.task = task self.init_ui() proxy_config = { 'signal': self.task.progressed, 'delay': 0.01, 'rateLimit': rate_limit, 'slot': self.update, } self.task.exception_raised.connect( lambda: self.update_run_state(state='error')) self.task.running.connect( lambda r: self.update_run_state(state='run' if r else 'stop')) self.proxy = SignalProxy(**proxy_config) self.running = False return
def PlotSin(self, amp, freq, phase): self.Fs = 44100 self.x = arange(0, 1, 1 / self.Fs) self.y = (amp / 10) * sin(2 * pi * freq * self.x + (phase * pi)) self.plot = self.PlotView.plotItem self.vBox = self.plot.vb self.vBox.setLimits(xMin=-0, yMin=-2, xMax=1.3, yMax=2) self.vBox.setBackgroundColor("w") # self.vBox.setBackgroundColor("white") self.plot.addLegend() self.plot.showGrid(x=True, y=True) self.plot.plot(self.x, self.y, pen=mkPen('b', width=1), name=str(amp) + "Sin(2π" + str(freq) + "+" + str(phase)) proxy = SignalProxy(self.plot.scene().sigMouseMoved, rateLimit=60, slot=self.MouseMoved)
def __init__(self, plots): """ Constructor arguments: - plots: the plots returns: the initialized class """ self.plots = plots self.cursor_x = [None] * 3 self.cursor_y = [None] * 3 self.cursor_label = [None] * 3 self.signal_proxy = [None] * 3 self.plot_data_items = [None] * 3 self._x = [None] * 3 self._y = [None] * 3 for num, plot in enumerate(plots): self.cursor_x[num] = InfiniteLine(angle=90, movable=False) self.cursor_y[num] = InfiniteLine(angle=0, movable=False) plot.addItem(self.cursor_x[num], ignoreBounds=True) plot.addItem(self.cursor_y[num], ignoreBounds=True) self.signal_proxy[num] = SignalProxy(plot.scene().sigMouseMoved, rateLimit=60, slot=self.update_cursor) self.cursor_label[num] = TextItem('', (255, 255, 255), anchor=(0, 0)) self.cursor_label[num].setPos(-10.4, 10) plot.addItem(self.cursor_label[num]) # Find the PlotDataItem displaying data for item in plot.getPlotItem().items: if isinstance(item, PlotDataItem): self.plot_data_items[num] = item self.hide_cursors()
def enableCrosshair(self, is_enabled, starting_x_pos, starting_y_pos, vertical_angle=90, horizontal_angle=0, vertical_movable=False, horizontal_movable=False): """ Enable the crosshair to be drawn on the ViewBox. Parameters ---------- is_enabled : bool True is to draw the crosshair, False is to not draw. starting_x_pos : float The x coordinate where to start the vertical crosshair line. starting_y_pos : float The y coordinate where to start the horizontal crosshair line. vertical_angle : float The angle to tilt the vertical crosshair line. Default at 90 degrees. horizontal_angle The angle to tilt the horizontal crosshair line. Default at 0 degrees. vertical_movable : bool True if the vertical line can be moved by the user; False is not. horizontal_movable False if the horizontal line can be moved by the user; False is not. """ if is_enabled: self.vertical_crosshair_line = InfiniteLine(pos=starting_x_pos, angle=vertical_angle, movable=vertical_movable) self.horizontal_crosshair_line = InfiniteLine(pos=starting_y_pos, angle=horizontal_angle, movable=horizontal_movable) self.plotItem.addItem(self.vertical_crosshair_line) self.plotItem.addItem(self.horizontal_crosshair_line) self.crosshair_movement_proxy = SignalProxy(self.plotItem.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) else: if self.vertical_crosshair_line: self.plotItem.removeItem(self.vertical_crosshair_line) if self.horizontal_crosshair_line: self.plotItem.removeItem(self.horizontal_crosshair_line) if self.crosshair_movement_proxy: self.crosshair_movement_proxy.disconnect()
def __init__(self, schema: Dict[str, Any], parent_model): super().__init__() self._schema = schema self._model = parent_model self._fit_type = self._schema["fit_type"] self._fit_obj = FIT_OBJECTS[self._fit_type] self._last_fit_params = None self._last_fit_errors = None self._recompute_fit_limiter = SignalProxy( self._trigger_recompute_fit, slot=lambda: asyncio.ensure_future(self._recompute_fit()), rateLimit=30) self._recompute_in_progress = False self._fit_executor = ProcessPoolExecutor(max_workers=1) self._model.points_rewritten.connect(self._update) self._model.points_appended.connect(self._update) self._update()
def __init__(self, parent=None): super().__init__(parent=parent) self.ui.histogram.hide() self.ui.roiBtn.hide() self.ui.menuBtn.hide() self.image_view_text = TextItem(text="", color=(255, 0, 0), anchor=(0, 0)) self.getView().addItem(self.image_view_text) self.image_view_vline = InfiniteLine(angle=90, movable=False) self.image_view_hline = InfiniteLine(angle=0, movable=False) self.getView().addItem(self.image_view_vline, ignoreBounds=True) self.getView().addItem(self.image_view_hline, ignoreBounds=True) self.image_view_proxy = SignalProxy( self.getView().scene().sigMouseMoved, rateLimit=60, slot=self.onMouseMoved) self.signals = FilteratorImageViewSignals()
class BasePlot(PlotWidget, PyDMPrimitiveWidget): crosshair_position_updated = Signal(float, float) def __init__(self, parent=None, background='default', axisItems=None): PlotWidget.__init__(self, parent=parent, background=background, axisItems=axisItems) PyDMPrimitiveWidget.__init__(self) self.plotItem = self.getPlotItem() self.plotItem.hideButtons() self._auto_range_x = None self.setAutoRangeX(True) self._auto_range_y = None self.setAutoRangeY(True) self._min_x = 0.0 self._max_x = 1.0 self._min_y = 0.0 self._max_y = 1.0 self._show_x_grid = None self.setShowXGrid(False) self._show_y_grid = None self.setShowYGrid(False) self._show_right_axis = False self.redraw_timer = QTimer(self) self.redraw_timer.timeout.connect(self.redrawPlot) self._redraw_rate = 30 # Redraw at 30 Hz by default. self.maxRedrawRate = self._redraw_rate self._curves = [] self._title = None self._show_legend = False self._legend = self.addLegend() self._legend.hide() # Drawing crosshair on the ViewBox self.vertical_crosshair_line = None self.horizontal_crosshair_line = None self.crosshair_movement_proxy = None def addCurve(self, plot_item, curve_color=None): if curve_color is None: curve_color = utilities.colors.default_colors[ len(self._curves) % len(utilities.colors.default_colors)] plot_item.color_string = curve_color self._curves.append(plot_item) self.addItem(plot_item) self.redraw_timer.start() # Connect channels for chan in plot_item.channels(): if chan: chan.connect() # self._legend.addItem(plot_item, plot_item.curve_name) def removeCurve(self, plot_item): self.removeItem(plot_item) self._curves.remove(plot_item) if len(self._curves) < 1: self.redraw_timer.stop() # Disconnect channels for chan in plot_item.channels(): if chan: chan.disconnect() def removeCurveWithName(self, name): for curve in self._curves: if curve.name() == name: self.removeCurve(curve) def removeCurveAtIndex(self, index): curve_to_remove = self._curves[index] self.removeCurve(curve_to_remove) def setCurveAtIndex(self, index, new_curve): old_curve = self._curves[index] self._curves[index] = new_curve # self._legend.addItem(new_curve, new_curve.name()) self.removeCurve(old_curve) def curveAtIndex(self, index): return self._curves[index] def curves(self): return self._curves def clear(self): legend_items = [label.text for (sample, label) in self._legend.items] for item in legend_items: self._legend.removeItem(item) self.plotItem.clear() self._curves = [] @Slot() def redrawPlot(self): pass def getShowXGrid(self): return self._show_x_grid def setShowXGrid(self, value, alpha=None): self._show_x_grid = value self.showGrid(x=self._show_x_grid, alpha=alpha) def resetShowXGrid(self): self.setShowXGrid(False) showXGrid = Property("bool", getShowXGrid, setShowXGrid, resetShowXGrid) def getShowYGrid(self): return self._show_y_grid def setShowYGrid(self, value, alpha=None): self._show_y_grid = value self.showGrid(y=self._show_y_grid, alpha=alpha) def resetShowYGrid(self): self.setShowYGrid(False) showYGrid = Property("bool", getShowYGrid, setShowYGrid, resetShowYGrid) def getBackgroundColor(self): return self.backgroundBrush().color() def setBackgroundColor(self, color): if self.backgroundBrush().color() != color: self.setBackgroundBrush(QBrush(color)) backgroundColor = Property(QColor, getBackgroundColor, setBackgroundColor) def getAxisColor(self): return self.getAxis('bottom')._pen.color() def setAxisColor(self, color): if self.getAxis('bottom')._pen.color() != color: self.getAxis('bottom').setPen(color) self.getAxis('left').setPen(color) self.getAxis('top').setPen(color) self.getAxis('right').setPen(color) axisColor = Property(QColor, getAxisColor, setAxisColor) def getBottomAxisLabel(self): return self.getAxis('bottom').labelText def getShowRightAxis(self): """ Provide whether the right y-axis is being shown. Returns : bool ------- True if the graph shows the right y-axis. False if not. """ return self._show_right_axis def setShowRightAxis(self, show): """ Set whether the graph should show the right y-axis. Parameters ---------- show : bool True for showing the right axis; False is for not showing. """ if show: self.showAxis("right") else: self.hideAxis("right") self._show_right_axis = show showRightAxis = Property("bool", getShowRightAxis, setShowRightAxis) def getPlotTitle(self): if self._title is None: return "" return str(self._title) def setPlotTitle(self, value): self._title = str(value) if len(self._title) < 1: self._title = None self.setTitle(self._title) def resetPlotTitle(self): self._title = None self.setTitle(self._title) title = Property(str, getPlotTitle, setPlotTitle, resetPlotTitle) def getShowLegend(self): """ Check if the legend is being shown. Returns : bool ------- True if the legend is displayed on the graph; False if not. """ return self._show_legend def setShowLegend(self, value): """ Set to display the legend on the graph. Parameters ---------- value : bool True to display the legend; False is not. """ self._show_legend = value if self._show_legend: if self._legend is None: self._legend = self.addLegend() else: self._legend.show() else: if self._legend is not None: self._legend.hide() def resetShowLegend(self): """ Reset the legend display status to hidden. """ self.setShowLegend(False) showLegend = Property(bool, getShowLegend, setShowLegend, resetShowLegend) def getAutoRangeX(self): return self._auto_range_x def setAutoRangeX(self, value): self._auto_range_x = value if self._auto_range_x: self.plotItem.enableAutoRange(ViewBox.XAxis, enable=self._auto_range_x) def resetAutoRangeX(self): self.setAutoRangeX(True) def getAutoRangeY(self): return self._auto_range_y def setAutoRangeY(self, value): self._auto_range_y = value if self._auto_range_y: self.plotItem.enableAutoRange(ViewBox.YAxis, enable=self._auto_range_y) def resetAutoRangeY(self): self.setAutoRangeY(True) def getMinXRange(self): """ Minimum X-axis value visible on the plot. Returns ------- float """ return self.plotItem.viewRange()[0][0] def setMinXRange(self, new_min_x_range): """ Set the minimum X-axis value visible on the plot. Parameters ------- new_min_x_range : float """ if self._auto_range_x: return self._min_x = new_min_x_range self.plotItem.setXRange(self._min_x, self._max_x, padding=0) def getMaxXRange(self): """ Maximum X-axis value visible on the plot. Returns ------- float """ return self.plotItem.viewRange()[0][1] def setMaxXRange(self, new_max_x_range): """ Set the Maximum X-axis value visible on the plot. Parameters ------- new_max_x_range : float """ if self._auto_range_x: return self._max_x = new_max_x_range self.plotItem.setXRange(self._min_x, self._max_x, padding=0) def getMinYRange(self): """ Minimum Y-axis value visible on the plot. Returns ------- float """ return self.plotItem.viewRange()[1][0] def setMinYRange(self, new_min_y_range): """ Set the minimum Y-axis value visible on the plot. Parameters ------- new_min_y_range : float """ if self._auto_range_y: return self._min_y = new_min_y_range self.plotItem.setYRange(self._min_y, self._max_y, padding=0) def getMaxYRange(self): """ Maximum Y-axis value visible on the plot. Returns ------- float """ return self.plotItem.viewRange()[1][1] def setMaxYRange(self, new_max_y_range): """ Set the maximum Y-axis value visible on the plot. Parameters ------- new_max_y_range : float """ if self._auto_range_y: return self._max_y = new_max_y_range self.plotItem.setYRange(self._min_y, self._max_y, padding=0) @Property(bool) def mouseEnabledX(self): """ Whether or not mouse interactions are enabled for the X-axis. Returns ------- bool """ return self.plotItem.getViewBox().state['mouseEnabled'][0] @mouseEnabledX.setter def mouseEnabledX(self, x_enabled): """ Whether or not mouse interactions are enabled for the X-axis. Parameters ------- x_enabled : bool """ self.plotItem.setMouseEnabled(x=x_enabled) @Property(bool) def mouseEnabledY(self): """ Whether or not mouse interactions are enabled for the Y-axis. Returns ------- bool """ return self.plotItem.getViewBox().state['mouseEnabled'][1] @mouseEnabledY.setter def mouseEnabledY(self, y_enabled): """ Whether or not mouse interactions are enabled for the Y-axis. Parameters ------- y_enabled : bool """ self.plotItem.setMouseEnabled(y=y_enabled) @Property(int) def maxRedrawRate(self): """ The maximum rate (in Hz) at which the plot will be redrawn. The plot will not be redrawn if there is not new data to draw. Returns ------- int """ return self._redraw_rate @maxRedrawRate.setter def maxRedrawRate(self, redraw_rate): """ The maximum rate (in Hz) at which the plot will be redrawn. The plot will not be redrawn if there is not new data to draw. Parameters ------- redraw_rate : int """ self._redraw_rate = redraw_rate self.redraw_timer.setInterval(int((1.0/self._redraw_rate)*1000)) def pausePlotting(self): self.redraw_timer.stop() if self.redraw_timer.isActive() else self.redraw_timer.start() return self.redraw_timer.isActive() def mouseMoved(self, evt): """ A handler for the crosshair feature. Every time the mouse move, the mouse coordinates are updated, and the horizontal and vertical hairlines will be redrawn at the new coordinate. If a PyDMDisplay object is available, that display will also have the x- and y- values to update on the UI. Parameters ------- evt: MouseEvent The mouse event type, from which the mouse coordinates are obtained. """ pos = evt[0] if self.sceneBoundingRect().contains(pos): mouse_point = self.getViewBox().mapSceneToView(pos) self.vertical_crosshair_line.setPos(mouse_point.x()) self.horizontal_crosshair_line.setPos(mouse_point.y()) self.crosshair_position_updated.emit(mouse_point.x(), mouse_point.y()) def enableCrosshair(self, is_enabled, starting_x_pos, starting_y_pos, vertical_angle=90, horizontal_angle=0, vertical_movable=False, horizontal_movable=False): """ Enable the crosshair to be drawn on the ViewBox. Parameters ---------- is_enabled : bool True is to draw the crosshair, False is to not draw. starting_x_pos : float The x coordinate where to start the vertical crosshair line. starting_y_pos : float The y coordinate where to start the horizontal crosshair line. vertical_angle : float The angle to tilt the vertical crosshair line. Default at 90 degrees. horizontal_angle The angle to tilt the horizontal crosshair line. Default at 0 degrees. vertical_movable : bool True if the vertical line can be moved by the user; False is not. horizontal_movable False if the horizontal line can be moved by the user; False is not. """ if is_enabled: self.vertical_crosshair_line = InfiniteLine(pos=starting_x_pos, angle=vertical_angle, movable=vertical_movable) self.horizontal_crosshair_line = InfiniteLine(pos=starting_y_pos, angle=horizontal_angle, movable=horizontal_movable) self.plotItem.addItem(self.vertical_crosshair_line) self.plotItem.addItem(self.horizontal_crosshair_line) self.crosshair_movement_proxy = SignalProxy(self.plotItem.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) else: if self.vertical_crosshair_line: self.plotItem.removeItem(self.vertical_crosshair_line) if self.horizontal_crosshair_line: self.plotItem.removeItem(self.horizontal_crosshair_line) if self.crosshair_movement_proxy: self.crosshair_movement_proxy.disconnect()