Skip to content

Commit a3a12b0

Browse files
committed
added clipboard feedback and enhanced toolbar functionality for MPL plots
1 parent 55149f0 commit a3a12b0

1 file changed

Lines changed: 42 additions & 6 deletions

File tree

plottr/plot/mpl/widgets.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,36 @@
2121
from ..base import PlotWidget, PlotWidgetContainer
2222

2323

24+
class MPLNavBar(NavBar):
25+
"""
26+
Toolbar subclass that shows a hint when the mouse is outside the axes
27+
and can pin a clipboard confirmation message, so hovering won't overwrite it
28+
for a few seconds to make the message visible.
29+
"""
30+
31+
def __init__(self, canvas: FCanvas, parent: QtWidgets.QWidget):
32+
self.clipboardMessageActive = False
33+
self.hintMessage = "Click on plot to copy coordinates"
34+
super().__init__(canvas, parent)
35+
self.clipboardResetTimer = QtCore.QTimer(self)
36+
self.clipboardResetTimer.setSingleShot(True)
37+
self.clipboardResetTimer.timeout.connect(self.clearClipboardMessage)
38+
39+
def set_message(self, s: str) -> None:
40+
if self.clipboardMessageActive:
41+
return
42+
super().set_message(s if s else self.hintMessage)
43+
44+
def showClipboardMessage(self, message: str) -> None:
45+
self.clipboardMessageActive = True
46+
super().set_message(message)
47+
self.clipboardResetTimer.start(1500)
48+
49+
def clearClipboardMessage(self) -> None:
50+
self.clipboardMessageActive = False
51+
super().set_message(self.hintMessage)
52+
53+
2454
class MPLPlot(FCanvas):
2555
"""
2656
This is the basic matplotlib canvas widget we are using for matplotlib
@@ -30,6 +60,9 @@ class MPLPlot(FCanvas):
3060
It can be used as any QT widget.
3161
"""
3262

63+
#: Signal(str) -- emitted when content is copied to the clipboard, with a message describing what was copied.
64+
clipboardCopied = QtCore.Signal(str)
65+
3366
def __init__(self, parent: Optional[QtWidgets.QWidget] = None,
3467
width: float = 4.0, height: float = 3.0, dpi: int = 150,
3568
constrainedLayout: bool = True):
@@ -117,21 +150,22 @@ def toClipboard(self) -> None:
117150
clipboard = QtWidgets.QApplication.clipboard()
118151
clipboard.setImage(QtGui.QImage.fromData(buf.getvalue()))
119152
buf.close()
153+
self.clipboardCopied.emit("Figure copied to clipboard")
120154

121155
def metaToClipboard(self) -> None:
122156
clipboard = QtWidgets.QApplication.clipboard()
123157
meta_info_string = "\n".join(f"{k}: {v}"
124158
for k, v in self._meta_info.items())
125159
clipboard.setText(meta_info_string)
160+
self.clipboardCopied.emit("Meta copied to clipboard")
126161

127162
def coordinateToClipboard(self, event: Event) -> None:
128163
if isinstance(event, LocationEvent):
129164
clipboard = QtWidgets.QApplication.clipboard()
130165
if event.xdata is not None and event.ydata is not None:
131166
coord_info_string = '({:.8g}, {:.8g})'.format(event.xdata, event.ydata)
132167
clipboard.setText(coord_info_string)
133-
else:
134-
pass
168+
self.clipboardCopied.emit(f"Copied {coord_info_string} to clipboard")
135169

136170
def setFigureTitle(self, title: str) -> None:
137171
"""Add a title to the figure."""
@@ -163,14 +197,15 @@ def __init__(self, parent: Optional[PlotWidgetContainer] = None):
163197
self.plot = MPLPlot()
164198

165199
#: the matplotlib toolbar
166-
self.mplBar = NavBar(self.plot, self)
200+
self.mplBar = MPLNavBar(self.plot, self)
167201

168202
self.addMplBarOptions()
169203
defaultIconSize = int(16 * dpiScalingFactor(self))
170204
self.mplBar.setIconSize(QtCore.QSize(defaultIconSize, defaultIconSize))
171205
layout = QtWidgets.QVBoxLayout(self)
172206
layout.addWidget(self.plot)
173207
layout.addWidget(self.mplBar)
208+
174209
self.setLayout(layout)
175210
self.addPlotOptions()
176211

@@ -206,10 +241,12 @@ def addMplBarOptions(self) -> None:
206241
self.mplBar.addSeparator()
207242
self.mplBar.addAction('Copy Figure', self.plot.toClipboard)
208243
self.mplBar.addAction('Copy Meta', self.plot.metaToClipboard)
209-
244+
210245
def addPlotOptions(self) -> None:
211246
"""Add options for copying coordinates to the clipboard"""
212247
self.plot.mpl_connect('button_press_event', self.plot.coordinateToClipboard)
248+
self.plot.clipboardCopied.connect(self.mplBar.showClipboardMessage)
249+
self.mplBar.clearClipboardMessage()
213250

214251

215252
def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]:
@@ -218,5 +255,4 @@ def figureDialog() -> Tuple[Figure, QtWidgets.QDialog]:
218255
:return: The figure object of the plot, and the dialog window object.
219256
"""
220257
widget = MPLPlotWidget()
221-
return widget.plot.fig, widgetDialog(widget)
222-
258+
return widget.plot.fig, widgetDialog(widget)

0 commit comments

Comments
 (0)