matplotlib + wxpython的图例大小不正确 [英] matplotlib + wxpython not sizing correctly with legend

查看:40
本文介绍了matplotlib + wxpython的图例大小不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个matplotlib图,它嵌入在带有一些定尺寸器的wxpython框架中.一切正常,直到我包含一个图例,但随后 sizer 似乎并没有与图例一起工作.

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.

也就是说,注意图例在 wxFrame 中是不可见的.

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()


为了使解决方案对我有用,我希望当程序自动绘制图形时它看起来不错,因此可以在程序中或例如在窗口调整大小事件中对调整参数进行硬编码,但不能对它进行硬编码.为每个地块手动调整.我希望在此处更改的主要内容是: 1)标签的长度(例如1到25个字符), 2)窗口尺寸(通常是由用户在拐角处拖动,以及 3) 点和线的数量.(此外,如果很重要,我将希望在底部轴上显示日期.)


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.

我使用的是Python 2.6.6,wxPython 2.8.12.1和matplotlib 1.1.0,目前还停留在这些位置.

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

推荐答案

它正在正确地调整大小,只是你没有告诉它做你想让它做的事情.

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

问题是这一行:

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

请确保 bbox_to_anchor kwarg超出了 loc kwarg,并且您将图例的左下角以轴为单位固定为(1.05,0.5).如果轴扩展以填满您的窗口,则图例的左边缘将始终是轴右边缘右侧宽度轴的 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).

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

选项2移动轴+调整图形尺寸:

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

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))

# 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)

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)

这篇关于matplotlib + wxpython的图例大小不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