Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 56766cc

Browse files
lucychencysychen288
andauthored
implemented hover feature for other backends; fixed string list; adde... (#9)
* implemented hover feature for other backends; fixed string list; added dict * fix linter issues * more linter issues --------- Co-authored-by: Yanshi Chen <ychen288@u.rochester.edu>
1 parent 2211b57 commit 56766cc

File tree

9 files changed

+96
-24
lines changed

9 files changed

+96
-24
lines changed

‎galleries/examples/event_handling/hover_event_demo.py‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
* list of string literals - hovering is enabled, and hovering over a point
2020
displays the corresponding string literal.
2121
22+
* dictionary - hovering is enabled, and hovering over a point
23+
displays the string literal corresponding to the coordinate tuple.
24+
2225
* function - if hover is callable, it is a user supplied function which
2326
takes a ``mouseevent`` object (see below), and returns a tuple of transformed
2427
coordinates
@@ -69,16 +72,26 @@ def hover_handler(event):
6972
from numpy.random import rand
7073

7174
fig, ax = plt.subplots()
72-
plt.ylabel('some numbers')
7375

7476
ax.plot(rand(3), 'o', hover=['London', 'Paris', 'Barcelona'])
7577
plt.show()
7678

79+
# %%
80+
# Hover with dictionary data
81+
# --------------------------------
82+
fig, ax = plt.subplots()
83+
x = rand(3)
84+
y = rand(3)
85+
ax.plot(x, y, 'o', hover={
86+
(x[0], y[0]): "London",
87+
(x[1], y[1]): "Paris",
88+
(x[2], y[2]): "Barcelona"})
89+
plt.show()
90+
7791
# %%
7892
# Hover with a callable transformation function
7993
# ---------------------------------------------
8094
fig, ax = plt.subplots()
81-
plt.ylabel('some numbers')
8295

8396

8497
def user_defined_function(event):

‎lib/matplotlib/artist.py‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,10 +653,18 @@ def set_hover(self, hover):
653653
function which sets the hover message to be displayed.
654654
655655
- A list: If hover is a list of string literals, each string represents
656-
an additional information assigned to each data point. These arbitrary
657-
data labels will appear as a tooltip in the bottom right hand corner
656+
an additional information assigned to each data point. These data labels
657+
will appear as a tooltip in the bottom right hand corner
658658
of the screen when the cursor is detected to be hovering over a data
659-
point that corresponds with one of the data labels.
659+
point that corresponds with the data labels in the same order that
660+
was passed in.
661+
662+
- A dictionary: If hover is a dictionary of key value paris, each key
663+
represents a tuple of x and y coordinate and each value represnets
664+
additional information assigned to each data point. These data labels
665+
will appear as a tooltip in the bottom right hand corner of the
666+
screen when the cursor is detected to be hovering over a data point
667+
that corresponds with one of the data labels.
660668
"""
661669
self._hover = hover
662670

‎lib/matplotlib/artist.pyi‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ class Artist:
8383
hover: None
8484
| bool
8585
| list[str]
86+
| dict[tuple[float, float], str]
8687
| Callable[[Artist, MouseEvent], tuple[bool, dict[Any, Any]]],
8788
) -> None: ...
8889
def get_hover(
8990
self,
90-
) -> None | bool | list[str] | Callable[
91+
) -> None | bool | list[str] | dict[tuple[float, float], str] |Callable[
9192
[Artist, MouseEvent], tuple[bool, dict[Any, Any]]
9293
]: ...
9394
def get_url(self) -> str | None: ...

‎lib/matplotlib/backend_bases.py‎

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,25 +3015,26 @@ def _nonrect(self, x):
30153015
return not isinstance(x, Rectangle)
30163016

30173017
def _tooltip_list(self, event, hover):
3018-
import matplotlib.pyplot as plt
3019-
lines = plt.gca().get_lines()
3020-
num_of_points = 0
3021-
for line in lines:
3022-
num_of_points += 1
3023-
if num_of_points >= len(hover):
3018+
lines = self.canvas.figure.gca().get_lines()[0]
3019+
coor_data = list(zip(lines.get_xdata(), lines.get_ydata()))
3020+
3021+
if len(coor_data) != len(hover):
30243022
raise ValueError("""Number of data points
3025-
does not match up with number of labels""")
3023+
does not match up with number of labels""")
30263024
else:
3027-
mouse_x = event.xdata
3028-
mouse_y = event.ydata
3029-
for line in lines:
3030-
x_data = line.get_xdata()
3031-
y_data = line.get_ydata()
3032-
for i in range(len(x_data)):
3033-
distance = ((event.xdata - x_data[i])**2
3034-
+ (event.ydata - y_data[i])**2)**0.5
3035-
if distance < 0.05:
3036-
return "Data Label: " + hover[i]
3025+
distances = []
3026+
for a in coor_data:
3027+
distances.append(((event.xdata - a[0])**2 +
3028+
(event.ydata - a[1])**2)**0.5)
3029+
if (min(distances) < 0.05):
3030+
return f"Data Label: {hover[distances.index(min(distances))]}"
3031+
3032+
def _tooltip_dict(self, event, hover):
3033+
distances = {}
3034+
for a in hover.keys():
3035+
distances[a] = ((event.xdata - a[0])**2 + (event.ydata - a[1])**2)**0.5
3036+
if (min(distances.values()) < 0.05):
3037+
return f"Data Label: {hover[min(distances, key=distances.get)]}"
30373038

