From 4b4bf5e670089a3d5131e7d53c1d10e83cac05e7 Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Thu, 30 May 2024 20:34:30 +0900 Subject: [PATCH 1/9] Added the way that coordinates are copied to the clipboard --- plottr/plot/mpl/widgets.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 67194f38..adb449e2 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -123,6 +123,11 @@ def metaToClipboard(self) -> None: for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) + def coordinateToClipboard(self, event): + clipboard = QtWidgets.QApplication.clipboard() + coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) + clipboard.setText(coord_info_string) + def setFigureTitle(self, title: str) -> None: """Add a title to the figure.""" self.fig.suptitle(title, @@ -162,6 +167,7 @@ def __init__(self, parent: Optional[PlotWidgetContainer] = None): layout.addWidget(self.plot) layout.addWidget(self.mplBar) self.setLayout(layout) + self.addPlotOptions() def setMeta(self, data: DataDictBase) -> None: """Add meta info contained in the data to the figure. @@ -195,6 +201,10 @@ def addMplBarOptions(self) -> None: self.mplBar.addSeparator() self.mplBar.addAction('Copy Figure', self.plot.toClipboard) self.mplBar.addAction('Copy Meta', self.plot.metaToClipboard) + + def addPlotOptions(self) -> None: + """Add options for copying coordinates to the clipboard""" + self.plot.mpl_connect('button_press_event', self.plot.coordinateToClipboard) def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]: From efe39a3bf9e97baabd25654936d2fab49616e142 Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Fri, 31 May 2024 10:52:11 +0900 Subject: [PATCH 2/9] remove bug from coordinateToClipboard --- plottr/plot/mpl/widgets.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index adb449e2..839770e9 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -123,10 +123,13 @@ def metaToClipboard(self) -> None: for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) - def coordinateToClipboard(self, event): + def coordinateToClipboard(self, event) -> None: clipboard = QtWidgets.QApplication.clipboard() - coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) - clipboard.setText(coord_info_string) + try: + coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) + clipboard.setText(coord_info_string) + except TypeError: + pass def setFigureTitle(self, title: str) -> None: """Add a title to the figure.""" From a710590543b350e5ce40d41e53a4ac44f6a2c209 Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:32:54 +0900 Subject: [PATCH 3/9] Fixed mypy error --- plottr/plot/mpl/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 839770e9..f05719c6 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -8,6 +8,7 @@ from matplotlib import rcParams from matplotlib.axes import Axes from matplotlib.figure import Figure +from matplotlib.backend_bases import Event from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FCanvas, NavigationToolbar2QT as NavBar, @@ -123,7 +124,7 @@ def metaToClipboard(self) -> None: for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) - def coordinateToClipboard(self, event) -> None: + def coordinateToClipboard(self, event: Event) -> None: clipboard = QtWidgets.QApplication.clipboard() try: coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) From 77cabccdfa167f323180212f3fee6bf1e1c2b906 Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:24:37 +0900 Subject: [PATCH 4/9] Fixed mypy error 2 --- plottr/plot/mpl/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index f05719c6..8707f14b 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -8,7 +8,7 @@ from matplotlib import rcParams from matplotlib.axes import Axes from matplotlib.figure import Figure -from matplotlib.backend_bases import Event +from matplotlib.backend_bases import LocationEvent from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FCanvas, NavigationToolbar2QT as NavBar, @@ -124,7 +124,7 @@ def metaToClipboard(self) -> None: for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) - def coordinateToClipboard(self, event: Event) -> None: + def coordinateToClipboard(self, event: LocationEvent) -> None: clipboard = QtWidgets.QApplication.clipboard() try: coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) From 4f8fc7e81c4f01f3b3c2ace7e03b3143eebd1055 Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:01:29 +0900 Subject: [PATCH 5/9] Fixed mypy error 3 --- plottr/plot/mpl/widgets.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 8707f14b..92989a8e 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -8,7 +8,7 @@ from matplotlib import rcParams from matplotlib.axes import Axes from matplotlib.figure import Figure -from matplotlib.backend_bases import LocationEvent +from matplotlib.backend_bases import LocationEvent, Event from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FCanvas, NavigationToolbar2QT as NavBar, @@ -124,13 +124,14 @@ def metaToClipboard(self) -> None: for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) - def coordinateToClipboard(self, event: LocationEvent) -> None: - clipboard = QtWidgets.QApplication.clipboard() - try: - coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) - clipboard.setText(coord_info_string) - except TypeError: - pass + def coordinateToClipboard(self, event: Event) -> None: + if isinstance(event, LocationEvent): + clipboard = QtWidgets.QApplication.clipboard() + if event.xdata is not None and event.ydata is not None: + coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) + clipboard.setText(coord_info_string) + else: + pass def setFigureTitle(self, title: str) -> None: """Add a title to the figure.""" From 55149f0852fea55b30adea1030c347270a6a92df Mon Sep 17 00:00:00 2001 From: yuimuto <48644462+yuiponpon@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:39:53 +0900 Subject: [PATCH 6/9] Change the number of significant figures. --- plottr/plot/mpl/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 92989a8e..cdcd2f6b 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -128,7 +128,7 @@ def coordinateToClipboard(self, event: Event) -> None: if isinstance(event, LocationEvent): clipboard = QtWidgets.QApplication.clipboard() if event.xdata is not None and event.ydata is not None: - coord_info_string = '({:.4g}, {:.4g})'.format(event.xdata, event.ydata) + coord_info_string = '({:.8g}, {:.8g})'.format(event.xdata, event.ydata) clipboard.setText(coord_info_string) else: pass From a3a12b0908f59d062797f185270c71cd985f7186 Mon Sep 17 00:00:00 2001 From: marcosf2 Date: Thu, 14 May 2026 15:12:21 -0500 Subject: [PATCH 7/9] added clipboard feedback and enhanced toolbar functionality for MPL plots --- plottr/plot/mpl/widgets.py | 48 +++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index cdcd2f6b..68f78bce 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -21,6 +21,36 @@ from ..base import PlotWidget, PlotWidgetContainer +class MPLNavBar(NavBar): + """ + Toolbar subclass that shows a hint when the mouse is outside the axes + and can pin a clipboard confirmation message, so hovering won't overwrite it + for a few seconds to make the message visible. + """ + + def __init__(self, canvas: FCanvas, parent: QtWidgets.QWidget): + self.clipboardMessageActive = False + self.hintMessage = "Click on plot to copy coordinates" + super().__init__(canvas, parent) + self.clipboardResetTimer = QtCore.QTimer(self) + self.clipboardResetTimer.setSingleShot(True) + self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage) + + def set_message(self, s: str) -> None: + if self.clipboardMessageActive: + return + super().set_message(s if s else self.hintMessage) + + def showClipboardMessage(self, message: str) -> None: + self.clipboardMessageActive = True + super().set_message(message) + self.clipboardResetTimer.start(1500) + + def clearClipboardMessage(self) -> None: + self.clipboardMessageActive = False + super().set_message(self.hintMessage) + + class MPLPlot(FCanvas): """ This is the basic matplotlib canvas widget we are using for matplotlib @@ -30,6 +60,9 @@ class MPLPlot(FCanvas): It can be used as any QT widget. """ + #: Signal(str) -- emitted when content is copied to the clipboard, with a message describing what was copied. + clipboardCopied = QtCore.Signal(str) + def __init__(self, parent: Optional[QtWidgets.QWidget] = None, width: float = 4.0, height: float = 3.0, dpi: int = 150, constrainedLayout: bool = True): @@ -117,12 +150,14 @@ def toClipboard(self) -> None: clipboard = QtWidgets.QApplication.clipboard() clipboard.setImage(QtGui.QImage.fromData(buf.getvalue())) buf.close() + self.clipboardCopied.emit("Figure copied to clipboard") def metaToClipboard(self) -> None: clipboard = QtWidgets.QApplication.clipboard() meta_info_string = "\n".join(f"{k}: {v}" for k, v in self._meta_info.items()) clipboard.setText(meta_info_string) + self.clipboardCopied.emit("Meta copied to clipboard") def coordinateToClipboard(self, event: Event) -> None: if isinstance(event, LocationEvent): @@ -130,8 +165,7 @@ def coordinateToClipboard(self, event: Event) -> None: if event.xdata is not None and event.ydata is not None: coord_info_string = '({:.8g}, {:.8g})'.format(event.xdata, event.ydata) clipboard.setText(coord_info_string) - else: - pass + self.clipboardCopied.emit(f"Copied {coord_info_string} to clipboard") def setFigureTitle(self, title: str) -> None: """Add a title to the figure.""" @@ -163,7 +197,7 @@ def __init__(self, parent: Optional[PlotWidgetContainer] = None): self.plot = MPLPlot() #: the matplotlib toolbar - self.mplBar = NavBar(self.plot, self) + self.mplBar = MPLNavBar(self.plot, self) self.addMplBarOptions() defaultIconSize = int(16 * dpiScalingFactor(self)) @@ -171,6 +205,7 @@ def __init__(self, parent: Optional[PlotWidgetContainer] = None): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.plot) layout.addWidget(self.mplBar) + self.setLayout(layout) self.addPlotOptions() @@ -206,10 +241,12 @@ def addMplBarOptions(self) -> None: self.mplBar.addSeparator() self.mplBar.addAction('Copy Figure', self.plot.toClipboard) self.mplBar.addAction('Copy Meta', self.plot.metaToClipboard) - + def addPlotOptions(self) -> None: """Add options for copying coordinates to the clipboard""" self.plot.mpl_connect('button_press_event', self.plot.coordinateToClipboard) + self.plot.clipboardCopied.connect(self.mplBar.showClipboardMessage) + self.mplBar.clearClipboardMessage() def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]: @@ -218,5 +255,4 @@ def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]: :return: The figure object of the plot, and the dialog window object. """ widget = MPLPlotWidget() - return widget.plot.fig, widgetDialog(widget) - + return widget.plot.fig, widgetDialog(widget) \ No newline at end of file From df8106481f4240abae20e9eac3aeace2e3feaba4 Mon Sep 17 00:00:00 2001 From: marcosf2 Date: Thu, 14 May 2026 16:00:12 -0500 Subject: [PATCH 8/9] Added copy coordinates and messages to pyqtgraph --- plottr/plot/mpl/widgets.py | 4 +-- plottr/plot/pyqtgraph/autoplot.py | 56 ++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 68f78bce..88b6fc46 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -15,7 +15,7 @@ ) from matplotlib.text import Text -from plottr import QtWidgets, QtGui, QtCore, config as plottrconfig +from plottr import QtWidgets, QtGui, QtCore, Signal, config as plottrconfig from plottr.data.datadict import DataDictBase from plottr.gui.tools import widgetDialog, dpiScalingFactor from ..base import PlotWidget, PlotWidgetContainer @@ -61,7 +61,7 @@ class MPLPlot(FCanvas): """ #: Signal(str) -- emitted when content is copied to the clipboard, with a message describing what was copied. - clipboardCopied = QtCore.Signal(str) + clipboardCopied = Signal(str) def __init__(self, parent: Optional[QtWidgets.QWidget] = None, width: float = 4.0, height: float = 3.0, dpi: int = 150, diff --git a/plottr/plot/pyqtgraph/autoplot.py b/plottr/plot/pyqtgraph/autoplot.py index 31b9e054..08ed324f 100644 --- a/plottr/plot/pyqtgraph/autoplot.py +++ b/plottr/plot/pyqtgraph/autoplot.py @@ -271,6 +271,16 @@ def __init__(self, parent: Optional[PlotWidgetContainer]) -> None: layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) + self.statusLabel = QtWidgets.QLabel("Click on plot to copy coordinates") + self.statusLabel.setAlignment(QtCore.Qt.AlignCenter) + self.statusLabel.setStyleSheet("color: gray;") + + self.clipboardMessageActive = False + self.hintMessage = "Click on plot to copy coordinates" + self.clipboardResetTimer = QtCore.QTimer(self) + self.clipboardResetTimer.setSingleShot(True) + self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage) + self.setLayout(layout) self.setMinimumSize(*getcfg('main', 'pyqtgraph', 'minimum_plot_size', default=(400, 400))) @@ -327,6 +337,11 @@ def _plotData(self, **kwargs: Any) -> None: self.figConfig.optionsChanged.connect(self._refreshPlot) self.figConfig.figCopied.connect(self.onfigCopied) self.figConfig.figSaved.connect(self.onfigSaved) + self.layout().addWidget(self.statusLabel) + + if kwargs.get('clearWidget', True): + for subplot in self.fmWidget.subPlots: + self._connectPlotEvents(subplot) if self.data.has_meta('title'): self.fmWidget.setTitle(self.data.meta_val('title')) @@ -356,6 +371,45 @@ def _plotData(self, **kwargs: Any) -> None: def _refreshPlot(self) -> None: self._plotData() + def showClipboardMessage(self, message: str) -> None: + self.clipboardMessageActive = True + self.statusLabel.setText(message) + self.clipboardResetTimer.start(1500) + + def clearClipboardMessage(self) -> None: + self.clipboardMessageActive = False + self.statusLabel.setText(self.hintMessage) + + def setStatusMessage(self, message: str) -> None: + if not self.clipboardMessageActive: + self.statusLabel.setText(message if message else self.hintMessage) + + def _connectPlotEvents(self, subplot: PlotBase) -> None: + subplot.plot.scene().sigMouseMoved.connect( + lambda pos, sp=subplot: self._onMouseMoved(sp, pos) + ) + subplot.plot.scene().sigMouseClicked.connect( + lambda event, sp=subplot: self._onPlotClicked(sp, event) + ) + + def _onMouseMoved(self, subplot: PlotBase, pos: Any) -> None: + vb = subplot.plot.getViewBox() + local = vb.mapFromScene(pos) + if vb.boundingRect().contains(local): + pt = vb.mapSceneToView(pos) + self.setStatusMessage(f'({pt.x():.8g}, {pt.y():.8g})') + else: + self.setStatusMessage('') + + def _onPlotClicked(self, subplot: PlotBase, event: Any) -> None: + vb = subplot.plot.getViewBox() + local = vb.mapFromScene(event.scenePos()) + if vb.boundingRect().contains(local): + pt = vb.mapSceneToView(event.scenePos()) + coord_str = '({:.8g}, {:.8g})'.format(pt.x(), pt.y()) + QtWidgets.QApplication.clipboard().setText(coord_str) + self.showClipboardMessage(f"Copied {coord_str} to clipboard") + @Slot() def onfigCopied(self) -> None: """ @@ -366,6 +420,7 @@ def onfigCopied(self) -> None: screenshot = self.fmWidget.grab(rectangle=QtCore.QRect(QtCore.QPoint(0, 0), QtCore.QSize(-1, -1))) clipboard = QtWidgets.QApplication.clipboard() clipboard.setImage(screenshot.toImage()) + self.showClipboardMessage("Figure copied to clipboard") @Slot() def onfigSaved(self) -> None: @@ -449,7 +504,6 @@ def __init__(self, options: FigureOptions, self.copyFig = self.addAction('Copy Figure', self._copyFig) self.saveFig = self.addAction('Save Figure', self._saveFig) - def _setOption(self, option: str, value: Any) -> None: setattr(self.options, option, value) self.optionsChanged.emit() From 19dfd1abfe8a8d4723ea0c52d839b8d7e8741757 Mon Sep 17 00:00:00 2001 From: marcosf2 Date: Thu, 14 May 2026 17:21:38 -0500 Subject: [PATCH 9/9] Makes messaging and clipboard logic into its own mixin --- plottr/plot/base.py | 37 +++++++++++++++++++++++++++++-- plottr/plot/mpl/widgets.py | 28 +++++++++-------------- plottr/plot/pyqtgraph/autoplot.py | 25 +++++++-------------- 3 files changed, 53 insertions(+), 37 deletions(-) diff --git a/plottr/plot/base.py b/plottr/plot/base.py index 8b7217d8..a1e94399 100644 --- a/plottr/plot/base.py +++ b/plottr/plot/base.py @@ -9,11 +9,11 @@ from enum import Enum, unique, auto from types import TracebackType from typing import Dict, List, Type, Tuple, Optional, Any, \ - OrderedDict as OrderedDictType, Union + OrderedDict as OrderedDictType, Union, cast import numpy as np -from .. import Signal, Flowchart, QtWidgets +from .. import Signal, Flowchart, QtCore, QtWidgets from ..data.datadict import DataDictBase, DataDict, MeshgridDataDict from ..node import Node, linearFlowchart from ..utils import LabeledOptions @@ -22,6 +22,39 @@ __license__ = 'MIT' +class ClipboardMessageMixin: + """ + Mixin for widgets that show a transient clipboard-feedback message + and revert to a hint message after a short timeout. + + Subclasses must inherit from a ``QObject``, implement ``_displayMessage`` + to render the text, and call ``_initClipboardMessage`` once in ``__init__``. + """ + + CLIPBOARD_MESSAGE_DURATION_MS = 1500 + CLIPBOARD_HINT_MESSAGE = "Click on plot to copy coordinates" + + def _initClipboardMessage(self) -> None: + self.clipboardMessageActive = False + # cast: subclasses are guaranteed to be QObjects (see docstring), but + # the mixin can't inherit from QObject without breaking Qt-binding portability. + self.clipboardResetTimer = QtCore.QTimer(cast(QtCore.QObject, self)) + self.clipboardResetTimer.setSingleShot(True) + self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage) + + def _displayMessage(self, message: str) -> None: + raise NotImplementedError + + def showClipboardMessage(self, message: str) -> None: + self.clipboardMessageActive = True + self._displayMessage(message) + self.clipboardResetTimer.start(self.CLIPBOARD_MESSAGE_DURATION_MS) + + def clearClipboardMessage(self) -> None: + self.clipboardMessageActive = False + self._displayMessage(self.CLIPBOARD_HINT_MESSAGE) + + class PlotNode(Node): """ Basic Plot Node, derived from :class:`plottr.node.node.Node`. diff --git a/plottr/plot/mpl/widgets.py b/plottr/plot/mpl/widgets.py index 88b6fc46..39b144c0 100644 --- a/plottr/plot/mpl/widgets.py +++ b/plottr/plot/mpl/widgets.py @@ -8,7 +8,7 @@ from matplotlib import rcParams from matplotlib.axes import Axes from matplotlib.figure import Figure -from matplotlib.backend_bases import LocationEvent, Event +from matplotlib.backend_bases import LocationEvent, MouseButton, Event from matplotlib.backends.backend_qt5agg import ( FigureCanvasQTAgg as FCanvas, NavigationToolbar2QT as NavBar, @@ -18,10 +18,10 @@ from plottr import QtWidgets, QtGui, QtCore, Signal, config as plottrconfig from plottr.data.datadict import DataDictBase from plottr.gui.tools import widgetDialog, dpiScalingFactor -from ..base import PlotWidget, PlotWidgetContainer +from ..base import PlotWidget, PlotWidgetContainer, ClipboardMessageMixin -class MPLNavBar(NavBar): +class MPLNavBar(ClipboardMessageMixin, NavBar): """ Toolbar subclass that shows a hint when the mouse is outside the axes and can pin a clipboard confirmation message, so hovering won't overwrite it @@ -29,26 +29,16 @@ class MPLNavBar(NavBar): """ def __init__(self, canvas: FCanvas, parent: QtWidgets.QWidget): - self.clipboardMessageActive = False - self.hintMessage = "Click on plot to copy coordinates" super().__init__(canvas, parent) - self.clipboardResetTimer = QtCore.QTimer(self) - self.clipboardResetTimer.setSingleShot(True) - self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage) + self._initClipboardMessage() def set_message(self, s: str) -> None: if self.clipboardMessageActive: return - super().set_message(s if s else self.hintMessage) + NavBar.set_message(self, s if s else self.CLIPBOARD_HINT_MESSAGE) - def showClipboardMessage(self, message: str) -> None: - self.clipboardMessageActive = True - super().set_message(message) - self.clipboardResetTimer.start(1500) - - def clearClipboardMessage(self) -> None: - self.clipboardMessageActive = False - super().set_message(self.hintMessage) + def _displayMessage(self, message: str) -> None: + NavBar.set_message(self, message) class MPLPlot(FCanvas): @@ -161,6 +151,8 @@ def metaToClipboard(self) -> None: def coordinateToClipboard(self, event: Event) -> None: if isinstance(event, LocationEvent): + if getattr(event, 'button', None) != MouseButton.LEFT: + return clipboard = QtWidgets.QApplication.clipboard() if event.xdata is not None and event.ydata is not None: coord_info_string = '({:.8g}, {:.8g})'.format(event.xdata, event.ydata) @@ -255,4 +247,4 @@ def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]: :return: The figure object of the plot, and the dialog window object. """ widget = MPLPlotWidget() - return widget.plot.fig, widgetDialog(widget) \ No newline at end of file + return widget.plot.fig, widgetDialog(widget) diff --git a/plottr/plot/pyqtgraph/autoplot.py b/plottr/plot/pyqtgraph/autoplot.py index 08ed324f..23011431 100644 --- a/plottr/plot/pyqtgraph/autoplot.py +++ b/plottr/plot/pyqtgraph/autoplot.py @@ -23,7 +23,7 @@ from .plots import Plot, PlotWithColorbar, PlotBase from ..base import AutoFigureMaker as BaseFM, PlotDataType, \ PlotItem, ComplexRepresentation, determinePlotDataType, \ - PlotWidgetContainer, PlotWidget + PlotWidgetContainer, PlotWidget, ClipboardMessageMixin logger = logging.getLogger(__name__) @@ -249,7 +249,7 @@ def _scatterPlot2d(self, plotItem: PlotItem) -> None: subPlot.setScatter2d(*plotItem.data) -class AutoPlot(PlotWidget): +class AutoPlot(ClipboardMessageMixin, PlotWidget): """Widget for automatic plotting with pyqtgraph. Uses :class:`.FigureMaker` to produce subplots. @@ -271,16 +271,11 @@ def __init__(self, parent: Optional[PlotWidgetContainer]) -> None: layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) - self.statusLabel = QtWidgets.QLabel("Click on plot to copy coordinates") + self._initClipboardMessage() + self.statusLabel = QtWidgets.QLabel(self.CLIPBOARD_HINT_MESSAGE) self.statusLabel.setAlignment(QtCore.Qt.AlignCenter) self.statusLabel.setStyleSheet("color: gray;") - self.clipboardMessageActive = False - self.hintMessage = "Click on plot to copy coordinates" - self.clipboardResetTimer = QtCore.QTimer(self) - self.clipboardResetTimer.setSingleShot(True) - self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage) - self.setLayout(layout) self.setMinimumSize(*getcfg('main', 'pyqtgraph', 'minimum_plot_size', default=(400, 400))) @@ -371,18 +366,12 @@ def _plotData(self, **kwargs: Any) -> None: def _refreshPlot(self) -> None: self._plotData() - def showClipboardMessage(self, message: str) -> None: - self.clipboardMessageActive = True + def _displayMessage(self, message: str) -> None: self.statusLabel.setText(message) - self.clipboardResetTimer.start(1500) - - def clearClipboardMessage(self) -> None: - self.clipboardMessageActive = False - self.statusLabel.setText(self.hintMessage) def setStatusMessage(self, message: str) -> None: if not self.clipboardMessageActive: - self.statusLabel.setText(message if message else self.hintMessage) + self.statusLabel.setText(message if message else self.CLIPBOARD_HINT_MESSAGE) def _connectPlotEvents(self, subplot: PlotBase) -> None: subplot.plot.scene().sigMouseMoved.connect( @@ -402,6 +391,8 @@ def _onMouseMoved(self, subplot: PlotBase, pos: Any) -> None: self.setStatusMessage('') def _onPlotClicked(self, subplot: PlotBase, event: Any) -> None: + if event.button() != QtCore.Qt.LeftButton: + return vb = subplot.plot.getViewBox() local = vb.mapFromScene(event.scenePos()) if vb.boundingRect().contains(local):