matplotlib+;wxpython未使用图例正确调整大小
我有一个matplotlib图,嵌入了一个wxpython框架中,带有一些尺寸标注器。在我加入一个传奇之前,一切都很好,但随后施胶器似乎没有与传奇一起工作 即使通过在拐角处拖动来调整窗口的大小,主图形也会改变大小,但只会显示图例的边缘 也就是说,请注意,图例在wxFrame中不可见matplotlib+;wxpython未使用图例正确调整大小,matplotlib,wxpython,Matplotlib,Wxpython,我有一个matplotlib图,嵌入了一个wxpython框架中,带有一些尺寸标注器。在我加入一个传奇之前,一切都很好,但随后施胶器似乎没有与传奇一起工作 即使通过在拐角处拖动来调整窗口的大小,主图形也会改变大小,但只会显示图例的边缘 也就是说,请注意,图例在wxFrame中不可见 import wx import matplotlib as mpl from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canva
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)点和线的数量。(另外,如果有关系的话,我最终会希望在底轴上标注日期。) 我把图例放在轴的外面,这样它就不会覆盖任何数据点,我更希望它保持在轴的右边
我使用的是Python 2.6.6、wxPython 2.8.12.1和matplotlib 1.1.0,目前仍在使用这些工具。它正在正确调整大小,您只是没有告诉它做您希望它做的事情 问题在于这一行:
axes.legend(loc='center left', bbox_to_anchor=(1.05, 0.5))
非常确定bbox\u to\u锚定kwarg覆盖了loc
kwarg,并且您将图例的左下角以轴单位固定到(1.05,0.5)。如果轴展开以填充窗口,则图例的左边缘将始终是轴右边缘右侧宽度轴的5%,因此始终不可见
您需要将图例放在其他地方,或者收缩轴(在图分数中)
选项1移动图例:
选项2移动轴并调整图形大小:
选项3:自动化选项2
好的,我看到你的编辑,但这不是我要找的。相反,我想要一个好方法,当图例在主图形之外时,让绘图很好地适合框架。不过感谢您的想法。matplotlib
只能绘制到它的画布上,而它的画布是图
小部件的大小。请注意命名法,图
是wiget,轴
是可以在其上划线的白色框。您可以将图例放在轴之外
,但您不能将任何东西放在图形之外
谢谢您的输入,但这对我不起作用。我需要一个解决方案,该解决方案不需要手动调整每个绘图,可以通过拖动调整大小,具有不同的长度标签,等等,并且仍然看起来不错。好吧,你不能使用不存在的功能(据我所知,我说我对此有80%的把握)。看看下面的紧凑布局是如何工作的。您可以询问算术师(轴和图例)它们在渲染图形上的大小,然后通过编程重新调整它们的大小。另一种方法是查看DraggableLegend
Fit
是一个wx级别的函数,它将调整图形大小以适合您的窗口,图例是图形小部件的一部分。画图后边界框的大小会改变,因为在画出图形之前文本的大小不会被排序。我知道你说的。它仍然无法解决问题。您希望a)图例不在轴上,并且b)能够看到图例。使用右侧图例的唯一方法是使轴以图形分数单位占用更少的空间。然后,您可以在重新调整窗口大小时使图形变宽。看起来发生的事情可能是一个错误,或者我做错了什么,但是直观地说,wx使用的图形/画布的大小也应该包括图例,即使图例在轴之外。还是我错了?我希望有人能告诉我如何正确使用总尺寸,否则我就自己把它写进浆纱机。这在代码方面有点难看,但我认为它会比手动改变尺寸(例如使用图形分数单位)更美观。这可能是缺少功能,但不是一个bug。
axes.legend(bbox_to_anchor=(0.5, 0.5)) #find a better place this is in the center
axes.set_position([.1, .1, .5, .8]) # units are in figure fraction
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)