matplotlib和wxpython的透明度问题

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

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

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

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

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

如果您抓住窗口的一个角并摇动它几次调整大小,则蓝色通常是可见的。 我立即调整目标,而不是等待窗口闲置。

请取消注释代码中的指示行,以查看我可能没有清楚解释的内容。

我的配置: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()
    

    谢谢你的帮助 :)

    链接地址: http://www.djcxy.com/p/37899.html

    上一篇: Transparency issue with matplotlib and wxpython

    下一篇: Get colors of current gtk style