Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 844fcc8

Browse files
authored
Merge pull request #2 from eslothower/yc-task2
task 2 - added hover backend implementation & tk specific label
2 parents e2b2c0e + 3998293 commit 844fcc8

File tree

7 files changed

+92
-33
lines changed

7 files changed

+92
-33
lines changed

doc/api/artist_api.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Interactive
4444
Artist.pickable
4545
Artist.set_picker
4646
Artist.get_picker
47+
Artist.hover
48+
Artist.hoverable
49+
Artist.set_hover
50+
Artist.get_hover
4751

4852
Clipping
4953
--------

lib/matplotlib/artist.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -595,38 +595,62 @@ def get_picker(self):
595595
set_picker, pickable, pick
596596
"""
597597
return self._picker
598-
598+
599+
def hoverable(self):
600+
"""
601+
Return whether the artist is hoverable.
602+
603+
See Also
604+
--------
605+
set_hover, get_hover, hover
606+
"""
607+
return self.figure is not None and self._hover is not None
608+
609+
def hover(self, mouseevent):
610+
"""
611+
Process a hover event.
612+
613+
Each child artist will fire a hover event if *mouseevent* is over
614+
the artist and the artist has hover set.
615+
616+
See Also
617+
--------
618+
set_hover, get_hover, hoverable
619+
"""
620+
from .backend_bases import HoverEvent # Circular import.
621+
# Hover self
622+
if self.hoverable():
623+
hoverer = self.get_hover()
624+
inside, prop = self.contains(mouseevent)
625+
if inside:
626+
HoverEvent("hover_event", self.figure.canvas,
627+
mouseevent, self, **prop)._process()
628+
629+
# Pick children
630+
for a in self.get_children():
631+
# make sure the event happened in the same Axes
632+
ax = getattr(a, 'axes', None)
633+
if (mouseevent.inaxes is None or ax is None
634+
or mouseevent.inaxes == ax):
635+
a.hover(mouseevent)
636+
599637
def set_hover(self, hover):
600638
"""
601639
Define the hover status of the artist.
602640
603641
Parameters
604642
----------
605-
hover : None or bool or float or callable
643+
hover : None or bool
606644
This can be one of the following:
607645
608646
- *None*: Hover is disabled for this artist (default).
609647
610648
- A boolean: If *True* then hover will be enabled and the
611649
artist will fire a hover event if the mouse event is hovering over
612650
the artist.
613-
614-
- A float: If hover is a number it is interpreted as an
615-
epsilon tolerance in points and the artist will fire
616-
off an event if its data is within epsilon of the mouse
617-
event. For some artists like lines and patch collections,
618-
the artist may provide additional data to the hover event
619-
that is generated, e.g., the indices of the data within
620-
epsilon of the hover event
621-
622-
- A function: If hover is callable, it is a user supplied
623-
function which determines whether the artist is hit by the
624-
mouse event to determine the hit test. if the mouse event
625-
is over the artist, return *hit=True* and props is a dictionary of
626-
properties you want added to the HoverEvent attributes.
627651
"""
628652
self._hover = hover
629-
653+
630654
def get_hover(self):
631655
"""
632656
Return the hover status of the artist.

lib/matplotlib/artist.pyi

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,10 @@ class Artist:
7676
) -> None | bool | float | Callable[
7777
[Artist, MouseEvent], tuple[bool, dict[Any, Any]]
7878
]: ...
79-
def set_hover(
80-
self,
81-
hover: None
82-
| bool
83-
| float
84-
| Callable[[Artist, MouseEvent], str],
85-
) -> None: ...
86-
def get_hover(
87-
self,
88-
) -> None | bool | float | Callable[
89-
[Artist, MouseEvent], str
90-
]: ...
79+
def hoverable(self) -> bool: ...
80+
def hover(self, mouseevent: MouseEvent) -> None: ...
81+
def set_hover(self, hover: None | bool) -> None: ...
82+
def get_hover(self) -> None | bool: ...
9183
def get_url(self) -> str | None: ...
9284
def set_url(self, url: str | None) -> None: ...
9385
def get_gid(self) -> str | None: ...

lib/matplotlib/backend_bases.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,8 @@ def __str__(self):
14731473
f"xy=({self.x}, {self.y}) xydata=({self.xdata}, {self.ydata}) "
14741474
f"button={self.button} dblclick={self.dblclick} "
14751475
f"inaxes={self.inaxes}")
1476-
1476+
1477+
14771478
class HoverEvent(Event):
14781479
"""
14791480
A hover event.
@@ -1522,6 +1523,7 @@ def __init__(self, name, canvas, mouseevent, artist,
15221523
self.artist = artist
15231524
self.__dict__.update(kwargs)
15241525

1526+
15251527
class PickEvent(Event):
15261528
"""
15271529
A pick event.
@@ -1571,7 +1573,7 @@ def __init__(self, name, canvas, mouseevent, artist,
15711573
self.__dict__.update(kwargs)
15721574

15731575

1574-
class KeyEvent(LocationEvent):
1576+
class KeyEvent(LocationEvent):
15751577
"""
15761578
A key event (key press, key release).
15771579
@@ -1744,7 +1746,8 @@ class FigureCanvasBase:
17441746
'figure_leave_event',
17451747
'axes_enter_event',
17461748
'axes_leave_event',
1747-
'close_event'
1749+
'close_event',
1750+
'hover_event'
17481751
]
17491752

17501753
fixed_dpi = None
@@ -2295,7 +2298,8 @@ def mpl_connect(self, s, func):
22952298
- 'figure_leave_event',
22962299
- 'axes_enter_event',
22972300
- 'axes_leave_event'
2298-
- 'close_event'.
2301+
- 'close_event'
2302+
- 'hover_event'
22992303
23002304
func : callable
23012305
The callback function to be executed, which must have the
@@ -3007,9 +3011,20 @@ def _mouse_event_to_message(event):
30073011
return ""
30083012

30093013
def mouse_move(self, event):
3014+
from .patches import Rectangle
30103015
self._update_cursor(event)
30113016
self.set_message(self._mouse_event_to_message(event))
30123017

3018+
if callable(getattr(self, 'set_hover_message', None)):
3019+
for a in self.canvas.figure.findobj(match=lambda x: not isinstance(x,
3020+
Rectangle), include_self=False):
3021+
inside, prop = a.contains(event)
3022+
if inside:
3023+
self.set_hover_message(self._mouse_event_to_message(event))
3024+
else:
3025+
self.set_hover_message("")
3026+
break
3027+
30133028
def _zoom_pan_handler(self, event):
30143029
if self.mode == _Mode.PAN:
30153030
if event.name == "button_press_event":

lib/matplotlib/backends/_backend_tk.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,12 @@ def __init__(self, canvas, window=None, *, pack_toolbar=True):
649649
justify=tk.RIGHT)
650650
self._message_label.pack(side=tk.RIGHT)
651651

652+
self.hover_message = tk.StringVar(master=self)
653+
self._hover_label = tk.Label(master=self, font=self._label_font,
654+
textvariable=self.hover_message,
655+
justify=tk.RIGHT)
656+
self._hover_label.pack(side=tk.RIGHT)
657+
652658
NavigationToolbar2.__init__(self, canvas)
653659
if pack_toolbar:
654660
self.pack(side=tk.BOTTOM, fill=tk.X)
@@ -700,6 +706,9 @@ def zoom(self, *args):
700706
def set_message(self, s):
701707
self.message.set(s)
702708

709+
def set_hover_message(self, s):
710+
self.hover_message.set(s)
711+
703712
def draw_rubberband(self, event, x0, y0, x1, y1):
704713
# Block copied from remove_rubberband for backend_tools convenience.
705714
if self.canvas._rubberband_rect_white:
@@ -976,6 +985,12 @@ def __init__(self, toolmanager, window=None):
976985
self._message_label = tk.Label(master=self, font=self._label_font,
977986
textvariable=self._message)
978987
self._message_label.pack(side=tk.RIGHT)
988+
989+
self._hover_message = tk.StringVar(master=self)
990+
self._hover_label = tk.Label(master=self, font=self._label_font,
991+
textvariable=self._hover_message)
992+
self._hover_label.pack(side=tk.RIGHT)
993+
979994
self._toolitems = {}
980995
self.pack(side=tk.TOP, fill=tk.X)
981996
self._groups = {}
@@ -1032,6 +1047,9 @@ def remove_toolitem(self, name):
10321047
def set_message(self, s):
10331048
self._message.set(s)
10341049

1050+
def set_hover_message(self, s):
1051+
self._hover_message.set(s)
1052+
10351053

10361054
@backend_tools._register_tool_class(FigureCanvasTk)
10371055
class SaveFigureTk(backend_tools.SaveFigureBase):

lib/matplotlib/figure.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,6 +2519,7 @@ def __init__(self,
25192519
]
25202520
self._button_pick_id = connect('button_press_event', self.pick)
25212521
self._scroll_pick_id = connect('scroll_event', self.pick)
2522+
self._hover_id = connect('motion_notify_event', self.hover)
25222523

25232524
if figsize is None:
25242525
figsize = mpl.rcParams['figure.figsize']
@@ -2566,6 +2567,10 @@ def pick(self, mouseevent):
25662567
if not self.canvas.widgetlock.locked():
25672568
super().pick(mouseevent)
25682569

2570+
def hover(self, mouseevent):
2571+
if not self.canvas.widgetlock.locked():
2572+
super().hover(mouseevent)
2573+
25692574
def _check_layout_engines_compat(self, old, new):
25702575
"""
25712576
Helper for set_layout engine

lib/matplotlib/figure.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ class Figure(FigureBase):
321321
**kwargs
322322
) -> None: ...
323323
def pick(self, mouseevent: MouseEvent) -> None: ...
324+
def hover(self, mouseevent: MouseEvent) -> None: ...
324325
def set_layout_engine(
325326
self,
326327
layout: Literal["constrained", "compressed", "tight", "none"]

0 commit comments

Comments
 (0)