Matplotlib/PyQT4:透明图 [英] Matplotlib / PyQT4: transparent figure

查看:46
本文介绍了Matplotlib/PyQT4:透明图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 PyQt4 中使用 Python,并且我想在 GUI 中嵌入一个 matplotlib 图.对我来说重要的是 Figure 的背景与 GUI 的背景颜色匹配.(实际情节周围没有灰色背景)

我的部分解决方案是使用以下代码使 Figure 透明:

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

这在pylab模式下进行绘制时效果很好,但是在PyQt4中嵌入时,重新渲染并不能清除旧图,而是在上面加上我给出的透明度.如下面的示例所示,这是调整窗口大小的结果:

该示例是使用matplotlib网站上的代码并添加MyMplCanvas 的 __init__ 语句中的 >set_alpha(0.5) 行.

您已经在 matplotlib 中发现了一个有趣的错误.Qt4 后端不会清除它用于在重绘之前显示图形的 qImage,因此您会看到阴影.只需在 matplotlib.backends.backed_qt4Agg.FigureCanvasQTAgg.paintEvent

中添加几行,即可轻松解决此问题

defpaintEvent(self, e):"""将图像从 Agg 画布复制到 qt.drawable.在Qt中,当一个小部件是显示在屏幕上."""#FigureCanvasQT.paintEvent(self,e)如果调试:打印('FigureCanvasQtAgg.paintEvent:',自我,self.get_width_height())如果self.blitbox为None:#matplotlib是rgba字节顺序.QImage想放字节#转换为argb格式,格式为4字节无符号int.小端# 系统是 LSB 优先,并期望字节顺序相反#(bgra).如果 QtCore.QSysInfo.ByteOrder == QtCore.QSysInfo.LittleEndian:stringBuffer = self.renderer._renderer.tostring_bgra()别的: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() ### <-- 添加了这一行p = QtGui.QPainter(自己)p.eraseRect(rect)###<-添加了这一行p.drawPixmap(QtCore.QPoint(0,0),QtGui.QPixmap.fromImage(qImage))#将缩放矩形绘制到QPainter如果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()#可以解决Python 3.x上PySide 1.1.2中的一个错误,# stringBuffer 的引用计数增加的地方# 但从未被 QImage 递减.# TODO:一旦问题在 PySide 中得到修复,就恢复 PR #1323.删除 qImage如果refcnt!= sys.getrefcount(stringBuffer):_decref(stringBuffer)别的:bbox = self.blitboxl, b, r, t = bbox.extentsw = int(r)-int(l)h = int(t) - int(b)t = int(b)+ hreg = 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 =无self.drawRect =假

差异形式的更改:

  diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py索引 8433731..718d352 100644--- a/lib/matplotlib/backends/backend_qt4agg.py+++ b/lib/matplotlib/backends/backend_qt4agg.py@@ -118,7 +118,9 @@类FigureCanvasQTAgg(FigureCanvasQT,FigureCanvasAgg):qImage = QtGui.QImage(stringBuffer, self.renderer.width,self.renderer.height,QtGui.QImage.Format_ARGB32)+ rect = qImage.rect()p = QtGui.QPainter(自己)+ p.eraseRect(rect)p.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap.fromImage(qImage))# 将缩放矩形绘制到 QPainter

您可以修改本地安装或在代码中修补它.

PR#2449 ,该文件已合并并位于1.3.1版中

I am using Python with PyQt4 and I want to embed a matplotlib figure in the GUI. What's important to me, is that the background of the Figure matches the background color of the GUI. (no grey background around the actual plot)

My partial solution would be to make the Figure transparent with the following code:

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

解决方案

You have found an interesting bug in matplotlib. The Qt4 backend does not clear the qImage it uses to display the figure before redrawing, hence the reason you see the shadows. This is easily fixed by adding a few lines to 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

这篇关于Matplotlib/PyQT4:透明图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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