matplotlib + wxpython not sizing correctly with legend
Question: I have a matplotlib figure embedded in a wxpython frame with a few sizers.
Everything works fine until I include a legend but then the sizers don't seem
to be working with the legend.

Even when I resize the window by dragging at the corner, the main figure
changes size, but only the edge of the legend is ever shown.

![enter image description here](http://i.stack.imgur.com/D6Fbp.png)

That is, note that the legend is not visible in the wxFrame.

    
    
    import wx
    import matplotlib as mpl
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
    from random import shuffle  
    
    class PlotFrame(wx.Frame):
    
        def __init__(self):     
    
            wx.Frame.__init__(self, None, -1, title="Plot", size=(-1, -1))
            self.main_panel = wx.Panel(self, -1)
            self.plot_panel = PlotPanel(self.main_panel)
    
            s0 = wx.BoxSizer(wx.VERTICAL)
            s0.Add(self.main_panel, 1, wx.EXPAND)
            self.SetSizer(s0)
            self.s0 = s0
    
            self.main_sizer = wx.BoxSizer(wx.VERTICAL)        
            self.main_sizer.Add(self.plot_panel, 1, wx.EXPAND)        
            self.main_panel.SetSizer(self.main_sizer)       
    
    class PlotPanel(wx.Panel):
    
        def __init__(self, parent, id = -1, dpi = None, **kwargs):
            wx.Panel.__init__(self, parent, id=id, **kwargs)
            self.figure = mpl.figure.Figure(dpi=dpi, figsize=(2,2))
            self.canvas = Canvas(self, -1, self.figure)
    
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.canvas,1,wx.EXPAND)
            self.SetSizer(sizer)
            sizer.SetMinSize((600, 500))
            self.sizer = sizer
    
    def test(plot_panel):
        axes = plot_panel.figure.gca()
        for c in ['r', 'b', 'k']:
            vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
            shuffle(vals)
            axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
        legend = axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
        return legend
    
    if __name__=="__main__":
        app = wx.PySimpleApp()
        frame = PlotFrame()
        legend = test(frame.plot_panel)
        frame.Fit()
        print "legend frame pre show: ", legend.get_frame()
        frame.Show(True)
        print "legend frame post show:", legend.get_frame()
        frame.Fit()
        app.MainLoop()
    

**Edit:**  
For a solution to be useful to me, I would like it to look good when the
figure is automatically drawn by the program, so adjustment parameters can be
hard coded in the program, or, for example, on a window resize event, but not
adjusted by hand for each plot. The main things that I expect to change here
are: **1)** the lengths of the labels (from, say, 1 to 25 characters), **2)**
the windows size (usually by the user dragging around the corner, and **3)**
the number of points and lines. (Also, if it matters, eventually, I'll want to
have dates on the bottom axis.)

I've put the legend outside of the axes so that it won't cover any data
points, and I'd prefer that it stay to the right of the axes.

I'm using Python 2.6.6, wxPython 2.8.12.1, and matplotlib 1.1.0 and am stuck
with these for now.


Answer: It is re-sizing correctly, you just didn't tell it to do what you want it to
do.

The problem is this line:

    
    
    axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
    

Pretty sure the `bbox_to_anchor` kwarg is over-ridding the `loc` kwarg and you
are pegging the bottom left of the legend to (1.05, 0.5) in axes units. If the
axes expands to fill your window, the left edge of the legend will always be
5% of the width axes to the right of the right edge of you axes, hence always
out of view.

You either need to put your legend someplace else or shrink your axes (in
figure fraction).

## option 1 move the legend:

    
    
    axes.legend(bbox_to_anchor=(0.5, 0.5)) #find a better place this is in the center
    

## option 2 move the axes + resize the figure:

    
    
    axes.set_position([.1, .1, .5, .8]) # units are in figure fraction
    

[`set_position`](http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_position)

    
    
    fig = figure()
    axes = fig.add_subplot(111)
    
    for c in ['r', 'b', 'k']:
        vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
        shuffle(vals)
        axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
    
    legend = axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
    

![enter image description here](http://i.stack.imgur.com/8tJRy.png)

    
    
    # adjust the figure size (in inches)
    fig.set_size_inches(fig.get_size_inches() * np.array([1.5, 1]), forward=True)
    
    # and the axes size (in figure fraction)
    # to (more-or-less) preserve the aspect ratio of the original axes
    # and show the legend
    pos = np.array(axes.get_position().bounds)
    pos[2] = .66
    axes.set_position(pos)
    

![enter image description here](http://i.stack.imgur.com/Dw1ci.png)

## option 3: automate option 2

    
    
    fig = figure() # use plt to set this up for demo purposes
    axes = fig.add_subplot(111) # add a subplot
    
    # control paramters 
    left_pad = .05 
    right_pad = .05
    
    # plot data
    for c in ['r', 'b', 'k']:
        vals = [20, 30, 40, 50, 80, 20, 50, 60, 70, 70, 80]
        shuffle(vals)
        axes.plot(range(len(vals)), vals, "-o", color=c, label=c*10)
    # set axes labels
    axes.set_xlabel('test x')
    axes.set_ylabel('test y')
    
    # make the legend
    legend = axes.legend(loc='center left', bbox_to_anchor=(1 + left_pad, 0.5))
    
    # function to 'squeeze' the legend into place
    def squeeze_legend(event):
        fig.tight_layout()
        right_frac = 1 - legend.get_window_extent().width / fig.get_window_extent().width - left_pad - right_pad
        fig.subplots_adjust(right=right_frac)
        fig.canvas.draw()
    
    # call it so the first draw is right
    squeeze_legend()
    
    # use the resize event call-back to make sure it works even if the window is re-sized
    fig.canvas.mpl_connect('resize_event', squeeze_legend)
    

