|
6 | 6 | import numpy as np |
7 | 7 | import numpy.typing as npt |
8 | 8 | import pandas as pd |
9 | | -from matplotlib.backend_bases import PickEvent |
| 9 | +from matplotlib.backend_bases import Event, MouseEvent, PickEvent |
10 | 10 | from matplotlib.backends.backend_qt5agg import ( # type: ignore |
11 | 11 | FigureCanvas, |
12 | 12 | NavigationToolbar2QT, |
13 | 13 | ) |
14 | 14 | from matplotlib.figure import Figure |
| 15 | +from matplotlib.font_manager import FontProperties |
| 16 | +from matplotlib.text import Text |
15 | 17 | from PyQt6.QtCore import QStringListModel, Qt |
16 | 18 | from PyQt6.QtCore import pyqtSignal as Signal |
17 | 19 | from PyQt6.QtCore import pyqtSlot as Slot |
18 | | -from PyQt6.QtGui import QAction |
| 20 | +from PyQt6.QtGui import QAction, QCursor |
19 | 21 | from PyQt6.QtWidgets import ( |
20 | 22 | QComboBox, |
| 23 | + QToolTip, |
21 | 24 | QVBoxLayout, |
22 | 25 | QWidget, |
23 | 26 | QWidgetAction, |
@@ -139,9 +142,13 @@ def __init__( |
139 | 142 | self._figure.set_layout_engine("tight") |
140 | 143 | self._canvas = FigureCanvas(self._figure) |
141 | 144 | self._canvas.mpl_connect("pick_event", self._on_canvas_pick) |
| 145 | + self._canvas.mpl_connect("motion_notify_event", self._on_canvas_motion) |
| 146 | + self._canvas.mpl_connect("figure_leave_event", self._on_canvas_leave) |
142 | 147 | self._canvas.setParent(self) |
143 | 148 | self._canvas.setFocusPolicy(Qt.FocusPolicy.StrongFocus) |
144 | 149 | self._canvas.setFocus() |
| 150 | + self._hovered_text_artist: Text | None = None |
| 151 | + self._hovered_font_properties: FontProperties | None = None |
145 | 152 |
|
146 | 153 | vbox = QVBoxLayout() |
147 | 154 | vbox.addWidget(self._canvas) |
@@ -203,10 +210,58 @@ def updatePlot( |
203 | 210 | ) |
204 | 211 |
|
205 | 212 | def _enable_text_picking(self) -> None: |
206 | | - for axes in self._figure.axes: |
207 | | - axes.xaxis.label.set_picker(True) |
208 | | - axes.yaxis.label.set_picker(True) |
209 | | - axes.title.set_picker(True) |
| 213 | + self._hovered_text_artist = None |
| 214 | + self._hovered_font_properties = None |
| 215 | + QToolTip.hideText() |
| 216 | + |
| 217 | + for text_artist in self._editable_text_artists(): |
| 218 | + text_artist.set_picker(True) |
| 219 | + |
| 220 | + def _editable_text_artists(self) -> list[Text]: |
| 221 | + return [ |
| 222 | + text_artist |
| 223 | + for axes in self._figure.axes |
| 224 | + for text_artist in (axes.xaxis.label, axes.yaxis.label, axes.title) |
| 225 | + ] |
| 226 | + |
| 227 | + def _clear_hovered_text_artist(self) -> None: |
| 228 | + if ( |
| 229 | + self._hovered_text_artist is not None |
| 230 | + and self._hovered_font_properties is not None |
| 231 | + ): |
| 232 | + self._hovered_text_artist.set_fontproperties(self._hovered_font_properties) |
| 233 | + |
| 234 | + self._hovered_text_artist = None |
| 235 | + self._hovered_font_properties = None |
| 236 | + QToolTip.hideText() |
| 237 | + |
| 238 | + def _on_canvas_motion(self, event: MouseEvent) -> None: |
| 239 | + hovered_text_artist = next( |
| 240 | + ( |
| 241 | + text_artist |
| 242 | + for text_artist in self._editable_text_artists() |
| 243 | + if text_artist.contains(event)[0] |
| 244 | + ), |
| 245 | + None, |
| 246 | + ) |
| 247 | + if hovered_text_artist is self._hovered_text_artist: |
| 248 | + return |
| 249 | + |
| 250 | + self._clear_hovered_text_artist() |
| 251 | + if hovered_text_artist is None: |
| 252 | + self._canvas.draw_idle() |
| 253 | + return |
| 254 | + |
| 255 | + self._hovered_text_artist = hovered_text_artist |
| 256 | + self._hovered_font_properties = hovered_text_artist.get_fontproperties().copy() |
| 257 | + hovered_text_artist.set_fontweight("bold") |
| 258 | + QToolTip.showText(QCursor.pos(), "Click to edit", self._canvas) |
| 259 | + |
| 260 | + self._canvas.draw_idle() |
| 261 | + |
| 262 | + def _on_canvas_leave(self, _: Event) -> None: |
| 263 | + self._clear_hovered_text_artist() |
| 264 | + self._canvas.draw_idle() |
210 | 265 |
|
211 | 266 | def _on_canvas_pick(self, event: PickEvent) -> None: |
212 | 267 | for axes in self._figure.axes: |
|
0 commit comments