3

In a pyQt application, I'm copying matplotlib figures (self.canvas) to a QClipboard instance using either

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

or

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

Both work well, however, I haven't managed to control the resolution of the exported image. This would be possible by creating and exporting a temporary file, however, this is slow and has potential problems due to file system restrictions:

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

So, is there a way to set the resolution of the copied image without taking a detour through the file system?

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

Edit: I just found out that the above doesn't work under pyqt4. Instead, you can use

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

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

Edit: Another solution that nearly works is the following piece of code, unfortunately it changes the colors (back to matplotlib defaults?):

# 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)
Chipmuenk
  • 607
  • 1
  • 7
  • 22

1 Answers1

0

The following is an incomplete answer. So further answers, making this complete or alternative solutions are still welcome.

You may, instead of saving the image to disk, save it to a filebuffer and read it from there. However, reading a buffer directly into QImage may be hard. This was asked here, but the answer uses a workaround to save the file to disk first. This is undesired here.

Instead, you may read the figure in terms of a numpy array into the QImage. This may involve the steps of

  1. Saving the figure with the desired resolution to a buffer, then reading the buffer and creating a numpy array out of it. This is tackled in this question: How can I render a Matplotlib Axes object to an image (as a Numpy array)?
  2. Creating a QImage from a numpy array. This is tackled in this question: How to set an numpy array image on a QWidget using PyQt5 and also Convert 16-bit grayscale to QImage

Unfortunately I am currently unable to get the RGB array to show correctly, but the following would the solution to showing the figure as Greyscale image:

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_())
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • The remaining step of showing the image as RGB may be small one, but I was not able to use RGB values. So any insights on how to make this work with RGB values are very welcome (feel free to use the above code for another answer or to edit this answer). – ImportanceOfBeingErnest Nov 23 '17 at 10:28
  • Thanx a lot for your support, but I'm afraid that solution is too complicated for my needs ... I'll stay with my two-liner. while searching the web I also found that one of the next matplotlib releases will add a "copy to clipboard" functionality to the NavigationToolbar. I had tried a solution similar to yours, however the colors came out differently - see the edit to my question. – Chipmuenk Nov 24 '17 at 12:04