|
| 1 | +""" |
| 2 | +=============== |
| 3 | +Pick event demo |
| 4 | +=============== |
| 5 | +
|
| 6 | +You can enable picking by setting the "picker" property of an artist |
| 7 | +(for example, a Matplotlib Line2D, Text, Patch, Polygon, AxesImage, |
| 8 | +etc.) |
| 9 | +
|
| 10 | +There are a variety of meanings of the picker property: |
| 11 | +
|
| 12 | +* *None* - picking is disabled for this artist (default) |
| 13 | +
|
| 14 | +* bool - if *True* then picking will be enabled and the artist will fire a pick |
| 15 | + event if the mouse event is over the artist. |
| 16 | +
|
| 17 | + Setting ``pickradius`` will add an epsilon tolerance in points and the artist |
| 18 | + will fire off an event if its data is within epsilon of the mouse event. For |
| 19 | + some artists like lines and patch collections, the artist may provide |
| 20 | + additional data to the pick event that is generated, for example, the indices |
| 21 | + of the data within epsilon of the pick event |
| 22 | +
|
| 23 | +* function - if picker is callable, it is a user supplied function which |
| 24 | + determines whether the artist is hit by the mouse event. :: |
| 25 | +
|
| 26 | + hit, props = picker(artist, mouseevent) |
| 27 | +
|
| 28 | + to determine the hit test. If the mouse event is over the artist, return |
| 29 | + hit=True and props is a dictionary of properties you want added to the |
| 30 | + PickEvent attributes. |
| 31 | +
|
| 32 | +After you have enabled an artist for picking by setting the "picker" |
| 33 | +property, you need to connect to the figure canvas pick_event to get |
| 34 | +pick callbacks on mouse press events. For example, :: |
| 35 | +
|
| 36 | + def pick_handler(event): |
| 37 | + mouseevent = event.mouseevent |
| 38 | + artist = event.artist |
| 39 | + # now do something with this... |
| 40 | +
|
| 41 | +
|
| 42 | +The pick event (matplotlib.backend_bases.PickEvent) which is passed to |
| 43 | +your callback is always fired with two attributes: |
| 44 | +
|
| 45 | +mouseevent |
| 46 | + the mouse event that generate the pick event. |
| 47 | +
|
| 48 | + The mouse event in turn has attributes like x and y (the coordinates in |
| 49 | + display space, such as pixels from left, bottom) and xdata, ydata (the |
| 50 | + coords in data space). Additionally, you can get information about |
| 51 | + which buttons were pressed, which keys were pressed, which Axes |
| 52 | + the mouse is over, etc. See matplotlib.backend_bases.MouseEvent |
| 53 | + for details. |
| 54 | +
|
| 55 | +artist |
| 56 | + the matplotlib.artist that generated the pick event. |
| 57 | +
|
| 58 | +Additionally, certain artists like Line2D and PatchCollection may |
| 59 | +attach additional metadata like the indices into the data that meet |
| 60 | +the picker criteria (for example, all the points in the line that are within |
| 61 | +the specified epsilon tolerance) |
| 62 | +
|
| 63 | +The examples below illustrate each of these methods. |
| 64 | +
|
| 65 | +.. note:: |
| 66 | + These examples exercises the interactive capabilities of Matplotlib, and |
| 67 | + this will not appear in the static documentation. Please run this code on |
| 68 | + your machine to see the interactivity. |
| 69 | +
|
| 70 | + You can copy and paste individual parts, or download the entire example |
| 71 | + using the link at the bottom of the page. |
| 72 | +""" |
| 73 | + |
| 74 | +import matplotlib.pyplot as plt |
| 75 | +import numpy as np |
| 76 | +from numpy.random import rand |
| 77 | + |
| 78 | +from matplotlib.image import AxesImage |
| 79 | +from matplotlib.lines import Line2D |
| 80 | +from matplotlib.patches import Rectangle |
| 81 | +from matplotlib.text import Text |
| 82 | + |
| 83 | +# Fixing random state for reproducibility |
| 84 | +np.random.seed(19680801) |
| 85 | + |
| 86 | + |
| 87 | +# %% |
| 88 | +# Simple picking, lines, rectangles and text |
| 89 | +# ------------------------------------------ |
| 90 | + |
| 91 | +fig, (ax1, ax2) = plt.subplots(2, 1) |
| 92 | +ax1.set_title('click on points, rectangles or text', picker=True) |
| 93 | +ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red')) |
| 94 | +line, = ax1.plot(rand(100), 'o', picker=True, pickradius=5) |
| 95 | + |
| 96 | +# Pick the rectangle. |
| 97 | +ax2.bar(range(10), rand(10), picker=True) |
| 98 | +for label in ax2.get_xticklabels(): # Make the xtick labels pickable. |
| 99 | + label.set_picker(True) |
| 100 | + |
| 101 | + |
| 102 | +def onpick1(event): |
| 103 | + if isinstance(event.artist, Line2D): |
| 104 | + thisline = event.artist |
| 105 | + xdata = thisline.get_xdata() |
| 106 | + ydata = thisline.get_ydata() |
| 107 | + ind = event.ind |
| 108 | + print('onpick1 line:', np.column_stack([xdata[ind], ydata[ind]])) |
| 109 | + elif isinstance(event.artist, Rectangle): |
| 110 | + patch = event.artist |
| 111 | + print('onpick1 patch:', patch.get_path()) |
| 112 | + elif isinstance(event.artist, Text): |
| 113 | + text = event.artist |
| 114 | + print('onpick1 text:', text.get_text()) |
| 115 | + |
| 116 | + |
| 117 | +fig.canvas.mpl_connect('pick_event', onpick1) |
| 118 | + |
| 119 | + |
| 120 | +# %% |
| 121 | +# Picking with a custom hit test function |
| 122 | +# --------------------------------------- |
| 123 | +# You can define custom pickers by setting picker to a callable function. The |
| 124 | +# function has the signature:: |
| 125 | +# |
| 126 | +# hit, props = func(artist, mouseevent) |
| 127 | +# |
| 128 | +# to determine the hit test. If the mouse event is over the artist, return |
| 129 | +# ``hit=True`` and ``props`` is a dictionary of properties you want added to |
| 130 | +# the `.PickEvent` attributes. |
| 131 | + |
| 132 | +def line_picker(line, mouseevent): |
| 133 | + """ |
| 134 | + Find the points within a certain distance from the mouseclick in |
| 135 | + data coords and attach some extra attributes, pickx and picky |
| 136 | + which are the data points that were picked. |
| 137 | + """ |
| 138 | + if mouseevent.xdata is None: |
| 139 | + return False, dict() |
| 140 | + xdata = line.get_xdata() |
| 141 | + ydata = line.get_ydata() |
| 142 | + maxd = 0.05 |
| 143 | + d = np.sqrt( |
| 144 | + (xdata - mouseevent.xdata)**2 + (ydata - mouseevent.ydata)**2) |
| 145 | + |
| 146 | + ind, = np.nonzero(d <= maxd) |
| 147 | + if len(ind): |
| 148 | + pickx = xdata[ind] |
| 149 | + picky = ydata[ind] |
| 150 | + props = dict(ind=ind, pickx=pickx, picky=picky) |
| 151 | + return True, props |
| 152 | + else: |
| 153 | + return False, dict() |
| 154 | + |
| 155 | + |
| 156 | +def onpick2(event): |
| 157 | + print('onpick2 line:', event.pickx, event.picky) |
| 158 | + |
| 159 | + |
| 160 | +fig, ax = plt.subplots() |
| 161 | +ax.set_title('custom picker for line data') |
| 162 | +line, = ax.plot(rand(100), rand(100), 'o', picker=line_picker) |
| 163 | +fig.canvas.mpl_connect('pick_event', onpick2) |
| 164 | + |
| 165 | + |
| 166 | +# %% |
| 167 | +# Picking on a scatter plot |
| 168 | +# ------------------------- |
| 169 | +# A scatter plot is backed by a `~matplotlib.collections.PathCollection`. |
| 170 | + |
| 171 | +x, y, c, s = rand(4, 100) |
| 172 | + |
| 173 | + |
| 174 | +def onpick3(event): |
| 175 | + ind = event.ind |
| 176 | + print('onpick3 scatter:', ind, x[ind], y[ind]) |
| 177 | + |
| 178 | + |
| 179 | +fig, ax = plt.subplots() |
| 180 | +ax.scatter(x, y, 100*s, c, picker=True) |
| 181 | +fig.canvas.mpl_connect('pick_event', onpick3) |
| 182 | + |
| 183 | + |
| 184 | +# %% |
| 185 | +# Picking images |
| 186 | +# -------------- |
| 187 | +# Images plotted using `.Axes.imshow` are `~matplotlib.image.AxesImage` |
| 188 | +# objects. |
| 189 | + |
| 190 | +fig, ax = plt.subplots() |
| 191 | +ax.imshow(rand(10, 5), extent=(1, 2, 1, 2), picker=True) |
| 192 | +ax.imshow(rand(5, 10), extent=(3, 4, 1, 2), picker=True) |
| 193 | +ax.imshow(rand(20, 25), extent=(1, 2, 3, 4), picker=True) |
| 194 | +ax.imshow(rand(30, 12), extent=(3, 4, 3, 4), picker=True) |
| 195 | +ax.set(xlim=(0, 5), ylim=(0, 5)) |
| 196 | + |
| 197 | + |
| 198 | +def onpick4(event): |
| 199 | + artist = event.artist |
| 200 | + if isinstance(artist, AxesImage): |
| 201 | + im = artist |
| 202 | + A = im.get_array() |
| 203 | + print('onpick4 image', A.shape) |
| 204 | + |
| 205 | + |
| 206 | +fig.canvas.mpl_connect('pick_event', onpick4) |
| 207 | + |
| 208 | +plt.show() |
0 commit comments