<h3 dir="auto">Bug report</h3>
<p dir="auto">Pick events are fired twice instead of once following <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="549605493" data-permission-text="Title is private" data-url="https://github.com/matplotlib/matplotlib/issues/16220" data-hovercard-type="pull_request" data-hovercard-url="/matplotlib/matplotlib/pull/16220/hovercard" href="https://github.com/matplotlib/matplotlib/pull/16220">#16220</a>. This example is a bit wacky, but it's the minimal version of a <a href="https://mne.tools/dev/auto_tutorials/raw/plot_30_annotate_raw.html#operations-on-annotations-objects" rel="nofollow">much more complete GUI</a>:</p>
<details>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# -*- coding: utf-8 -*-

import numpy as np
from matplotlib.figure import Figure
from matplotlib.text import Text
import matplotlib  # noqa
from matplotlib.pyplot import figure
from matplotlib.widgets import Button
from mpl_toolkits.axes_grid1.axes_size import Fixed
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
# matplotlib.use('Agg', force=True)


class Figure1(Figure):
    &quot;&quot;&quot;Interactive figure with scrollbars, for data browsing.&quot;&quot;&quot;

    def __init__(self, yticks, **kwargs):
        super().__init__(figsize=(6, 6))
        ax_main = self.add_subplot(1, 1, 1, position=[0.1, 0.1, 0.9, 0.9])
        div = make_axes_locatable(ax_main)
        ax_button = div.append_axes(position='bottom', size=Fixed(0.5), pad=0)
        self._button = Button(ax_button, 'Help')

        # main plot
        offsets = np.arange(len(yticks))
        ax_main.set(xlim=[0, 1], yticks=offsets)
        ax_main.set_yticklabels(yticks, picker=True)
        ax_main.plot([0, 1], [offsets, offsets])


picked = list()


def on_pick(event):
    &quot;&quot;&quot;Handle matplotlib pick events.&quot;&quot;&quot;
    if isinstance(event.artist, Text):
        ch_name = event.artist.get_text()
        print(f'pick {ch_name}')
        picked.append(ch_name)


yticks = list(x * 5 for x in 'ABCD')
fig = figure(FigureClass=Figure1, yticks=yticks)
fig.canvas.mpl_connect('pick_event', on_pick)
fig.canvas.draw()


ax = fig.axes[0]
x, y = ax.transData.transform_point((-0.1, 0))
func = fig.canvas.button_press_event(x=x, y=y, button=1, guiEvent=None)
assert 'AAAAA' in picked
assert len(picked) == 1, len(picked)"><pre class="notranslate"><span class="pl-c"># -*- coding: utf-8 -*-</span>

<span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">figure</span> <span class="pl-k">import</span> <span class="pl-v">Figure</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">text</span> <span class="pl-k">import</span> <span class="pl-v">Text</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>  <span class="pl-c"># noqa</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">import</span> <span class="pl-s1">figure</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">widgets</span> <span class="pl-k">import</span> <span class="pl-v">Button</span>
<span class="pl-k">from</span> <span class="pl-s1">mpl_toolkits</span>.<span class="pl-s1">axes_grid1</span>.<span class="pl-s1">axes_size</span> <span class="pl-k">import</span> <span class="pl-v">Fixed</span>
<span class="pl-k">from</span> <span class="pl-s1">mpl_toolkits</span>.<span class="pl-s1">axes_grid1</span>.<span class="pl-s1">axes_divider</span> <span class="pl-k">import</span> <span class="pl-s1">make_axes_locatable</span>
<span class="pl-c"># matplotlib.use('Agg', force=True)</span>


