From 88ee8e3b47c6ab0a9f520958c136022346fd4932 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 31 Jul 2015 22:38:31 -0400 Subject: [PATCH] ENH: make mouse over behavior configurable The mouse-over behavior to add a string to the message line can quickly become too expensive to compute the hit list in the time between mouse move events (particularly in the nbagg and qt5agg backends) when the number of artists gets large. This adds: - a flag on the Axes objects to control if the hitlist should be computed - an rcparam to control it --- .../whats_new/2015-01-19_cursor_pixel_data.rst | 18 +++++++++++++++++- lib/matplotlib/axes/_base.py | 5 +++++ lib/matplotlib/backend_bases.py | 5 ++++- lib/matplotlib/rcsetup.py | 4 ++-- matplotlibrc.template | 9 ++++++--- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/doc/users/whats_new/2015-01-19_cursor_pixel_data.rst b/doc/users/whats_new/2015-01-19_cursor_pixel_data.rst index 4490e9df35e4..b7339389dee9 100644 --- a/doc/users/whats_new/2015-01-19_cursor_pixel_data.rst +++ b/doc/users/whats_new/2015-01-19_cursor_pixel_data.rst @@ -1,6 +1,22 @@ Allow Artists to Display Pixel Data in Cursor --------------------------------------------- -Adds `get_pixel_data` and `format_pixel_data` methods to artists +Adds `get_cursor_data` and `format_cursor_data` methods to artists which can be used to add zdata to the cursor display in the status bar. Also adds an implementation for Images. + +Added an property attribute ``mouseover`` and rcParam +(``axes.mouseover``) to Axes objects to control if the hit list is +computed. For moderate number of artists (>100) in the axes the +expense to compute the top artist becomes greater than the time +between mouse events. For this reason the behavior defaults to +``False``, but maybe enabled by default in the future when the hitlist +computation is optimized. + +To enable the cursor message on a given axes :: + + ax.mouseover = True + +To enable for all new axes created :: + + matplotlib.rcParams['axes.mouseover'] = True diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 0b3f8b20a738..913f1b57473e 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -390,6 +390,8 @@ def __init__(self, fig, rect, *yscale* [%(scale)s] *yticklabels* sequence of strings *yticks* sequence of floats + *mouseover* [ *True* | *False*] if mouseover artists + adds to message string in the gui window ================ ========================================= """ % {'scale': ' | '.join( [repr(x) for x in mscale.get_scale_names()])} @@ -406,6 +408,7 @@ def __init__(self, fig, rect, self.set_anchor('C') self._sharex = sharex self._sharey = sharey + if sharex is not None: self._shared_x_axes.join(self, sharex) if sharex._adjustable == 'box': @@ -467,6 +470,8 @@ def __init__(self, fig, rect, self._ycid = self.yaxis.callbacks.connect('units finalize', self.relim) + self.mouseover = kwargs.pop('mouseover', rcParams['axes.mouseover']) + def __setstate__(self, state): self.__dict__ = state # put the _remove_method back on all artists contained within the axes diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index d0b59e5b7524..f61b1f35feaf 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2812,7 +2812,10 @@ def mouse_move(self, event): except (ValueError, OverflowError): pass else: - artists = event.inaxes.hitlist(event) + if event.inaxes.mouseover: + artists = event.inaxes.hitlist(event) + else: + artists = [] if artists: a = max(enumerate(artists), key=lambda x: x[1].zorder)[1] diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index a54463b1b49c..03b9a2feefae 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -756,7 +756,7 @@ def __call__(self, s): 'axes.ymargin': [0, ValidateInterval(0, 1, closedmin=True, closedmax=True)],# margin added to yaxis - + 'axes.mouseover': [False, validate_bool], # find top most artist and ask it for a message 'polaraxes.grid': [True, validate_bool], # display polar grid or # not 'axes3d.grid': [True, validate_bool], # display 3d grid @@ -812,7 +812,7 @@ def __call__(self, s): 'xtick.minor.pad': [4, validate_float], # distance to label in points 'xtick.color': ['k', validate_color], # color of the xtick labels 'xtick.minor.visible': [False, validate_bool], # visiablility of the x axis minor ticks - + # fontsize of the xtick labels 'xtick.labelsize': ['medium', validate_fontsize], 'xtick.direction': ['in', six.text_type], # direction of xticks diff --git a/matplotlibrc.template b/matplotlibrc.template index 968c32802005..e159e42068c7 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -273,6 +273,9 @@ backend : %(backend)s # web-style hex #axes.xmargin : 0 # x margin. See `axes.Axes.margins` #axes.ymargin : 0 # y margin See `axes.Axes.margins` +#axes.mouseover : False # if mouse motion should try to find the + # top artist and append a message from that + # artist to the gui message box #polaraxes.grid : True # display grid on polar axes #axes3d.grid : True # display grid on 3d axes @@ -356,9 +359,9 @@ backend : %(backend)s #image.lut : 256 # the size of the colormap lookup table #image.origin : upper # lower | upper #image.resample : False -#image.composite_image : True # When True, all the images on a set of axes are - # combined into a single composite image before - # saving a figure as a vector graphics file, +#image.composite_image : True # When True, all the images on a set of axes are + # combined into a single composite image before + # saving a figure as a vector graphics file, # such as a PDF. ### CONTOUR PLOTS