issues with interacting with a plot

Hi,

I’ve coded (with help from John) a
plot of mine to allow a user to select a data point, and when they click on it
a new plot pops up. It works great. However, some of the points are
very close together and if I’m not extremely careful in selecting the
point, then multiple graphs pop up or I get the wrong one entirely.

So, I figured maybe if I zoomed in then it’d
be easier to select the desired point. The problem is that after
zooming/panning, the mouse cursor changes and my click events are no longer
recognized as such. Furthermore, I can’t find a way to make the
mouse cursor return to its normal state and allow me to continue clicking
events. Is there something I’m missing?

thanks,

trevis

···

Trevis Crane

Postdoctoral Research Assoc.

Department of Physics

University of Ilinois

1110 W. Green St.

Urbana, IL 61801

p: 217-244-8652

f: 217-244-2278

e: tcrane@…1315…


Hi Trevis,

<snip>

So, I figured maybe if I zoomed in then it'd be easier to select the desired
point. The problem is that after zooming/panning, the mouse cursor changes
and my click events are no longer recognized as such. Furthermore, I can't
find a way to make the mouse cursor return to its normal state and allow me
to continue clicking events. Is there something I'm missing?

Could it be that you're still in zoom or pan mode when you try to
click to select a point? You'll see the zoom or pan button highlighted
in the toolbar if that is the case. Clicks when in these modes don't
activate the callback feature, so you need to click again on the same
toolbar button to leave that mode; then the cursor should return to an
arrow and your callback routine should be activated correctly.

HTH,

A.

···

On 12/06/07, Trevis Crane <t_crane@...1614...> wrote:
--
AJC McMorland, PhD Student
Physiology, University of Auckland

You can always write a custom hit testing function -- see
http://matplotlib.sourceforge.net/examples/pick_event_demo.py for an
example.

Probably easiest here is to just find the index which is closest to
one of your data points and just plot that data set.

BTW, numpy gurus, is there a better way to find the index in an array
that is minimal than

indmin = int(numpy.nonzero(distances.min()==distances)[0])

import numpy
from pylab import figure, show

X = numpy.random.rand(100, 200)
xs = numpy.mean(X, axis=1)
ys = numpy.std(X, axis=1)

fig = figure()
ax = fig.add_subplot(211)
ax.set_title('click on point to plot time series')
line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance
ax2 = fig.add_subplot(212)

def onpick(event):

    if event.artist!=line: return True

    N = len(event.ind)
    if not N: return True

    # the click locations
    x = event.mouseevent.xdata
    y = event.mouseevent.ydata

    distances = numpy.array(numpy.sqrt((x-xs[event.ind])**2. +
(y-ys[event.ind])**2))
    indmin = int(numpy.nonzero(distances.min()==distances)[0])
    dataind = event.ind[indmin]
    print event.ind, distances, indmin, dataind, X[dataind][:5]

    ax2.cla()
    ax2.plot(X[dataind])
    ax2.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]),
            transform=ax2.transAxes, va='top')
    ax2.set_ylim(-0.5, 1.5)
    fig.canvas.draw()

    return True

fig.canvas.mpl_connect('pick_event', onpick)

show()

test.py (1.23 KB)

···

On 6/11/07, Trevis Crane <t_crane@...1614...> wrote:

I've coded (with help from John) a plot of mine to allow a user to select a
data point, and when they click on it a new plot pops up. It works great.
However, some of the points are very close together and if I'm not extremely
careful in selecting the point, then multiple graphs pop up or I get the
wrong one entirely.

John Hunter wrote:

BTW, numpy gurus, is there a better way to find the index in an array
that is minimal than

indmin = int(numpy.nonzero(distances.min()==distances)[0])

yes -- see below. Also a few tweaks:

   distances = numpy.array(numpy.sqrt((x-xs[event.ind])**2. +
(y-ys[event.ind])**2))

No need to call numpy.array on that, you're making a copy of what must be an array already. By the way, if you're not sure if it's an array, then you can use numpy.asarray(a) which won't make a copy if the argument is already an array.

You can also use numpy.hypot() rather than explicitly calling sqrt(SumOfSquares):

distances = numpy.hypot(x-xs[event.ind], y-ys[event.ind] )

(untested)

or, if all you want is the closest one, you don't need to take the sqrt() at all:

distances = ( (x-xs[event.ind])**2 + (y-ys[event.ind])**2 )

And don't use "2." in an exponent -- I think there is some optimization for integer exponents.

   indmin = int(numpy.nonzero(distances.min()==distances)[0])

here you can use argmin:

indmin = numpy.argmin(distances)

of course, what you'd really want is a spatial index....

All untested....

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...