<span class="pl-k">class</span> <span class="pl-v">Figure1</span>(<span class="pl-v">Figure</span>):
    <span class="pl-s">"""Interactive figure with scrollbars, for data browsing."""</span>

    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">yticks</span>, <span class="pl-c1">**</span><span class="pl-s1">kwargs</span>):
        <span class="pl-en">super</span>().<span class="pl-en">__init__</span>(<span class="pl-s1">figsize</span><span class="pl-c1">=</span>(<span class="pl-c1">6</span>, <span class="pl-c1">6</span>))
        <span class="pl-s1">ax_main</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">add_subplot</span>(<span class="pl-c1">1</span>, <span class="pl-c1">1</span>, <span class="pl-c1">1</span>, <span class="pl-s1">position</span><span class="pl-c1">=</span>[<span class="pl-c1">0.1</span>, <span class="pl-c1">0.1</span>, <span class="pl-c1">0.9</span>, <span class="pl-c1">0.9</span>])
        <span class="pl-s1">div</span> <span class="pl-c1">=</span> <span class="pl-en">make_axes_locatable</span>(<span class="pl-s1">ax_main</span>)
        <span class="pl-s1">ax_button</span> <span class="pl-c1">=</span> <span class="pl-s1">div</span>.<span class="pl-en">append_axes</span>(<span class="pl-s1">position</span><span class="pl-c1">=</span><span class="pl-s">'bottom'</span>, <span class="pl-s1">size</span><span class="pl-c1">=</span><span class="pl-v">Fixed</span>(<span class="pl-c1">0.5</span>), <span class="pl-s1">pad</span><span class="pl-c1">=</span><span class="pl-c1">0</span>)
        <span class="pl-s1">self</span>.<span class="pl-s1">_button</span> <span class="pl-c1">=</span> <span class="pl-v">Button</span>(<span class="pl-s1">ax_button</span>, <span class="pl-s">'Help'</span>)

        <span class="pl-c"># main plot</span>
        <span class="pl-s1">offsets</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-en">len</span>(<span class="pl-s1">yticks</span>))
        <span class="pl-s1">ax_main</span>.<span class="pl-en">set</span>(<span class="pl-s1">xlim</span><span class="pl-c1">=</span>[<span class="pl-c1">0</span>, <span class="pl-c1">1</span>], <span class="pl-s1">yticks</span><span class="pl-c1">=</span><span class="pl-s1">offsets</span>)
        <span class="pl-s1">ax_main</span>.<span class="pl-en">set_yticklabels</span>(<span class="pl-s1">yticks</span>, <span class="pl-s1">picker</span><span class="pl-c1">=</span><span class="pl-c1">True</span>)
        <span class="pl-s1">ax_main</span>.<span class="pl-en">plot</span>([<span class="pl-c1">0</span>, <span class="pl-c1">1</span>], [<span class="pl-s1">offsets</span>, <span class="pl-s1">offsets</span>])


<span class="pl-s1">picked</span> <span class="pl-c1">=</span> <span class="pl-en">list</span>()


<span class="pl-k">def</span> <span class="pl-en">on_pick</span>(<span class="pl-s1">event</span>):
    <span class="pl-s">"""Handle matplotlib pick events."""</span>
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">event</span>.<span class="pl-s1">artist</span>, <span class="pl-v">Text</span>):
        <span class="pl-s1">ch_name</span> <span class="pl-c1">=</span> <span class="pl-s1">event</span>.<span class="pl-s1">artist</span>.<span class="pl-en">get_text</span>()
        <span class="pl-en">print</span>(<span class="pl-s">f'pick <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">ch_name</span><span class="pl-kos">}</span></span>'</span>)
        <span class="pl-s1">picked</span>.<span class="pl-en">append</span>(<span class="pl-s1">ch_name</span>)


<span class="pl-s1">yticks</span> <span class="pl-c1">=</span> <span class="pl-en">list</span>(<span class="pl-s1">x</span> <span class="pl-c1">*</span> <span class="pl-c1">5</span> <span class="pl-k">for</span> <span class="pl-s1">x</span> <span class="pl-c1">in</span> <span class="pl-s">'ABCD'</span>)
<span class="pl-s1">fig</span> <span class="pl-c1">=</span> <span class="pl-en">figure</span>(<span class="pl-v">FigureClass</span><span class="pl-c1">=</span><span class="pl-v">Figure1</span>, <span class="pl-s1">yticks</span><span class="pl-c1">=</span><span class="pl-s1">yticks</span>)
<span class="pl-s1">fig</span>.<span class="pl-s1">canvas</span>.<span class="pl-en">mpl_connect</span>(<span class="pl-s">'pick_event'</span>, <span class="pl-s1">on_pick</span>)
<span class="pl-s1">fig</span>.<span class="pl-s1">canvas</span>.<span class="pl-en">draw</span>()


