I don't have wx installed, so i'm not able to test your code.
However, here are some of my thoughts.

The location of the legend is the location of the lower-left corner in
the normalized coordinate of its parent. In your case, it would be
normalized "axes" coordinates. However, it seems that you're setting
the legend location in the normalized "figure" coordinate.

http://matplotlib.sourceforge.net/api/artist_api.html#module-matplotlib.legend


The event.x and event.y is the position of the mouse, and often this
would not be the position of the legend (lower left corner) you want.
I guess a common practice is to calculate how much your mouse moved
since you started dragging and adjust the position of the legend from
its original position by the same amount. What I would do is, in the
on_pick call, save the current location of the mouse and the current
location of the legend. And, when on_motion is called, calculate the
dx, dy of your current mouse position from the saved (original) mouse
position, and set the location of the legend by adding the same amount
to the original legend position. Of course, the coordinate need to be
converted in a proper system.

IHTH,

-JJ






On Wed, Mar 25, 2009 at 2:37 AM, C M <cmpyt...@gmail.com> wrote:
> Using mpl 0.98.5.2 in OO mode with wxAgg backend.
>
> I'm trying to make my legends draggable.  It works, but
> there is a some inaccuracy with positioning.  As I drag it,
> the cursor "outruns" the position of the legend, and that
> error grows the further away from the initial starting point
> the cursor has been moved.  It makes the feel of dragging
> completely wrong.
>
> The work of repositioning the legend is done in an
> on_motion event.  self.figure here is a mpl Figure.
> The motion event handler is:
>
> #drag the legend
>    def on_motion(self, event):
>        height = float(self.figure.bbox.height)
>        width = float(self.figure.bbox.width)
>
>        dx = event.x/width
>        dy = event.y/height
>
>        if self.gotLegend == 1:  #it's picked up
>            self.legend._loc=(dx,dy)  #reposition it
>            self.canvas.draw()
>            self.parent.Refresh()
>
> Any idea why this is wrong?  I cobbled this from
> a few sources online and boiled it down to this.
> I am confused as to why it should use dx and dy
> instead of just the exact position of the mouse.
>
> Any ideas are appreciated, and full runnable
> sample is below.
>
> Thanks,
> Che
>
>
> #Boa:Frame:Frame1
>
> import wx
>
> import matplotlib
> matplotlib.interactive(True)
> matplotlib.use('WXAgg')
> from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
> from matplotlib.figure import Figure
>
> def create(parent):
>    return Frame1(parent)
>
> [wxID_FRAME1, wxID_FRAME1NOTEBOOK1, wxID_FRAME1PANEL1,
> ] = [wx.NewId() for _init_ctrls in range(3)]
>
> class PlotPanel(wx.Panel):
>    def __init__(self, parent,id = -1, color = None,\
>        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
>
>        self.parent = parent
>        self.line_collections_list = []
>
>        wx.Panel.__init__(self, parent, **kwargs)
>
>        self.figure = Figure(None, dpi)
>        self.canvas = FigureCanvasWxAgg( self, -1, self.figure )
>
>        #Connect all the mpl events
>        self.canvas.mpl_connect('motion_notify_event', self.on_motion)
>        self.canvas.mpl_connect('pick_event', self.on_pick)
>        self.canvas.mpl_connect('button_release_event', self.on_release)
>
>        self.gotLegend = 0  #to begin, legend is not picked.
>
>        self._SetInitialSize()
>
>        self.Bind(wx.EVT_SIZE, self._onSize)
>        self.state = 'Initial'
>        self.draw()
>
>    def _onSize(self, event):
>        self._SetSize()
>        event.Skip()
>
>    def _SetSize( self ):
>        pixels = tuple( self.GetClientSize() )
>        self.SetSize( pixels )
>        self.canvas.SetSize( pixels )
>        self.figure.set_size_inches( float( pixels[0] )/self.figure.get_dpi(),
>                                     float( pixels[1] )/self.figure.get_dpi() )
>
>    def _SetInitialSize(self,):
>        pixels = self.parent.GetClientSize()
>        self.canvas.SetSize(pixels)
>        self.figure.set_size_inches( (pixels[0])/self.figure.get_dpi(),
>         (pixels[1])/self.figure.get_dpi(), forward=True )
>
>
>    def draw(self):
>        self.subplot = self.figure.add_subplot(111)
>        line, = self.subplot.plot([1,2,3],[4,5,6],'o',picker=5)
>        self.line_collections_list.append(line)
>
>        #Legend
>        self.legend = self.subplot.legend(self.line_collections_list,
> ['datum'], 'right',
>           numpoints=1)
>        self.legend.set_picker(self.my_legend_picker)
>
>    #pick up the legend patch
>    def my_legend_picker(self, legend, event):
>        return self.legend.legendPatch.contains(event)
>
>    #pick the legend
>    def on_pick(self, event):
>        legend = self.legend
>        if event.artist == legend:
>            self.gotLegend = 1
>
>    #drag the legend
>    #(This doesn't work well enough)
>    def on_motion(self, event):
>        height = float(self.figure.bbox.height)
>        width = float(self.figure.bbox.width)
>
>        dx = event.x/width
>        dy = event.y/height
>
>        if self.gotLegend == 1:
>            self.legend._loc=(dx,dy)
>            self.canvas.draw()
>            self.parent.Refresh()
>
>    #release the legend
>    def on_release(self, event):
>        if self.gotLegend == 1:
>            self.gotLegend = 0
>
> class Frame1(wx.Frame):
>    def _init_coll_boxSizer1_Items(self, parent):
>        # generated method, don't edit
>
>        parent.AddWindow(self.notebook1, 1, border=0, flag=wx.EXPAND)
>
>    def _init_sizers(self):
>        # generated method, don't edit
>        self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL)
>
>        self._init_coll_boxSizer1_Items(self.boxSizer1)
>
>        self.panel1.SetSizer(self.boxSizer1)
>
>    def _init_ctrls(self, prnt):
>        # generated method, don't edit
>        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
>              pos=wx.Point(333, 202), size=wx.Size(592, 474),
>              style=wx.DEFAULT_FRAME_STYLE,
>              title='moving the legend accurately')
>        self.SetClientSize(wx.Size(584, 440))
>
>        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', 
> parent=self,
>              pos=wx.Point(0, 0), size=wx.Size(584, 440),
>              style=wx.TAB_TRAVERSAL)
>
>        self.notebook1 = wx.Notebook(id=wxID_FRAME1NOTEBOOK1, name='notebook1',
>              parent=self.panel1, pos=wx.Point(0, 0), size=wx.Size(584, 440),
>              style=0)
>
>
>        self._init_sizers()
>
>    def __init__(self, parent):
>        self._init_ctrls(parent)
>        graph = PlotPanel(self.notebook1)
>        self.notebook1.AddPage(graph,'graph')
>
> if __name__ == '__main__':
>    app = wx.PySimpleApp()
>    frame = create(None)
>    frame.Show()
>
>    app.MainLoop()
>
> ------------------------------------------------------------------------------
> Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
> powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
> easily build your RIAs with Flex Builder, the Eclipse(TM)based development
> software that enables intelligent coding and step-through debugging.
> Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/matplotlib-users
>

------------------------------------------------------------------------------
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to