pick_event problems

Hello all,

I've been working on some interactive graphs and have run into several problems
with the pick_event feature:
(1) If a Figure Legend is made draggable() and then dropped onto an AxesSubplot,
it can no longer be dragged
(2) Any lines associated with the left axis of a twinx() subplot are unable to
be picked
(3) Hidden lines can be picked (seems like an undesirable feature). Try picking
on the top subplot at y=1 for a hidden line.

I know #2 has <a
href="http://old.nabble.com/onpick-on-a-2-y-plot-(-via-twinx()-)-seems-to-only-allow-picking-of-second-axes's-artists-td25049128.html">caused
problems for others</a>, with less than elegant solutions given.

Here's the code showing what is currently broken (as of v1.0.0):

#!/usr/bin/env python
import matplotlib as mpl
import pylab

# <-- Insert code to fix problem here

def on_pick(event):
    if isinstance(event.artist, mpl.legend.Legend):
        print 'Picked Legend'
    else:
        print 'Picked', event.artist.get_label(), event.ind

fig = pylab.figure()
ax = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax3 = ax2.twinx()
# Top subplot
ax.plot(range(10), range(10), c='r', marker='^', picker=5, label='Ramp')
line, = ax.plot(range(10), [1]*10, c='k', marker='o', picker=5, label='Hidden')
line.set_visible(False)
# Bottom subplot
legn_handles = []
legn_labels = []
line = ax2.plot(range(10), [1,3,1,3,0,3,1,3,1,3], c='b', marker='o', picker=5,
label='Teeth')
legn_handles.append(line)
legn_labels.append('Teeth')
ax2.set_ylim(0, 4)
ax2.set_ylabel('Left side', color='b')
line = ax3.plot(range(10), [1,1,1,1,4,4,4,4,4,4], c='m', marker='.', picker=5,
label='Shelf')
legn_handles.append(line)
legn_labels.append('Shelf')
ax3.set_ylim(0, 5)
ax3.set_ylabel('Right side', color='m')
# Subplot Legend for top plot
legn = ax.legend()
legn.draggable()
# Figure Legend
legn = fig.legend(legn_handles, legn_labels, 'lower right')
legn.draggable()
fig.canvas.mpl_connect('pick_event', on_pick)
pylab.show()

···

#
--------------------------------------------------------------------------------------------

I've found a decent workaround, but it involves some very fundamental changes
to the way picking is resolved in the Figure and Axes classes. If you add the
following code to the spot indicated for the fix, everything works correctly.

# Fix for pick_event problems
def axes_pick(self, *args):
    if len(args)>1:
        raise DeprecationWarning('New pick API implemented -- '
                                 'see API_CHANGES in the src distribution')
    mouseevent = args[0]
    if not self.in_axes(mouseevent):
        return
    for a in self.get_children():
        if not a.get_visible():
            continue
        a.pick(mouseevent)
mpl.axes.Axes.pick = axes_pick

def figure_pick(self, mouseevent):
    for a in self.get_children():
        if not a.get_visible():
            continue
        a.pick(mouseevent)
mpl.figure.Figure.pick = figure_pick

To compare the differences, you need to look at the artist.Artist.pick()
method. It only calls pick() for children whose axes==mouseevent.inaxes or when
inaxes is None (to handle the Legend). But this fails when the Legend is
dragged over a Subplot (inaxes no longer None), causing bug #1. Also,
mouseevent.inaxes only contains a single axes instance, which causes a failure
for overlapping twinx() axes, hence bug #2. And of course there is no check for
hidden artists (#3).

My change calls pick() for every child of the Figure or Subplot, but then has
the Subplot check whether the mouseevent is in its own axes space. This seems
to fix all the problems, but could potentially cause new bugs. Any thoughts?
I'm new to the mailing list, so I'm not sure how patches get applied and how
much testing needs to be done for a change like this.

Thanks,
Jim