diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 80d35ec8c42b..b1d18df74494 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1537,22 +1537,19 @@ def __init__(self, name, canvas, x, y, guiEvent=None): else: axes_list = [self.canvas.mouse_grabber] - if axes_list: # Use highest zorder. - self.inaxes = max(axes_list, key=lambda x: x.zorder) - else: # None found. - self.inaxes = None - self._update_enter_leave() - return - - try: - trans = self.inaxes.transData.inverted() - xdata, ydata = trans.transform_point((x, y)) - except ValueError: - self.xdata = None - self.ydata = None + if axes_list: + self.inaxes = cbook._topmost_artist(axes_list) + try: + trans = self.inaxes.transData.inverted() + xdata, ydata = trans.transform_point((x, y)) + except ValueError: + self.xdata = None + self.ydata = None + else: + self.xdata = xdata + self.ydata = ydata else: - self.xdata = xdata - self.ydata = ydata + self.inaxes = None self._update_enter_leave() @@ -1815,7 +1812,7 @@ def onRemove(self, ev): canvas.mpl_connect('mouse_press_event',canvas.onRemove) """ # Find the top artist under the cursor - under = sorted(self.figure.hitlist(ev), key=lambda x: x.zorder) + under = cbook._topmost_artist(self.figure.hitlist(ev)) h = None if under: h = under[-1] @@ -2899,7 +2896,7 @@ def mouse_move(self, event): if a.contains(event) and a.get_visible()] if artists: - a = max(artists, key=lambda x: x.zorder) + a = cbook._topmost_artist(artists) if a is not event.inaxes.patch: data = a.get_cursor_data(event) if data is not None: diff --git a/lib/matplotlib/backend_tools.py b/lib/matplotlib/backend_tools.py index 553f3b62c5b0..415fe8442b47 100644 --- a/lib/matplotlib/backend_tools.py +++ b/lib/matplotlib/backend_tools.py @@ -340,7 +340,7 @@ def send_message(self, event): if a.contains(event) and a.get_visible()] if artists: - a = max(artists, key=lambda x: x.zorder) + a = cbook._topmost_artist(artists) if a is not event.inaxes.patch: data = a.get_cursor_data(event) if data is not None: diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index bf33e5fe65cc..0fc3052f783f 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -21,6 +21,7 @@ from itertools import repeat import locale import numbers +import operator import os import re import sys @@ -2752,3 +2753,16 @@ def _get_key_params(self): (params, str_func)) return str_func, params + + +def _topmost_artist( + artists, + _cached_max=functools.partial(max, key=operator.attrgetter("zorder"))): + """Get the topmost artist of a list. + + In case of a tie, return the *last* of the tied artists, as it will be + drawn on top of the others. `max` returns the first maximum in case of ties + (on Py2 this is undocumented but true), so we need to iterate over the list + in reverse order. + """ + return _cached_max(reversed(artists))