matplotlib和wxpython的透明度问题

我正在开发基于matplotlibWindows的wxpython的GUI。 当使用“Windows XP”主题(绿色“开始”button,蓝色任务栏)时,我遇到了一个可见的问题。 我很确定,同样的问题也会出现在Vista上。 我知道一个不完善的解决方法,但我无法正确解决此问题。

我的matplotlib图embedded到wxPanel中,embedded到wxNotebook(如果您愿意,可以使用制表符)。 对于一些主题,选项卡的背景颜色实际上是一个渐变,并且wx会尝试将其与接近它的颜色相匹配。 这是不完美的解决方法:颜色匹配在窗口的顶部,但不在底部。

这就是为什么我想实际使用具有透明背景的matplotlib图。 当我将graphics的facecolor设置为透明的时候,它实际上会把桌面或者任何窗口的“颜色”放在后面,而不是wxPanel / wxNotebook。 如果我调整窗口大小,透明部分会累积绘制的数据。 这最后一个问题不再是主题,我也在“Windows Classic”上观察它。

在下面的示例代码中,我宁愿期望图的透明部分显示在embedded图的面板上设置的蓝色。

import wx import matplotlib matplotlib.use('WXAgg') from matplotlib.figure import Figure from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg import wxversion import sys class MyFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 300,650 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) bSizer3 = wx.BoxSizer( wx.VERTICAL ) self.m_notebook2 = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_panel1 = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer4 = wx.BoxSizer( wx.VERTICAL ) self.m_panel2 = wx.Panel( self.m_panel1, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.m_panel2.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_ACTIVECAPTION ) ) bSizer4.Add( self.m_panel2, 1, wx.EXPAND |wx.ALL, 5 ) self.m_panel1.SetSizer( bSizer4 ) self.m_panel1.Layout() bSizer4.Fit( self.m_panel1 ) self.m_notebook2.AddPage( self.m_panel1, u"a page", False ) bSizer3.Add( self.m_notebook2, 1, wx.EXPAND |wx.ALL, 0 ) self.SetSizer( bSizer3 ) self.Layout() self.Centre( wx.BOTH ) def __del__( self ): pass class MyPlot: def __init__(self, panel, notebook): self.panel = panel self.panel.figure = Figure(None, dpi=None) self.panel.canvas = FigureCanvasWxAgg(self.panel, -1, self.panel.figure) self.panel.axes = self.panel.figure.add_subplot(111) self.panel.Bind(wx.EVT_SIZE, self.onSize) # I want this code to work whatever the theme. It works fine on WinXP "Windows Classic" theme, but not on WinXP "Windows XP" theme (with green Start menu button and blue taskbar) self.setColor(None) # The problem here is that SYS_COLOUR_BTNFACE does not match the notebook background for the Windows XP theme # Solution 1: get background gradient from notebook # Source: http://wxpython-users.1045709.n5.nabble.com/wxTextCtrl-doesn-t-show-background-as-expected-on-a-notebook-panel-td2359680.html # Problem: match is perfect at top, not at bottom (not much difference, though) # # # # Uncomment below # rgbtuple = notebook.GetThemeBackgroundColour() # clr = [c / 255. for c in rgbtuple] # self.panel.figure.set_facecolor(clr) # self.panel.figure.set_edgecolor(clr) # Solution 2: set transparent figure facecolor to capture color from panel # Problem 1: it takes the color from behind the frame (ie desktop, any other window behind...), not the color of the panel # Problem 2 (linked to problem 1): it gets worse when resizing as it doesn't repaint but accumulates # # http://matplotlib.1069221.n5.nabble.com/redrawing-plot-with-transparent-background-in-wx-tt26694.html seems related but did not receive any answer # # # Recomment above, uncomment below #self.panel.figure.set_facecolor('None') self.setSize() def setSize(self): pixels = tuple(self.panel.GetClientSize()) self.panel.SetSize(pixels) self.panel.canvas.SetSize(pixels) self.panel.figure.set_size_inches(float(pixels[0]) / self.panel.figure.get_dpi(), float(pixels[1]) / self.panel.figure.get_dpi()) def onSize(self, event): self.setSize() def setColor(self, rgbtuple=None): if rgbtuple is None: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() clr = [c / 255. for c in rgbtuple] self.panel.figure.set_facecolor(clr) self.panel.figure.set_edgecolor(clr) self.panel.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) print "python " + str(sys.version_info) print "wx " + str(wxversion.getInstalled()) print "matplotlib " + matplotlib.__version__ app = wx.App(0) window = MyFrame(None) plot = MyPlot(window.m_panel2, window.m_notebook2) window.Show() app.MainLoop() 

如果您抓住窗口的一个angular落并摇动它来调整它的大小,那么蓝色通常是可见的。 我立即调整了目的,而不是等待窗户闲置。

请取消注释代码中的指示行,看看我可能不清楚解释。

我的configuration:Python 2.7.3,wx 2.9.4-msw,matplotlib 1.1.1

编辑

我没有取得很大的进展:

  • 我注意到matplotlib 1.2.0出来了,所以试了一下,但没有改变
  • 我简化了这个例子,摆脱了wxNotebook,问题仍然存在,只有一个wxPanel
  • 我发现http://wxpython-users.1045709.n5.nabble.com/advice-on-filling-squares-tp4475117p4479387.html这可能会提示发生了什么事情

我还开发了另外一个例子,我叠加了两个数字,看透明度在哪里停止。 有趣的是,下图阻止了上图中的透明度,而不是wxPanel。

 import wx import matplotlib matplotlib.use('WXAgg') from matplotlib.patches import Rectangle from matplotlib.figure import Figure from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg import wxversion import sys class MyFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 300,650 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) bSizer4 = wx.BoxSizer( wx.VERTICAL ) self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.m_panel2.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_ACTIVECAPTION ) ) bSizer4.Add( self.m_panel2, 1, wx.EXPAND |wx.ALL, 5 ) self.m_panel2.Layout() self.SetSizer( bSizer4 ) self.Layout() self.Centre( wx.BOTH ) def __del__( self ): pass class MyPlot: def __init__(self, panel): self.panel = panel # This figure is behind self.panel.figure = Figure(figsize=(2,2), dpi=None) self.panel.canvas = FigureCanvasWxAgg(self.panel, -1, self.panel.figure) self.panel.axes = self.panel.figure.add_axes([0.3,0.3,0.5,0.5]) patch = Rectangle((0,0), 0.3, 0.2, facecolor='red') self.panel.axes.add_patch(patch) # This figure is on top self.panel.figure2 = Figure(figsize=(3,3), dpi=None) self.panel.canvas2 = FigureCanvasWxAgg(self.panel, -1, self.panel.figure2) self.panel.axes2 = self.panel.figure2.add_axes([0.3,0.3,0.5,0.5]) patch2 = Rectangle((0.5,0.5), 0.4, 0.1, facecolor='blue') self.panel.axes2.add_patch(patch2) # Make the top figure transparent # self.panel.figure2.set_facecolor('None') # equivalent to self.panel.figure2.patch.set_alpha(0) # By default, leave figure on bottom opaque # Uncomment to see effect of transparency #self.panel.figure.patch.set_alpha(0.5) self.panel.figure2.patch.set_alpha(0.5) # Draw everything self.panel.canvas.draw() print "python " + str(sys.version_info) print "wx " + str(wxversion.getInstalled()) print "matplotlib " + matplotlib.__version__ app = wx.App(0) window = MyFrame(None) plot = MyPlot(window.m_panel2) window.Show() app.MainLoop() 

谢谢你的帮助 :)