Axes3D rotation not working when embedded in backend

I would like to use Axes3D embedded in Wx. This works, but there is no mouse rotation. Clicking and dragging the mouse on the plot does not rotate the 3D axes like it does in the "scatter3d_demo.py". I tried: WX, WXAgg, and TkAgg with similar results. Can this be fixed soon, or can someone point me to where I can try to fix it?

I tested with the latest SVN tree on Linux and Windows.

Thanks,
-Ben

Below is some sample code adapted from "embedding_in_wx2.py", but with an Axes3D instead of the regular plot:

#!/usr/bin/env python
# adapted from example code "embedding_in_wx2.py"

# Used to guarantee to use at least Wx2.8
import wxversion
wxversion.ensureMinimal('2.8')

import numpy as np

import matplotlib

# uncomment the following to use wx rather than wxagg
#matplotlib.use('WX')
#from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas

# comment out the following to use wx rather than wxagg
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

from matplotlib.backends.backend_wx import NavigationToolbar2Wx

from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
import wx

class CanvasFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,None,-1,
                         'CanvasFrame',size=(550,350))

        self.SetBackgroundColour(wx.NamedColor("WHITE"))

        self.figure = Figure()
        self.axes = Axes3D(self.figure)
        
        xs = np.random.rand(100)
        ys = np.random.rand(100)
        zs = np.random.rand(100)
        self.axes.scatter(xs, ys, zs)
    
        self.canvas = FigureCanvas(self, -1, self.figure)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()

        self.add_toolbar() # comment this out for no toolbar

    def add_toolbar(self):
        self.toolbar = NavigationToolbar2Wx(self.canvas)
        self.toolbar.Realize()
        if wx.Platform == '__WXMAC__':
            # Mac platform (OSX 10.3, MacPython) does not seem to cope with
            # having a toolbar in a sizer. This work-around gets the buttons
            # back, but at the expense of having the toolbar at the top
            self.SetToolBar(self.toolbar)
        else:
            # On Windows platform, default window size is incorrect, so set
            # toolbar width to figure width.
            tw, th = self.toolbar.GetSizeTuple()
            fw, fh = self.canvas.GetSizeTuple()
            # By adding toolbar in sizer, we are able to put it at the bottom
            # of the frame - so appearance is closer to GTK version.
            # As noted above, doesn't work for Mac.
            self.toolbar.SetSize(wx.Size(fw, th))
            self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        self.toolbar.update()

    def OnPaint(self, event):
        self.canvas.draw()

class App(wx.App):

    def OnInit(self):
        'Create the main window and insert the custom frame'
        frame = CanvasFrame()
        frame.Show(True)

        return True

app = App(0)
app.MainLoop()
#end code

I looked into this issue a little bit and found that the FigureCanvas must be set on the Figure before the 3D axes is instantiated. A simple re-ordering of the lines in the code below makes mouse rotation work again.

# ...
self.figure = Figure()
self.canvas = FigureCanvas(self, -1, self.figure)
#You must set up the canvas before creating the 3D axes
self.axes = Axes3D(self.figure)
# ...

Perhaps this should be documented somehow? Or maybe a new mplot3d example code should be added. Or maybe
Axes3D.mouse_init() should warn the user if self.figure.canvas is None.

-Ben

···

-----Original Message-----
From: Ben Axelrod [mailto:BAxelrod@…2066…]
Sent: Monday, February 01, 2010 3:56 PM
To: matplotlib-users@lists.sourceforge.net
Subject: [Matplotlib-users] Axes3D rotation not working when embedded in backend

I would like to use Axes3D embedded in Wx. This works, but there is no mouse rotation. Clicking and dragging the mouse on the plot does not rotate the 3D axes like it does in the "scatter3d_demo.py". I tried: WX, WXAgg, and TkAgg with similar results. Can this be fixed soon, or can someone point me to where I can try to fix it?

I tested with the latest SVN tree on Linux and Windows.

Thanks,
-Ben

Below is some sample code adapted from "embedding_in_wx2.py", but with an Axes3D instead of the regular plot:

#!/usr/bin/env python
# adapted from example code "embedding_in_wx2.py"

# Used to guarantee to use at least Wx2.8 import wxversion
wxversion.ensureMinimal('2.8')

import numpy as np

import matplotlib

# uncomment the following to use wx rather than wxagg
#matplotlib.use('WX')
#from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas

# comment out the following to use wx rather than wxagg
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

from matplotlib.backends.backend_wx import NavigationToolbar2Wx

from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
import wx

class CanvasFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,None,-1,
                         'CanvasFrame',size=(550,350))

        self.SetBackgroundColour(wx.NamedColor("WHITE"))

        self.figure = Figure()
        self.axes = Axes3D(self.figure)
        
        xs = np.random.rand(100)
        ys = np.random.rand(100)
        zs = np.random.rand(100)
        self.axes.scatter(xs, ys, zs)
    
        self.canvas = FigureCanvas(self, -1, self.figure)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()

        self.add_toolbar() # comment this out for no toolbar

    def add_toolbar(self):
        self.toolbar = NavigationToolbar2Wx(self.canvas)
        self.toolbar.Realize()
        if wx.Platform == '__WXMAC__':
            # Mac platform (OSX 10.3, MacPython) does not seem to cope with
            # having a toolbar in a sizer. This work-around gets the buttons
            # back, but at the expense of having the toolbar at the top
            self.SetToolBar(self.toolbar)
        else:
            # On Windows platform, default window size is incorrect, so set
            # toolbar width to figure width.
            tw, th = self.toolbar.GetSizeTuple()
            fw, fh = self.canvas.GetSizeTuple()
            # By adding toolbar in sizer, we are able to put it at the bottom
            # of the frame - so appearance is closer to GTK version.
            # As noted above, doesn't work for Mac.
            self.toolbar.SetSize(wx.Size(fw, th))
            self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        self.toolbar.update()

    def OnPaint(self, event):
        self.canvas.draw()

