Quantcast

onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

othererik
Good day,

I've hit an issue that may be a bug.  In a previous version of
matplotlib (.98.x) I had a picker set for lines plotted on two axes.
This was working until I upgraded to version 0.99.0.   Now the first
axes's pick events never seem to fire even though they respond true if
queried with pickable(). The second axes's pick events still fire.

Using the example below, clicking on the left y's line will never
print anything, but the sin from the right will if clicked on.

OS: Windows XP Pro
Python: 2.6
matplotlib version: 0.99.0 -- installed using the python2.6 windows
exe obtained from sourceforge


Code to reproduce:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(111)
t = np.arange(0.01, 10.0, 0.01)
s1 = np.exp(t)
ax1.plot(t, s1, 'b-', picker = 4.0)
ax1.set_xlabel('time (s)')
# Make the y-axis label and tick labels match the line color.
ax1.set_ylabel('exp', color='b')
for tl in ax1.get_yticklabels():
    tl.set_color('b')


ax2 = ax1.twinx()
s2 = np.sin(2*np.pi*t)
ax2.plot(t, s2, 'r.', picker = 4.0)
ax2.set_ylabel('sin', color='r')
for tl in ax2.get_yticklabels():
    tl.set_color('r')


def onpick(event):
    thisline = event.artist
    xdata = thisline.get_xdata()
    ydata = thisline.get_ydata()
    ind = event.ind
    print 'onpick points:', zip(xdata[ind], ydata[ind])

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

plt.show()


Thanks for a wonderful plotting package!

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Matplotlib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

John Hunter-4
On Thu, Aug 13, 2009 at 12:51 PM, Erik Schweller<[hidden email]> wrote:

> Good day,
>
> I've hit an issue that may be a bug.  In a previous version of
> matplotlib (.98.x) I had a picker set for lines plotted on two axes.
> This was working until I upgraded to version 0.99.0.   Now the first
> axes's pick events never seem to fire even though they respond true if
> queried with pickable(). The second axes's pick events still fire.
>
> Using the example below, clicking on the left y's line will never
> print anything, but the sin from the right will if clicked on.

I'm not sure why it worked before -- that surprises me.  Only one axes
can receive the pick event currently, so if you have overlapping axes,
as you do with twinx, the one with the highest zorder will receive the
pick events.  By default, the zorder by the Axes is 0, so you could
raise the twinx axes, by increaseing the zorder

  ax2.set_zorder(0.1)

and then the line on that axes will respond to the pick events.  With
some work, we might be able to support multiple overlapping axes
handling a single pick event.

JDH

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Matplotlib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

othererik
John,

Thanks for the information. The solution worked so, I can now do a mouse over over lines from either axes and have a nice little tooltip, etc.  I found that if I change the zorder of the axis right after attempting to "pick" on the mouse event, it fails, but it's fine for my needs to just toggle the "top" axes on mouse events when looking for a mouse hover.

                    if self.ax.get_zorder() == 0.1:
                        ax.set_zorder( 0 )
                        ax2.set_zorder( 0.1 )
                    else:
                        ax2.set_zorder( 0 )
                        ax.set_zorder( 0.1 )

                self.figure.pick( event )

This is perhaps a bit of hackery, but I've not seen any mouse over legends of the sorts built in.  

Thanks again,
-Erik

John Hunter-4 wrote
I'm not sure why it worked before -- that surprises me.  Only one axes
can receive the pick event currently, so if you have overlapping axes,
as you do with twinx, the one with the highest zorder will receive the
pick events.  
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

Stephan Markus
Hello!

I am also using two axes in a plot and want to be able to pick the lines of both axes.
So far I used MPL 0.99.3 and a button on my interface to change the z-order of the axes in order to be able to pick lines of the "active" axes and to see the correct x/y data in the navigation toolbar. The callback code of my button is basically the code from othererik.

Since MPL 1.0.0 I have the problem that lines of the second axes simply disappear from the plot whenever the plot is redrawn and it's zorder is higher.

Here is my example code:
twinxtest.py
-----------------------
import matplotlib
matplotlib.use('TkAgg')

from numpy import arange, sin, pi, cos
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as Tk


root = Tk.Tk()

f = Figure(figsize=(5,4), dpi=100)
ax1 = f.add_subplot(111)
ax2 = ax1.twinx()

t = arange(0.0,3.0,0.01)
s1 = sin(2*pi*t)
s2 = 2*cos(2*pi*t)

ax1.plot(t,s1,color='red', picker=True)
ax2.plot(t,s2,picker=True)


def pick_cb(event):
    if event.artist.get_lw() > 1:
        event.artist.set_lw(1)
    else:
        event.artist.set_lw(3)
    f.canvas.draw()
   

def toggle():
    if ax1.get_zorder() == 0:
        ax1.set_zorder(0.1)
        ax2.set_zorder(0)
    else:
        ax1.set_zorder(0)
        ax2.set_zorder(0.1)


canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

canvas.mpl_connect('pick_event', pick_cb)

