timnz
timnz

Reputation: 11

Incorrect sizing of matplotlib figures within a wxPython panel

I am attempting to have two matplotlib figures side-by-side inside a panel in a wxPython application. This used to work with wxPython 2.8, but no longer in wxPython 3.0.

In wxPython 2.8, the width of each plot is half of the panel size. In wxPython 3.0, the width of the plot is equal to the panel size, which means only the plot on the left shows. Expanding the window then eventually reveals the right-hand-side plot.

Simplest example that reproduces the problem is below.

import wx
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(TestPlot(panel), 1, wx.EXPAND | wx.ALL, border=5)
        sizer.Add(TestPlot(panel), 1, wx.EXPAND | wx.ALL, border=5)
        panel.SetSizerAndFit(sizer)

class TestPlot(wx.Window):
    def __init__(self, *args, **kwargs):
        wx.Window.__init__(self, *args, **kwargs)

        self.canvas = FigureCanvasWxAgg(self, wx.ID_ANY, Figure())

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.canvas, 1, wx.ALL, border=20)
        self.SetSizerAndFit(sizer)

if __name__ == "__main__":
    app = wx.App()
    MainFrame(parent=None, size=(300, 300)).Show()
    app.MainLoop()

How can I get this layout to work in wxPython 3.0?

Upvotes: 1

Views: 1163

Answers (2)

snakagawa
snakagawa

Reputation: 11

I've had the same problem on wxpython 3.0.

I think the problem is that the default minimum size of self.canvas is too large.

Setting the minimum size manually to some very small values by self.canvas.SetMinSize(wx.Size(1,1)) seems to solve the problem. Not an elegant way though...

Following is the fixed version of your example.

import wx
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(TestPlot(panel), 1, wx.EXPAND | wx.ALL, border=5)
        sizer.Add(TestPlot(panel), 1, wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        # don't do Fit(), as it sets the canvases to its minimum size
        panel.Layout()

class TestPlot(wx.Window):
    def __init__(self, *args, **kwargs):
        wx.Window.__init__(self, *args, **kwargs)

        self.canvas = FigureCanvasWxAgg(self, wx.ID_ANY, Figure())
        # setting the minimum canvas size as small as possible
        self.canvas.SetMinSize(wx.Size(1,1))

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        # added wx.EXPAND so that the canvas can stretch vertically
        sizer.Add(self.canvas, 1, wx.ALL|wx.EXPAND, border=20)
        self.SetSizer(sizer)

if __name__ == "__main__":
    app = wx.App()
    MainFrame(parent=None, size=(300, 300)).Show()
    app.MainLoop()

Hope this helps.

Tested on Windows 8.1/Python 2.7.9/matplotlib 1.4.3/wxpython 3.0.0.0

Upvotes: 1

nepix32
nepix32

Reputation: 3177

Replace

    panel.SetSizerAndFit(sizer)

by

    panel.SetSizer(sizer)
    sizer.Fit(self)

to finally adjust the wx.Frame to the elements in the panel.

Upvotes: 0

Related Questions