30383039
def mouse_move(self, event):
30393040
self._update_cursor(event)
@@ -3050,6 +3051,8 @@ def mouse_move(self, event):
30503051
self.set_hover_message(hover(event))
30513052
elif type(hover) == list:
30523053
self.set_hover_message(self._tooltip_list(event, hover))
3054+
elif type(hover) == dict:
3055+
self.set_hover_message(self._tooltip_dict(event, hover))
30533056
else:
30543057
self.set_hover_message(self._mouse_event_to_message(event))
30553058
else:

‎lib/matplotlib/backends/_backend_gtk.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ def set_message(self, s):
274274
escaped = GLib.markup_escape_text(s)
275275
self.message.set_markup(f'<small>{escaped}</small>')
276276

277+
def set_hover_message(self, s):
278+
escaped = GLib.markup_escape_text(s)
279+
self.hover_message.set_markup(f'<small>{escaped}</small>')
280+
277281
def draw_rubberband(self, event, x0, y0, x1, y1):
278282
height = self.canvas.figure.bbox.height
279283
y1 = height - y1

‎lib/matplotlib/backends/backend_gtk3.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,11 @@ def __init__(self, toolmanager):
395395
self._message = Gtk.Label()
396396
self._message.set_justify(Gtk.Justification.RIGHT)
397397
self.pack_end(self._message, False, False, 0)
398+
399+
self.hover_message = Gtk.Label()
400+
self.hover_message.set_justify(Gtk.Justification.RIGHT)
401+
self.pack_end(self.hover_message, False, False, 0)
402+
398403
self.show_all()
399404
self._groups = {}
400405
self._toolitems = {}
@@ -465,6 +470,9 @@ def _add_separator(self):
465470
def set_message(self, s):
466471
self._message.set_label(s)
467472

473+
def set_hover_message(self, s):
474+
self._hover_message.set_label(s)
475+
468476

469477
@backend_tools._register_tool_class(FigureCanvasGTK3)
470478
class SaveFigureGTK3(backend_tools.SaveFigureBase):

‎lib/matplotlib/backends/backend_gtk4.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ def __init__(self, canvas):
328328
self.message.set_justify(Gtk.Justification.RIGHT)
329329
self.append(self.message)
330330

331+
self.hover_message = Gtk.Label()
332+
self.hover_message.set_justify(Gtk.Justification.RIGHT)
333+
self.append(self.hover_message)
334+
331335
_NavigationToolbar2GTK.__init__(self, canvas)
332336

333337
def save_figure(self, *args):
@@ -493,6 +497,9 @@ def _add_separator(self):
493497
def set_message(self, s):
494498
self._message.set_label(s)
495499