<span class="pl-s1">ax</span> <span class="pl-c1">=</span> <span class="pl-s1">fig</span>.<span class="pl-s1">axes</span>[<span class="pl-c1">0</span>]
<span class="pl-s1">x</span>, <span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">ax</span>.<span class="pl-s1">transData</span>.<span class="pl-en">transform_point</span>((<span class="pl-c1">-</span><span class="pl-c1">0.1</span>, <span class="pl-c1">0</span>))
<span class="pl-s1">func</span> <span class="pl-c1">=</span> <span class="pl-s1">fig</span>.<span class="pl-s1">canvas</span>.<span class="pl-en">button_press_event</span>(<span class="pl-s1">x</span><span class="pl-c1">=</span><span class="pl-s1">x</span>, <span class="pl-s1">y</span><span class="pl-c1">=</span><span class="pl-s1">y</span>, <span class="pl-s1">button</span><span class="pl-c1">=</span><span class="pl-c1">1</span>, <span class="pl-s1">guiEvent</span><span class="pl-c1">=</span><span class="pl-c1">None</span>)
<span class="pl-k">assert</span> <span class="pl-s">'AAAAA'</span> <span class="pl-c1">in</span> <span class="pl-s1">picked</span>
<span class="pl-k">assert</span> <span class="pl-en">len</span>(<span class="pl-s1">picked</span>) <span class="pl-c1">==</span> <span class="pl-c1">1</span>, <span class="pl-en">len</span>(<span class="pl-s1">picked</span>)</pre></div>
</details>
<p dir="auto">If you click on a ylabel (or simulate this with the code above), you get two pick events instead of one.</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/2365790/109532002-9b9e9600-7a86-11eb-9530-4463d39633f9.png"><img src="https://user-images.githubusercontent.com/2365790/109532002-9b9e9600-7a86-11eb-9530-4463d39633f9.png" alt="Screenshot from 2021-03-01 12-06-30" style="max-width: 100%;"></a></p>
<p dir="auto"><strong>Actual outcome</strong></p>
<p dir="auto">On <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a/hovercard" href="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a"><tt>6d79e6e</tt></a> / after <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="549605493" data-permission-text="Title is private" data-url="https://github.com/matplotlib/matplotlib/issues/16220" data-hovercard-type="pull_request" data-hovercard-url="/matplotlib/matplotlib/pull/16220/hovercard" href="https://github.com/matplotlib/matplotlib/pull/16220">#16220</a>:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="pick AAAAA
pick AAAAA
Traceback (most recent call last):
  File &quot;/home/larsoner/Desktop/fig.py&quot;, line 52, in &lt;module&gt;
    assert len(picked) == 1, len(picked)
AssertionError: 2"><pre class="notranslate"><code class="notranslate">pick AAAAA
pick AAAAA
Traceback (most recent call last):
  File "/home/larsoner/Desktop/fig.py", line 52, in &lt;module&gt;
    assert len(picked) == 1, len(picked)
AssertionError: 2
</code></pre></div>
<p dir="auto"><strong>Expected outcome</strong></p>
<p dir="auto">On <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/matplotlib/matplotlib/commit/74d61451efb9e6dd4916f4facf5614cc66528a4d/hovercard" href="https://github.com/matplotlib/matplotlib/commit/74d61451efb9e6dd4916f4facf5614cc66528a4d"><tt>74d6145</tt></a> / before <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="549605493" data-permission-text="Title is private" data-url="https://github.com/matplotlib/matplotlib/issues/16220" data-hovercard-type="pull_request" data-hovercard-url="/matplotlib/matplotlib/pull/16220/hovercard" href="https://github.com/matplotlib/matplotlib/pull/16220">#16220</a>:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="pick AAAAA"><pre class="notranslate"><code class="notranslate">pick AAAAA
</code></pre></div>
<p dir="auto"><strong>Matplotlib version</strong></p>
<ul dir="auto">
<li>Matplotlib version (<code class="notranslate">import matplotlib; print(matplotlib.__version__)</code>): <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a/hovercard" href="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a"><tt>6d79e6e</tt></a> or later</li>
<li>Matplotlib backend (<code class="notranslate">print(matplotlib.get_backend())</code>): Tested on Qt5Agg and Agg</li>
<li>Python version: 3.9.0</li>
</ul>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/anntzer/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/anntzer">@anntzer</a> since it was your PR that seems to have caused this.</p>
<h3 dir="auto">Bug report</h3>
<p dir="auto"><strong>duplicate pick events occurring in 3.4.rc1</strong></p>
<p dir="auto">In MNE-Python, our CIs that test against 3.4.rc1 are failing, because pick events are getting fired twice for every time an artist is picked (this is not happening on 3.3.4). It's happening in a very complicated interactive figure, and I haven't yet managed to work up an MWE that doesn't depend on MNE-Python.  But, I've used <code class="notranslate">git bisect</code> to isolate the first test failure to matplotlib commit <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a/hovercard" href="https://github.com/matplotlib/matplotlib/commit/6d79e6eddfe14a10141bab3ce421b2b43bc9a57a"><tt>6d79e6e</tt></a>.  I will continue trying to further isolate this, but in the meantime if anyone is familiar with MPL changes in the last 4 months, I'd be happy to hear ideas about what might be going on here.</p>
<p dir="auto"><strong>Code for reproduction</strong></p>
<p dir="auto">This code mirrors what we're doing but is too minimal, in that it doesn't yield doubled pick events:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import matplotlib.pyplot as plt
from matplotlib.text import Text


