1+ from collections import namedtuple
12import functools
23import os
34import sys
@@ -213,6 +214,9 @@ def _timer_stop(self):
213214 self ._timer .stop ()
214215
215216
217+ Crosshair = namedtuple ('Crosshair' , 'x, y, x0, x1, y0, y1' )
218+
219+
216220class FigureCanvasQT (FigureCanvasBase , QtWidgets .QWidget ):
217221 required_interactive_framework = "qt"
218222 _timer_cls = TimerQT
@@ -231,6 +235,7 @@ class FigureCanvasQT(FigureCanvasBase, QtWidgets.QWidget):
231235 def __init__ (self , figure = None ):
232236 _create_qApp ()
233237 super ().__init__ (figure = figure )
238+ self ._crosshair = None
234239
235240 self ._draw_pending = False
236241 self ._is_drawing = False
@@ -239,7 +244,6 @@ def __init__(self, figure=None):
239244
240245 self .setAttribute (QtCore .Qt .WidgetAttribute .WA_OpaquePaintEvent )
241246 self .setMouseTracking (True )
242- self .mouse_xy = (0 , 0 )
243247 self .resize (* self .get_width_height ())
244248
245249 palette = QtGui .QPalette (QtGui .QColor ("white" ))
@@ -306,6 +310,21 @@ def mouseEventCoords(self, pos=None):
306310 y = self .figure .bbox .height / self .device_pixel_ratio - pos .y ()
307311 return x * self .device_pixel_ratio , y * self .device_pixel_ratio
308312
313+ def _update_crosshair (self , x , y ):
314+ previous_crosshair = self ._crosshair
315+ ax = self .inaxes ((x , y ))
316+ if ax is None :
317+ self ._crosshair = None
318+ else :
319+ bbox = ax .get_position () # in figure coords
320+ x0 = int (bbox .x0 * self .width ())
321+ x1 = int (bbox .x1 * self .width ())
322+ y0 = int ((1 - bbox .y0 ) * self .height ())
323+ y1 = int ((1 - bbox .y1 ) * self .height ())
324+ self ._crosshair = Crosshair (x , y , x0 , x1 , y0 , y1 )
325+ needs_repaint = previous_crosshair is not None or self ._crosshair is not None
326+ return needs_repaint
327+
309328 def enterEvent (self , event ):
310329 # Force querying of the modifiers, as the cached modifier state can
311330 # have been invalidated while the window was out of focus.
@@ -345,10 +364,12 @@ def mouseDoubleClickEvent(self, event):
345364 def mouseMoveEvent (self , event ):
346365 if self .figure is None :
347366 return
348- self .mouse_xy = self .mouseEventCoords (event )
349- self .repaint ()
367+ mouse_xy = self .mouseEventCoords (event )
368+ needs_repaint = self ._update_crosshair (* mouse_xy )
369+ if needs_repaint :
370+ self .repaint ()
350371 MouseEvent ("motion_notify_event" , self ,
351- * self . mouse_xy ,
372+ * mouse_xy ,
352373 buttons = self ._mpl_buttons (event .buttons ()),
353374 modifiers = self ._mpl_modifiers (),
354375 guiEvent = event )._process ()
0 commit comments