From 2c859ee68b37e3df1dfea123dcb81a231d16f08c Mon Sep 17 00:00:00 2001 From: pm3512 Date: Sun, 7 May 2023 23:08:04 -0400 Subject: [PATCH 1/2] created demo file --- .../event_handling/hover_event_demo.py | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 galleries/examples/event_handling/hover_event_demo.py diff --git a/galleries/examples/event_handling/hover_event_demo.py b/galleries/examples/event_handling/hover_event_demo.py new file mode 100644 index 000000000000..163aaf923d77 --- /dev/null +++ b/galleries/examples/event_handling/hover_event_demo.py @@ -0,0 +1,208 @@ +""" +=============== +Pick event demo +=============== + +You can enable picking by setting the "picker" property of an artist +(for example, a Matplotlib Line2D, Text, Patch, Polygon, AxesImage, +etc.) + +There are a variety of meanings of the picker property: + +* *None* - picking is disabled for this artist (default) + +* bool - if *True* then picking will be enabled and the artist will fire a pick + event if the mouse event is over the artist. + + Setting ``pickradius`` will add an epsilon tolerance in points and the artist + will fire off an event if its data is within epsilon of the mouse event. For + some artists like lines and patch collections, the artist may provide + additional data to the pick event that is generated, for example, the indices + of the data within epsilon of the pick event + +* function - if picker is callable, it is a user supplied function which + determines whether the artist is hit by the mouse event. :: + + hit, props = picker(artist, mouseevent) + + to determine the hit test. If the mouse event is over the artist, return + hit=True and props is a dictionary of properties you want added to the + PickEvent attributes. + +After you have enabled an artist for picking by setting the "picker" +property, you need to connect to the figure canvas pick_event to get +pick callbacks on mouse press events. For example, :: + + def pick_handler(event): + mouseevent = event.mouseevent + artist = event.artist + # now do something with this... + + +The pick event (matplotlib.backend_bases.PickEvent) which is passed to +your callback is always fired with two attributes: + +mouseevent + the mouse event that generate the pick event. + + The mouse event in turn has attributes like x and y (the coordinates in + display space, such as pixels from left, bottom) and xdata, ydata (the + coords in data space). Additionally, you can get information about + which buttons were pressed, which keys were pressed, which Axes + the mouse is over, etc. See matplotlib.backend_bases.MouseEvent + for details. + +artist + the matplotlib.artist that generated the pick event. + +Additionally, certain artists like Line2D and PatchCollection may +attach additional metadata like the indices into the data that meet +the picker criteria (for example, all the points in the line that are within +the specified epsilon tolerance) + +The examples below illustrate each of these methods. + +.. note:: + These examples exercises the interactive capabilities of Matplotlib, and + this will not appear in the static documentation. Please run this code on + your machine to see the interactivity. + + You can copy and paste individual parts, or download the entire example + using the link at the bottom of the page. +""" + +import matplotlib.pyplot as plt +import numpy as np +from numpy.random import rand + +from matplotlib.image import AxesImage +from matplotlib.lines import Line2D +from matplotlib.patches import Rectangle +from matplotlib.text import Text + +# Fixing random state for reproducibility +np.random.seed(19680801) + + +# %% +# Simple picking, lines, rectangles and text +# ------------------------------------------ + +fig, (ax1, ax2) = plt.subplots(2, 1) +ax1.set_title('click on points, rectangles or text', picker=True) +ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red')) +line, = ax1.plot(rand(100), 'o', picker=True, pickradius=5) + +# Pick the rectangle. +ax2.bar(range(10), rand(10), picker=True) +for label in ax2.get_xticklabels(): # Make the xtick labels pickable. + label.set_picker(True) + + +def onpick1(event): + if isinstance(event.artist, Line2D): + thisline = event.artist + xdata = thisline.get_xdata() + ydata = thisline.get_ydata() + ind = event.ind + print('onpick1 line:', np.column_stack([xdata[ind], ydata[ind]])) + elif isinstance(event.artist, Rectangle): + patch = event.artist + print('onpick1 patch:', patch.get_path()) + elif isinstance(event.artist, Text): + text = event.artist + print('onpick1 text:', text.get_text()) + + +fig.canvas.mpl_connect('pick_event', onpick1) + + +# %% +# Picking with a custom hit test function +# --------------------------------------- +# You can define custom pickers by setting picker to a callable function. The +# function has the signature:: +# +# hit, props = func(artist, mouseevent) +# +# to determine the hit test. If the mouse event is over the artist, return +# ``hit=True`` and ``props`` is a dictionary of properties you want added to +# the `.PickEvent` attributes. + +def line_picker(line, mouseevent): + """ + Find the points within a certain distance from the mouseclick in + data coords and attach some extra attributes, pickx and picky + which are the data points that were picked. + """ + if mouseevent.xdata is None: + return False, dict() + xdata = line.get_xdata() + ydata = line.get_ydata() + maxd = 0.05 + d = np.sqrt( + (xdata - mouseevent.xdata)**2 + (ydata - mouseevent.ydata)**2) + + ind, = np.nonzero(d <= maxd) + if len(ind): + pickx = xdata[ind] + picky = ydata[ind] + props = dict(ind=ind, pickx=pickx, picky=picky) + return True, props + else: + return False, dict() + + +def onpick2(event): + print('onpick2 line:', event.pickx, event.picky) + + +fig, ax = plt.subplots() +ax.set_title('custom picker for line data') +line, = ax.plot(rand(100), rand(100), 'o', picker=line_picker) +fig.canvas.mpl_connect('pick_event', onpick2) + + +# %% +# Picking on a scatter plot +# ------------------------- +# A scatter plot is backed by a `~matplotlib.collections.PathCollection`. + +x, y, c, s = rand(4, 100) + + +def onpick3(event): + ind = event.ind + print('onpick3 scatter:', ind, x[ind], y[ind]) + + +fig, ax = plt.subplots() +ax.scatter(x, y, 100*s, c, picker=True) +fig.canvas.mpl_connect('pick_event', onpick3) + + +# %% +# Picking images +# -------------- +# Images plotted using `.Axes.imshow` are `~matplotlib.image.AxesImage` +# objects. + +fig, ax = plt.subplots() +ax.imshow(rand(10, 5), extent=(1, 2, 1, 2), picker=True) +ax.imshow(rand(5, 10), extent=(3, 4, 1, 2), picker=True) +ax.imshow(rand(20, 25), extent=(1, 2, 3, 4), picker=True) +ax.imshow(rand(30, 12), extent=(3, 4, 3, 4), picker=True) +ax.set(xlim=(0, 5), ylim=(0, 5)) + + +def onpick4(event): + artist = event.artist + if isinstance(artist, AxesImage): + im = artist + A = im.get_array() + print('onpick4 image', A.shape) + + +fig.canvas.mpl_connect('pick_event', onpick4) + +plt.show() From d84037d36327f2d52fdb8b50c866b0bf507f48d1 Mon Sep 17 00:00:00 2001 From: pm3512 Date: Mon, 8 May 2023 08:28:54 -0400 Subject: [PATCH 2/2] wrote docs --- .../event_handling/hover_event_demo.py | 198 ++++-------------- 1 file changed, 39 insertions(+), 159 deletions(-) diff --git a/galleries/examples/event_handling/hover_event_demo.py b/galleries/examples/event_handling/hover_event_demo.py index 163aaf923d77..5460a9913fe8 100644 --- a/galleries/examples/event_handling/hover_event_demo.py +++ b/galleries/examples/event_handling/hover_event_demo.py @@ -1,49 +1,43 @@ """ -=============== -Pick event demo -=============== +================ +Hover event demo +================ -You can enable picking by setting the "picker" property of an artist -(for example, a Matplotlib Line2D, Text, Patch, Polygon, AxesImage, -etc.) - -There are a variety of meanings of the picker property: - -* *None* - picking is disabled for this artist (default) +.. note:: + Data tooltips are currently only supported for the TkAgg backend. -* bool - if *True* then picking will be enabled and the artist will fire a pick - event if the mouse event is over the artist. +You can enable hovering by setting the "hover" property of an artist. +Hovering adds a tooltip to the bottom right corner +of the figure canvas, which is displayed when the mouse pointer hovers over the +artist. - Setting ``pickradius`` will add an epsilon tolerance in points and the artist - will fire off an event if its data is within epsilon of the mouse event. For - some artists like lines and patch collections, the artist may provide - additional data to the pick event that is generated, for example, the indices - of the data within epsilon of the pick event +The hover behavior depends on the type of the argument passed to the +``set_hover`` method: -* function - if picker is callable, it is a user supplied function which - determines whether the artist is hit by the mouse event. :: +* *None* - hovering is disabled for this artist (default) - hit, props = picker(artist, mouseevent) +* list of string literals - hovering is enabled, and hovering over a point + displays the corresponding string literal. - to determine the hit test. If the mouse event is over the artist, return - hit=True and props is a dictionary of properties you want added to the - PickEvent attributes. +* function - if hover is callable, it is a user supplied function which + takes a ``mouseevent`` object (see below), and returns a tuple of transformed + coordinates -After you have enabled an artist for picking by setting the "picker" -property, you need to connect to the figure canvas pick_event to get -pick callbacks on mouse press events. For example, :: +After you have enabled an artist for picking by setting the "hover" +property, you need to connect to the figure canvas hover_event to get +hover callbacks on mouse over events. For example, :: - def pick_handler(event): + def hover_handler(event): mouseevent = event.mouseevent artist = event.artist # now do something with this... -The pick event (matplotlib.backend_bases.PickEvent) which is passed to +The hover event (matplotlib.backend_bases.HoverEvent) which is passed to your callback is always fired with two attributes: mouseevent - the mouse event that generate the pick event. + the mouse event that generate the hover event. The mouse event in turn has attributes like x and y (the coordinates in display space, such as pixels from left, bottom) and xdata, ydata (the @@ -53,14 +47,12 @@ def pick_handler(event): for details. artist - the matplotlib.artist that generated the pick event. + the matplotlib.artist that generated the hover event. -Additionally, certain artists like Line2D and PatchCollection may -attach additional metadata like the indices into the data that meet -the picker criteria (for example, all the points in the line that are within -the specified epsilon tolerance) +You can set the ``hover`` property of an artist by supplying a ``hover`` +argument to ``Axes.plot()`` -The examples below illustrate each of these methods. +The examples below illustrate the different ways to use the ``hover`` property. .. note:: These examples exercises the interactive capabilities of Matplotlib, and @@ -70,139 +62,27 @@ def pick_handler(event): You can copy and paste individual parts, or download the entire example using the link at the bottom of the page. """ - +# %% +# Hover with string literal labels +# -------------------------------- import matplotlib.pyplot as plt -import numpy as np from numpy.random import rand -from matplotlib.image import AxesImage -from matplotlib.lines import Line2D -from matplotlib.patches import Rectangle -from matplotlib.text import Text - -# Fixing random state for reproducibility -np.random.seed(19680801) - - -# %% -# Simple picking, lines, rectangles and text -# ------------------------------------------ - -fig, (ax1, ax2) = plt.subplots(2, 1) -ax1.set_title('click on points, rectangles or text', picker=True) -ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red')) -line, = ax1.plot(rand(100), 'o', picker=True, pickradius=5) - -# Pick the rectangle. -ax2.bar(range(10), rand(10), picker=True) -for label in ax2.get_xticklabels(): # Make the xtick labels pickable. - label.set_picker(True) - - -def onpick1(event): - if isinstance(event.artist, Line2D): - thisline = event.artist - xdata = thisline.get_xdata() - ydata = thisline.get_ydata() - ind = event.ind - print('onpick1 line:', np.column_stack([xdata[ind], ydata[ind]])) - elif isinstance(event.artist, Rectangle): - patch = event.artist - print('onpick1 patch:', patch.get_path()) - elif isinstance(event.artist, Text): - text = event.artist - print('onpick1 text:', text.get_text()) - - -fig.canvas.mpl_connect('pick_event', onpick1) - - -# %% -# Picking with a custom hit test function -# --------------------------------------- -# You can define custom pickers by setting picker to a callable function. The -# function has the signature:: -# -# hit, props = func(artist, mouseevent) -# -# to determine the hit test. If the mouse event is over the artist, return -# ``hit=True`` and ``props`` is a dictionary of properties you want added to -# the `.PickEvent` attributes. - -def line_picker(line, mouseevent): - """ - Find the points within a certain distance from the mouseclick in - data coords and attach some extra attributes, pickx and picky - which are the data points that were picked. - """ - if mouseevent.xdata is None: - return False, dict() - xdata = line.get_xdata() - ydata = line.get_ydata() - maxd = 0.05 - d = np.sqrt( - (xdata - mouseevent.xdata)**2 + (ydata - mouseevent.ydata)**2) - - ind, = np.nonzero(d <= maxd) - if len(ind): - pickx = xdata[ind] - picky = ydata[ind] - props = dict(ind=ind, pickx=pickx, picky=picky) - return True, props - else: - return False, dict() - - -def onpick2(event): - print('onpick2 line:', event.pickx, event.picky) - - -fig, ax = plt.subplots() -ax.set_title('custom picker for line data') -line, = ax.plot(rand(100), rand(100), 'o', picker=line_picker) -fig.canvas.mpl_connect('pick_event', onpick2) - - -# %% -# Picking on a scatter plot -# ------------------------- -# A scatter plot is backed by a `~matplotlib.collections.PathCollection`. - -x, y, c, s = rand(4, 100) - - -def onpick3(event): - ind = event.ind - print('onpick3 scatter:', ind, x[ind], y[ind]) - - fig, ax = plt.subplots() -ax.scatter(x, y, 100*s, c, picker=True) -fig.canvas.mpl_connect('pick_event', onpick3) +plt.ylabel('some numbers') +ax.plot(rand(3), 'o', hover=['London', 'Paris', 'Barcelona']) +plt.show() # %% -# Picking images -# -------------- -# Images plotted using `.Axes.imshow` are `~matplotlib.image.AxesImage` -# objects. - +# Hover with a callable transformation function +# --------------------------------------------- fig, ax = plt.subplots() -ax.imshow(rand(10, 5), extent=(1, 2, 1, 2), picker=True) -ax.imshow(rand(5, 10), extent=(3, 4, 1, 2), picker=True) -ax.imshow(rand(20, 25), extent=(1, 2, 3, 4), picker=True) -ax.imshow(rand(30, 12), extent=(3, 4, 3, 4), picker=True) -ax.set(xlim=(0, 5), ylim=(0, 5)) - - -def onpick4(event): - artist = event.artist - if isinstance(artist, AxesImage): - im = artist - A = im.get_array() - print('onpick4 image', A.shape) +plt.ylabel('some numbers') -fig.canvas.mpl_connect('pick_event', onpick4) +def user_defined_function(event): + return round(event.xdata * 10, 1), round(event.ydata + 3, 3) +ax.plot(rand(100), 'o', hover=user_defined_function) plt.show()