500+
def set_hover_message(self, s):
501+
self._hover_message.set_label(s)
502+
496503

497504
@backend_tools._register_tool_class(FigureCanvasGTK4)
498505
class SaveFigureGTK4(backend_tools.SaveFigureBase):

‎lib/matplotlib/backends/backend_qt.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,9 +677,19 @@ def __init__(self, canvas, parent=None, coordinates=True):
677677
_enum("QtWidgets.QSizePolicy.Policy").Expanding,
678678
_enum("QtWidgets.QSizePolicy.Policy").Ignored,
679679
))
680+
self.hover_message = QtWidgets.QLabel("", self)
681+
self.hover_message.setAlignment(QtCore.Qt.AlignmentFlag(
682+
_to_int(_enum("QtCore.Qt.AlignmentFlag").AlignRight) |
683+
_to_int(_enum("QtCore.Qt.AlignmentFlag").AlignVCenter)))
684+
self.hover_message.setSizePolicy(QtWidgets.QSizePolicy(
685+
_enum("QtWidgets.QSizePolicy.Policy").Expanding,
686+
_enum("QtWidgets.QSizePolicy.Policy").Ignored,
687+
))
688+
labelActionHover = self.addWidget(self.hover_message)
689+
labelActionHover.setVisible(True)
690+
680691
labelAction = self.addWidget(self.locLabel)
681692
labelAction.setVisible(True)
682-
683693
NavigationToolbar2.__init__(self, canvas)
684694

685695
def _icon(self, name):
@@ -756,6 +766,11 @@ def set_message(self, s):
756766
if self.coordinates:
757767
self.locLabel.setText(s)
758768

769+
def set_hover_message(self, s):
770+
self.message.emit(s)
771+
if self.coordinates:
772+
self.hover_message.setText(s)
773+
759774
def draw_rubberband(self, event, x0, y0, x1, y1):
760775
height = self.canvas.figure.bbox.height
761776
y1 = height - y1

‎lib/matplotlib/backends/backend_wx.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,8 @@ def __init__(self, canvas, coordinates=True, *, style=wx.TB_BOTTOM):
10511051
self.AddStretchableSpace()
10521052
self._label_text = wx.StaticText(self, style=wx.ALIGN_RIGHT)
10531053
self.AddControl(self._label_text)
1054+
self._hover_message = wx.StaticText(self, style=wx.ALIGN_LEFT)
1055+
self.AddControl(self._hover_message)
10541056

10551057
self.Realize()
10561058

@@ -1143,6 +1145,10 @@ def set_message(self, s):
11431145
if self._coordinates:
11441146
self._label_text.SetLabel(s)
11451147

1148+
def set_hover_message(self, s):
1149+
if self._coordinates:
1150+
self._hover_message.SetLabel(s)
1151+
11461152
def set_history_buttons(self):
11471153
can_backward = self._nav_stack._pos > 0
11481154
can_forward = self._nav_stack._pos < len(self._nav_stack._elements) - 1
@@ -1163,6 +1169,10 @@ def __init__(self, toolmanager, parent=None, style=wx.TB_BOTTOM):
11631169
self._space = self.AddStretchableSpace()
11641170
self._label_text = wx.StaticText(self, style=wx.ALIGN_RIGHT)
11651171
self.AddControl(self._label_text)
1172+
1173+
self._hover_message = wx.StaticText(self, style=wx.ALIGN_LEFT)
1174+
self.AddControl(self._hover_message)
1175+
11661176
self._toolitems = {}
11671177
self._groups = {} # Mapping of groups to the separator after them.
11681178

@@ -1240,6 +1250,9 @@ def remove_toolitem(self, name):
12401250
def set_message(self, s):
12411251
self._label_text.SetLabel(s)
12421252

1253+
def set_hover_message(self, s):
1254+
self._hover_message.SetLabel(s)
1255+
12431256

12441257
@backend_tools._register_tool_class(_FigureCanvasWxBase)
12451258
class ConfigureSubplotsWx(backend_tools.ConfigureSubplotsBase):

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /