picking objects

Hello everyone, I am trying to implement object picking in my

    > matplotlib-based plotting application. I found two examples.
    > The 'picker_demo.py' demo is very nice and looks a lot simpler
    > than the 'object_picker.py' which requires you to use your own
    > Canvas object. But since object_picker needs to have the
    > event.inaxes object, it seems impossible to catch any events
    > outside the axes' bounding box, like 'click on axes title', or
    > 'click on ticks' or 'click on xlabel'.

Yes, the object_picker demo is very old and deprecated. It is around
from before the days of GUI neutral picking.

I wrote a little demo showing you how to pick the text (title, xlabel,
ylabel, ticklabels). Press "p" over a text instance outside the axes
bounding box and it will turn blue. If you think this is a reasonable
interface, I can make this the basis of a figure pick function. The
question is, what should such a function return. Eg, if you are
outside the axes and click over a text instance, it should return the
text instance. Clear enough. But if you are over an axes and click
on a line, what should it return? The Axes instance, The Line2D
instance, both in a tuple?

from pylab import subplot, title, connect, text, plot, rand, \
     show, gcf, draw
from matplotlib.text import Text
from matplotlib.lines import Line2D
from matplotlib.patches import Patch, Circle

def overtext(t, event):
    'return true if event is over text'
    bbox = t.get_window_extent()
    return bbox.contains(event.x, event.y)

def pick(event):
    
    if event.key!='p': return
    if event.inaxes is not None: # axes pick
        ax = event.inaxes
        a = ax.pick(event.x, event.y)
        
  if isinstance(a, Text):
            a.set_color('r')
        elif isinstance(a, Line2D):
            a.set_markerfacecolor('r')
  elif isinstance(a, Patch):
            a.set_facecolor('r')
        draw()
    else: # figure pick
        fig = gcf()
        texts = []
        for ax in fig.axes:
            texts.extend([ax.xaxis.label, ax.yaxis.label, ax.title])
            texts.extend(ax.xaxis.get_ticklabels())
            texts.extend(ax.yaxis.get_ticklabels())

        for t in texts:
            if overtext(t, event):
                t.set_color('blue')
                draw()
                return
        
connect('key_press_event', pick)

ax = subplot(111)
title('Put mouse over object and press "p" to pick it')

for i in range(20):
    x, y = rand(2)
    text(x,y,'hi!')

for i in range(5):
    x = rand(10)
    y = rand(10)
    plot(x,y,'go')

for i in range(5):
    x = rand()
    y = rand()
    center = x,y
    p = Circle(center, radius=.1)
    ax.add_patch(p)
    
show()

John Hunter schrieb:

[...]

Yes, the object_picker demo is very old and deprecated. It is around
from before the days of GUI neutral picking.

I wrote a little demo showing you how to pick the text (title, xlabel,
ylabel, ticklabels). Press "p" over a text instance outside the axes
bounding box and it will turn blue. If you think this is a reasonable
interface, I can make this the basis of a figure pick function. The
question is, what should such a function return. Eg, if you are
outside the axes and click over a text instance, it should return the
text instance. Clear enough. But if you are over an axes and click
on a line, what should it return? The Axes instance, The Line2D
instance, both in a tuple?

John,

thanks for the nice example.

I agree with you that one needs to think carefully about what pick() should actually return. I will experiment a little bit and will reply to the mailing list once I have made up my mind :wink:

Regards,

Niklas.