button = Tk.Button(master=root, text='Toggle', command=toggle)
button.pack(side=Tk.BOTTOM)

Tk.mainloop()
------------------

Right after start I can only pick the blue line and both lines are properly shown even when I resize the plot. When I hit the "Toggle" button now I can pick the red line but the pick event callback also calls canvas.draw() which let's the blue line disappear. When I click "Toggle" and call canvas.draw() again by resizing the window, the blue line is visible again.
In Matplotlib 0.99.3 everything worked as I expected with this code. Both lines were always visible.

-Stephan
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

Stephan Markus
Right now I use a customized FigureCanvasTkAgg and overwrite the draw() and resize() methods to reset the z-order of the axes before drawing / resizing the figure and to restore the desired z-order afterwards. This works quite well but it would be nice to have the picking work like in version <=0.99.3.

-----------------------
import matplotlib
matplotlib.use('TkAgg')

from numpy import arange, sin, pi, cos
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as Tk


root = Tk.Tk()

f = Figure(figsize=(5,4), dpi=100)
ax0 = f.add_subplot(111)
ax1 = ax0.twinx()

t = arange(0.0,3.0,0.01)
s1 = sin(2*pi*t)
s2 = 2*cos(2*pi*t)

ax0.plot(t,s1,color='red', picker=True)
ax1.plot(t,s2,picker=True)
ax0.my_zorder=0
ax1.my_zorder=0.1

class MyFigureCanvasTkAgg(FigureCanvasTkAgg):
    def draw(self):
        ax0 = self.figure.axes[0]
        ax1 = self.figure.axes[1]
        ax0.set_zorder(0)
        ax1.set_zorder(0)
        FigureCanvasTkAgg.draw(self)
        ax0.set_zorder(ax0.my_zorder)
        ax1.set_zorder(ax1.my_zorder)
           
    def resize(self, event):
        ax0 = self.figure.axes[0]
        ax1 = self.figure.axes[1]
        ax0.set_zorder(0)
        ax1.set_zorder(0)
        FigureCanvasTkAgg.resize(self, event)
        ax0.set_zorder(ax0.my_zorder)
        ax1.set_zorder(ax1.my_zorder)


def pick_cb(event):
    if event.artist.get_lw() > 1:
        event.artist.set_lw(1)
    else:
        event.artist.set_lw(3)
    f.canvas.draw()
   

def toggle():
    if ax0.my_zorder == 0:
        ax0.my_zorder=0.1
        ax1.my_zorder=0
    else:
        ax0.my_zorder=0
        ax1.my_zorder=0.1
    ax0.set_zorder(ax0.my_zorder)
    ax1.set_zorder(ax1.my_zorder)


canvas = MyFigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

canvas.mpl_connect('pick_event', pick_cb)

button = Tk.Button(master=root, text='Toggle', command=toggle)
button.pack(side=Tk.BOTTOM)

Tk.mainloop()
-----------------------
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

Chelonian
In reply to this post by Stephan Markus
On Thu, Jan 20, 2011 at 4:44 AM, Stephan Markus <[hidden email]> wrote:

>
> Hello!
>
> I am also using two axes in a plot and want to be able to pick the lines of
> both axes.
> So far I used MPL 0.99.3 and a button on my interface to change the z-order
> of the axes in order to be able to pick lines of the "active" axes and to
> see the correct x/y data in the navigation toolbar. The callback code of my
> button is basically the code from othererik.
>
> Since MPL 1.0.0 I have the problem that lines of the second axes simply
> disappear from the plot whenever the plot is redrawn and it's zorder is
> higher.

This thread, in which I asked a similar question and receive a
workable solution from JJ, might be helpful.  I am now just
automatically moving all my lines over to the highest z-order axis so
that whatever is visible is pickable.  (But see below for a gotcha)

http://old.nabble.com/unable-to-point-pick-2nd-axis-after-upgrade-to-mpl-1.0-td30400311.html

On this note, to the developers:  This need to take into account the
z-order for picking lines has made my development more difficult.  I
have had a week's delay due to a difficult-to-understand bug in my
code in which I prematurely moved the line over to the highest z-order
axis, and then tried to format the axis with a custom
formatter--causing an error.  Simply moving the line only after all
formatting is done fixed the bug, but that wasn't obvious for a while.
The need to track which lines are on which z-order and to move them
only after all formatting/locating has been done on them strikes me as
a new "gotcha" that the simpler and more intuitive approach of "if you
can see it, you can pick it" didn't have. (I have a somewhat complex
case, though, in which there are three possible sorts of axes that
could wind up on either the right or left sides).

It also seems counter-intuitive that a line can "belong" to an axis
from the in Matplotlib and yet for the user it clearly is measured
using the other axis.  Could "z-order mattering" be toggled?  Anyway,
my 2 cents.

Thanks,
Che

------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________
Matplotlib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: onpick on a 2 y plot ( via twinx() ) seems to only allow picking of second axes's artists

Stephan Markus
That solution might be fine for static plots, but I my case I prefer my solution.

My plot is quite interactive so using your solution causes many problems with my code.

Loading...