简体   繁体   English

Matplotlib / PyQT4:透明图

[英]Matplotlib / PyQT4: transparent figure

I am using Python with PyQt4 and I want to embed a matplotlib figure in the GUI. 我在PyQt4中使用Python,我想在GUI中嵌入一个matplotlib图。 What's important to me, is that the background of the Figure matches the background color of the GUI. 对我来说重要的是, Figure的背景与GUI的背景颜色相匹配。 (no grey background around the actual plot) (实际情节周围没有灰色背景)

My partial solution would be to make the Figure transparent with the following code: 我的部分解决方案是使用以下代码使Figure透明:

...
fig.patch.set_alpha(0.5)
...

This works fine when plotting in pylab mode, but when embedding in PyQt4, the re-rendering doesn't clear the old figure, but adds it with on top with transparency I give. 这在pylab模式下绘图时效果很好,但是当在PyQt4中嵌入时,重新渲染不会清除旧图形,而是将其添加到我给出的透明度的顶部。 As seen in the sample below, which is the result of resizing the window: 如下面的示例所示,这是调整窗口大小的结果:

没有工作样本

The sample was produced using the code from the matplotlib website with adding the set_alpha(0.5) line in the __init__ statement of MyMplCanvas . 将样品使用所产生的从matplotlib网站码与添加set_alpha(0.5)在管线__init__的语句MyMplCanvas

You have found an interesting bug in matplotlib . 您在matplotlib发现了一个有趣的错误。 The Qt4 backend does not clear the qImage it uses to display the figure before redrawing, hence the reason you see the shadows. Qt4后端不会清除重绘前用于显示图形的qImage ,因此您可以看到阴影的原因。 This is easily fixed by adding a few lines to matplotlib.backends.backed_qt4Agg.FigureCanvasQTAgg.paintEvent 通过向matplotlib.backends.backed_qt4Agg.FigureCanvasQTAgg.paintEvent添加几行可以很容易地解决这个问题。

def paintEvent(self, e):
    """
    Copy the image from the Agg canvas to the qt.drawable.
    In Qt, all drawing should be done inside of here when a widget is
    shown onscreen.
    """

    #FigureCanvasQT.paintEvent(self, e)
    if DEBUG:
        print('FigureCanvasQtAgg.paintEvent: ', self,
            self.get_width_height())

    if self.blitbox is None:
        # matplotlib is in rgba byte order.  QImage wants to put the bytes
        # into argb format and is in a 4 byte unsigned int.  Little endian
        # system is LSB first and expects the bytes in reverse order
        # (bgra).
        if QtCore.QSysInfo.ByteOrder == QtCore.QSysInfo.LittleEndian:
            stringBuffer = self.renderer._renderer.tostring_bgra()
        else:
            stringBuffer = self.renderer._renderer.tostring_argb()

        refcnt = sys.getrefcount(stringBuffer)

        qImage = QtGui.QImage(stringBuffer, self.renderer.width,
                              self.renderer.height,
                              QtGui.QImage.Format_ARGB32)
        rect = qImage.rect()    ### <-- added this line
        p = QtGui.QPainter(self)
        p.eraseRect(rect)       ### <-- added this line
        p.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap.fromImage(qImage))

        # draw the zoom rectangle to the QPainter
        if self.drawRect:
            p.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.DotLine))
            p.drawRect(self.rect[0], self.rect[1],
                       self.rect[2], self.rect[3])
        p.end()

        # This works around a bug in PySide 1.1.2 on Python 3.x,
        # where the reference count of stringBuffer is incremented
        # but never decremented by QImage.
        # TODO: revert PR #1323 once the issue is fixed in PySide.
        del qImage
        if refcnt != sys.getrefcount(stringBuffer):
            _decref(stringBuffer)
    else:
        bbox = self.blitbox
        l, b, r, t = bbox.extents
        w = int(r) - int(l)
        h = int(t) - int(b)
        t = int(b) + h
        reg = self.copy_from_bbox(bbox)
        stringBuffer = reg.to_string_argb()
        qImage = QtGui.QImage(stringBuffer, w, h,
                              QtGui.QImage.Format_ARGB32)
        pixmap = QtGui.QPixmap.fromImage(qImage)
        p = QtGui.QPainter(self)
        p.drawPixmap(QtCore.QPoint(l, self.renderer.height-t), pixmap)
        p.end()
        self.blitbox = None
    self.drawRect = False

Changes in diff form: 差异形式的变化:

diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py
index 8433731..718d352 100644
--- a/lib/matplotlib/backends/backend_qt4agg.py
+++ b/lib/matplotlib/backends/backend_qt4agg.py
@@ -118,7 +118,9 @@ class FigureCanvasQTAgg(FigureCanvasQT, FigureCanvasAgg):
             qImage = QtGui.QImage(stringBuffer, self.renderer.width,
                                   self.renderer.height,
                                   QtGui.QImage.Format_ARGB32)
+            rect = qImage.rect()
             p = QtGui.QPainter(self)
+            p.eraseRect(rect)
             p.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap.fromImage(qImage))

             # draw the zoom rectangle to the QPainter

You can either modify your local installation or monkey patch it in your code. 您可以修改本地安装,也可以在代码中修补它。

PR #2449 which has been merged and will be in 1.3.1 PR#2449已合并,将在1.3.1中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM