将 matplotlib 图形复制到具有更高分辨率的 QClipboard

Posted

技术标签:

【中文标题】将 matplotlib 图形复制到具有更高分辨率的 QClipboard【英文标题】:Copy matplotlib figure to QClipboard with increased resolution 【发布时间】:2018-05-07 02:10:25 【问题描述】:

在 pyQt 应用程序中,我将 matplotlib 图形 (self.canvas) 复制到使用任一方法的 QClipboard 实例中

cb = QClipboard(self)
img = QImage(self.canvas.grab())
cb.setImage(img)

img = QPixmap(self.canvas.grab())
self.cb.setPixmap(img)

两者都运行良好,但是我无法控制导出图像的分辨率。这可以通过创建和导出一个临时文件来实现,但是,由于文件系统的限制,这很慢并且有潜在的问题:

self.canvas.figure.savefig(self.temp_file, dpi = 300, type = 'png')
temp_img = QImage(self.temp_file)
cb.setImage(temp_img)

那么,有没有办法在不绕道文件系统的情况下设置复制图像的分辨率?

--------------------------

编辑:我刚刚发现上面在pyqt4下不起作用。相反,您可以使用

img = QPixmap.grabWidget(self.canvas)
self.cb.setPixmap(img)

--------------------------

编辑:另一个几乎可行的解决方案是以下代码,不幸的是它改变了颜色(回到 matplotlib 默认值?):

# construct image from raw rgba data, this changes the colormap:
size = self.canvas.size()
width, height = size.width(), size.height()
im = QImage(self.canvas.buffer_rgba(), width, height, QImage.Format_ARGB32)
self.cb.setImage(im)

【问题讨论】:

【参考方案1】:

以下是不完整的答案。因此,仍然欢迎提供进一步的答案,制作完整或替代解决方案。

您可以不将图像保存到磁盘,而是将其保存到文件缓冲区并从那里读取。但是,将缓冲区直接读入QImage 可能很困难。有人问过here,但答案使用了一种解决方法,首先将文件保存到磁盘。这是不希望的。

相反,您可以将数字以 numpy 数组的形式读入QImage。 这可能涉及到

的步骤
    将具有所需分辨率的图形保存到缓冲区,然后读取缓冲区并从中创建一个 numpy 数组。这在这个问题中得到解决: How can I render a Matplotlib Axes object to an image (as a Numpy array)? 从 numpy 数组创建 QImage。这个问题解决了这个问题:How to set an numpy array image on a QWidget using PyQt5 和Convert 16-bit grayscale to QImage

不幸的是,我目前无法正确显示 RGB 数组,但以下是将图形显示为灰度图像的解决方案:

import io
import sys
from PyQt4 import QtGui
import matplotlib.pyplot as plt
import numpy as np

def get_image():
    plt.plot([1,3,2])
    buff = io.BytesIO()
    plt.savefig(buff, format="png", dpi=100)
    buff.seek(0)
    img = plt.imread(buff)
    return img


class App(QtGui.QWidget):

    def __init__(self):
        super(App, self).__init__()
        self.setGeometry(300, 300, 250, 150)
        self.setLayout(QtGui.QVBoxLayout())
        label = QtGui.QLabel()
        label2 = QtGui.QLabel("Some other text label") 

        img = get_image()

        im = img.mean(axis=2)
        im = ((im - im.min()) / (im.ptp() / 255.0)).astype(np.uint8)
        print im.shape, im.max(), im.min()
        temp_img = QtGui.QImage(im,im.shape[1],im.shape[0],im.shape[1], QtGui.QImage.Format_Indexed8)
        pixmap = QtGui.QPixmap(temp_img)
        label.setPixmap(pixmap)

        self.layout().addWidget(label)
        self.layout().addWidget(label2)
        self.show()


if __name__ == '__main__':
    app = QtGui.QApplication([])
    ex = App()
    sys.exit(app.exec_())

【讨论】:

将图像显示为 RGB 的剩余步骤可能很小,但我无法使用 RGB 值。因此,非常欢迎任何有关如何使用 RGB 值进行这项工作的见解(请随意使用上述代码获取另一个答案或编辑此答案)。 非常感谢您的支持,但恐怕解决方案对我的需求来说太复杂了……我会继续使用我的两班轮船。在搜索网络时,我还发现下一个 matplotlib 版本之一将向 NavigationToolbar 添加“复制到剪贴板”功能。我曾尝试过类似于您的解决方案,但是颜色不同 - 请参阅我的问题的编辑。

以上是关于将 matplotlib 图形复制到具有更高分辨率的 QClipboard的主要内容,如果未能解决你的问题,请参考以下文章

matplotlib 设置图形大小时 figsize 与 dpi 的关系

如何使用matplotlib创建具有连续轴的图形?

matplotlib - 提高分辨率以查看细节

matplotlib 中的 figsize 不会改变图形大小? [复制]

如何在 Matplotlib 的子图中独立绘制相同的图形? [复制]

matplotlib 可以将元数据添加到保存的图形中吗?