1

I'm trying to make an icon from a numpy array displayed with matplotlib imshow.

I succeed in getting colors from matplotlib into a numpy array of dimension (n*n*4)

I then convert this numpy array to an Qimage then into a Qpixmap in order to update the Icon of a Qpushbutton.

However the icon of the button is not set to the image I created. In fact it doesn't do anything. If I used an image from my hard-drive instead, the icon is correctly updated.

Here a sample of code :

from PyQt5.QtGui import *
from PyQt5.QtWidgets import  *
from PyQt5.QtCore import *
import numpy as np
import sys
import matplotlib.pyplot as plt 

class StimEdit(QMainWindow):
    def __init__(self, parent=None):
        super(StimEdit, self).__init__()
        self.parent = parent

        self.centralWidget = QWidget()
        self.color = self.centralWidget.palette().color(QPalette.Background)
        self.setCentralWidget(self.centralWidget)
        self.mainHBOX_param_scene = QHBoxLayout()

        self.B = QPushButton('')
        self.B.setFixedSize(100,100)
        self.B.clicked.connect(self.updateicon)
        self.mainHBOX_param_scene.addWidget(self.B)
        self.centralWidget.setLayout(self.mainHBOX_param_scene)


    def updateicon(self):
        CM = np.random.random((10,10))
        ax = plt.imshow(CM)
        colours = (ax.cmap(ax.norm( CM )) * 255).astype(np.uint8)
        ncols, nrows, ncolors = colours.shape
        # image = QImage(colours.tostring(),ncols, nrows, ncolors,QImage.Format_RGBA8888)
        image = QImage(colours[:,:,:3].tostring(),ncols, nrows, ncolors-1,QImage.Format_RGB888)
        rMyIcon = QPixmap(image)
        self.B.setIcon(QIcon(rMyIcon))
        self.B.setIconSize(QSize(100, 100))
        self.parent.processEvents()


def main():
    app = QApplication(sys.argv)
    ex = StimEdit(app)
    ex.show()
    sys.exit(app.exec_( ))


if __name__ == '__main__':
    main()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
ymmx
  • 4,769
  • 5
  • 32
  • 64

1 Answers1

3

You have to copy the numpy array and using a previous answer you get the following

def updateicon(self):
    size = QSize(100, 100)
    CM = np.random.random((10,10))
    ax = plt.imshow(CM)
    colours = (ax.cmap(ax.norm( CM )) * 255).astype(np.uint8)
    im = colours[:, :, :3].copy()
    image = QImage(im.data, im.shape[1], im.shape[0], im.strides[0], QImage.Format_RGB888)
    pixmap = QPixmap(image)
    self.B.setIcon(QIcon(pixmap.scaled(size)))
    self.B.setIconSize(size)

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I think I didn't understand why we need to make a copy of the matrix to make it works. – ymmx Mar 28 '19 at 17:36
  • @ymmx If you realize your matrix has a dimension of size 4, so in memory there are no matrices but the data is linked, for example a 2x2 matrix: [[a, b], [c, d]] in memory could be a, c, b, d, now imagine a 3-dimensional matrix, although you want to copy data this is intertwined with the 4th dimension that you want to omit – eyllanesc Mar 28 '19 at 17:52
  • But when I do `colours[:, :, :3]`, as I only take a slice of the array, I should have a copy of it directly, right? Maybe np.array are different than list then? – ymmx Mar 29 '19 at 06:39
  • @ymmx the `colours[:, :, :3].data` does not copy the value but gives us the memory position – eyllanesc Mar 29 '19 at 06:41
  • Okay, It seems I still have a lot to learn. Thanks for your time. – ymmx Mar 29 '19 at 07:17