def pick_handler(event):
    if isinstance(event.artist, Text):
        print(&quot;PICKED&quot;)


fig, ax = plt.subplots()
_ = ax.plot((0, 1), (0, 1))
for lab in ax.get_yticklabels():
    lab.set_picker(True)

fig.canvas.mpl_connect('pick_event', pick_handler)"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">text</span> <span class="pl-k">import</span> <span class="pl-v">Text</span>


<span class="pl-k">def</span> <span class="pl-en">pick_handler</span>(<span class="pl-s1">event</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">event</span>.<span class="pl-s1">artist</span>, <span class="pl-v">Text</span>):
        <span class="pl-en">print</span>(<span class="pl-s">"PICKED"</span>)


<span class="pl-s1">fig</span>, <span class="pl-s1">ax</span> <span class="pl-c1">=</span> <span class="pl-s1">plt</span>.<span class="pl-en">subplots</span>()
<span class="pl-s1">_</span> <span class="pl-c1">=</span> <span class="pl-s1">ax</span>.<span class="pl-en">plot</span>((<span class="pl-c1">0</span>, <span class="pl-c1">1</span>), (<span class="pl-c1">0</span>, <span class="pl-c1">1</span>))
<span class="pl-k">for</span> <span class="pl-s1">lab</span> <span class="pl-c1">in</span> <span class="pl-s1">ax</span>.<span class="pl-en">get_yticklabels</span>():
    <span class="pl-s1">lab</span>.<span class="pl-en">set_picker</span>(<span class="pl-c1">True</span>)

<span class="pl-s1">fig</span>.<span class="pl-s1">canvas</span>.<span class="pl-en">mpl_connect</span>(<span class="pl-s">'pick_event'</span>, <span class="pl-s1">pick_handler</span>)</pre></div>
<p dir="auto">This code reproduces, but with <code class="notranslate">mne</code> dependency:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np
import matplotlib.pyplot as plt
import mne
# make fake data
data = np.random.standard_normal((2, 100))
info = mne.create_info(['ch1', 'ch2'], 1000)
raw = mne.io.RawArray(data, info)
# plot it
fig = raw.plot()"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-k">import</span> <span class="pl-s1">mne</span>
<span class="pl-c"># make fake data</span>
<span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">standard_normal</span>((<span class="pl-c1">2</span>, <span class="pl-c1">100</span>))
<span class="pl-s1">info</span> <span class="pl-c1">=</span> <span class="pl-s1">mne</span>.<span class="pl-en">create_info</span>([<span class="pl-s">'ch1'</span>, <span class="pl-s">'ch2'</span>], <span class="pl-c1">1000</span>)
<span class="pl-s1">raw</span> <span class="pl-c1">=</span> <span class="pl-s1">mne</span>.<span class="pl-s1">io</span>.<span class="pl-v">RawArray</span>(<span class="pl-s1">data</span>, <span class="pl-s1">info</span>)
<span class="pl-c"># plot it</span>
<span class="pl-s1">fig</span> <span class="pl-c1">=</span> <span class="pl-s1">raw</span>.<span class="pl-en">plot</span>()</pre></div>
<p dir="auto">In the resulting figure, clicking on one of the yticklabels (the channel names) is supposed to mark the channel as bad (which among other effects, will turn it light grey).  This doesn't happen because the pick event is fired twice, effectively marking and then unmarking the bad channel before a redraw can happen (I have confirmed this by simply inserting a <code class="notranslate">print</code> statement in the pick handler; it prints twice for each click).  There is nothing wrong with the code that marks bad channels; you can do it by clicking on the channel trace itself (which responds to <code class="notranslate">button_press_event</code> instead of <code class="notranslate">pick_event</code>, for complicated reasons).</p>
<p dir="auto"><strong>Matplotlib version</strong></p>

<ul dir="auto">
<li>Operating system:</li>
<li>Matplotlib version (<code class="notranslate">import matplotlib; print(matplotlib.__version__)</code>): 3.3.2.post1516+g6d79e6edd</li>
<li>Matplotlib backend (<code class="notranslate">print(matplotlib.get_backend())</code>): Qt5Agg</li>
<li>Python version: 3.8.8</li>
<li>Jupyter version (if applicable):</li>
<li>Other libraries: mne: current <code class="notranslate">main</code> (0.23.dev0)</li>
</ul>
<p dir="auto">matplotlib installed via <code class="notranslate">pip install -e .</code> from a git clone.</p>