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)
Esempio n. 2
0
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)
Esempio n. 3
0
    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)
Esempio n. 4
0
    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
Esempio n. 5
0
    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()
Esempio n. 6
0
    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
Esempio n. 8
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
Esempio n. 9
0
    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
Esempio n. 10
0
    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]))
Esempio n. 11
0
    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
Esempio n. 12
0
    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)
Esempio n. 13
0
    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()
Esempio n. 14
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()
Esempio n. 15
0
    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()
Esempio n. 16
0
    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()
Esempio n. 17
0
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()