class App(wx.App):

    def OnInit(self):
        'Create the main window and insert the custom frame'
        frame = CanvasFrame()
        frame.Show(True)

        return True

app = App(0)
app.MainLoop()
#end code

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

One more note about Axes3D and mouse rotation. Axes3D disconnects the mouse callbacks when cla() is called. Which means that if you do this:

self.axes = Axes3D(self.figure)
self.axes.scatter(xs, ys, zs)
self.axes.cla()
self.axes.scatter(xs, ys, zs)

then the plot will have no mouse rotation. To fix this, mouse_init() should be called after cla(). Currently, all of this is undocumented. Is disconnecting mouse callbacks on cla() the preferred matplotlib way to do things? Is it safe to *not* disconnect mouse callbacks on cla()? Maybe there is another type of destructor that is more appropriate for this?

Thanks,
-Ben

···

-----Original Message-----
From: Ben Axelrod [mailto:BAxelrod@…2066…]
Sent: Saturday, February 06, 2010 5:55 PM
To: matplotlib-users@lists.sourceforge.net
Subject: Re: [Matplotlib-users] Axes3D rotation not working when embedded in backend

I looked into this issue a little bit and found that the FigureCanvas must be set on the Figure before the 3D axes is instantiated. A simple re-ordering of the lines in the code below makes mouse rotation work again.

# ...
self.figure = Figure()
self.canvas = FigureCanvas(self, -1, self.figure) #You must set up the canvas before creating the 3D axes self.axes = Axes3D(self.figure) # ...

Perhaps this should be documented somehow? Or maybe a new mplot3d example code should be added. Or maybe
Axes3D.mouse_init() should warn the user if self.figure.canvas is None.

-Ben

-----Original Message-----
From: Ben Axelrod [mailto:BAxelrod@…2066…]
Sent: Monday, February 01, 2010 3:56 PM
To: matplotlib-users@lists.sourceforge.net
Subject: [Matplotlib-users] Axes3D rotation not working when embedded in backend

I would like to use Axes3D embedded in Wx. This works, but there is no mouse rotation. Clicking and dragging the mouse on the plot does not rotate the 3D axes like it does in the "scatter3d_demo.py". I tried: WX, WXAgg, and TkAgg with similar results. Can this be fixed soon, or can someone point me to where I can try to fix it?

I tested with the latest SVN tree on Linux and Windows.

Thanks,
-Ben

Below is some sample code adapted from "embedding_in_wx2.py", but with an Axes3D instead of the regular plot:

#!/usr/bin/env python
# adapted from example code "embedding_in_wx2.py"

# Used to guarantee to use at least Wx2.8 import wxversion
wxversion.ensureMinimal('2.8')

import numpy as np

import matplotlib

# uncomment the following to use wx rather than wxagg
#matplotlib.use('WX')
#from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas

# comment out the following to use wx rather than wxagg
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

from matplotlib.backends.backend_wx import NavigationToolbar2Wx

from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
import wx

class CanvasFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,None,-1,
                         'CanvasFrame',size=(550,350))

        self.SetBackgroundColour(wx.NamedColor("WHITE"))

        self.figure = Figure()
        self.axes = Axes3D(self.figure)
        
        xs = np.random.rand(100)
        ys = np.random.rand(100)
        zs = np.random.rand(100)
        self.axes.scatter(xs, ys, zs)
    
        self.canvas = FigureCanvas(self, -1, self.figure)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()

        self.add_toolbar() # comment this out for no toolbar

    def add_toolbar(self):
        self.toolbar = NavigationToolbar2Wx(self.canvas)
        self.toolbar.Realize()
        if wx.Platform == '__WXMAC__':
            # Mac platform (OSX 10.3, MacPython) does not seem to cope with
            # having a toolbar in a sizer. This work-around gets the buttons
            # back, but at the expense of having the toolbar at the top
            self.SetToolBar(self.toolbar)
        else:
            # On Windows platform, default window size is incorrect, so set
            # toolbar width to figure width.
            tw, th = self.toolbar.GetSizeTuple()
            fw, fh = self.canvas.GetSizeTuple()
            # By adding toolbar in sizer, we are able to put it at the bottom
            # of the frame - so appearance is closer to GTK version.
            # As noted above, doesn't work for Mac.
            self.toolbar.SetSize(wx.Size(fw, th))
            self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        self.toolbar.update()

    def OnPaint(self, event):
        self.canvas.draw()

class App(wx.App):

    def OnInit(self):
        'Create the main window and insert the custom frame'
        frame = CanvasFrame()
        frame.Show(True)

        return True

app = App(0)
app.MainLoop()
#end code

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users