Latest Update 3/29/2016:
If you copy paste the below code you should get a pyqt app with a button. If you click it you get a grayscale added to the ViewBox. If you rewrite where ARR_OFF
is declared so that ARR = plt.cm.jet(norm(ARR))
then you get the error I am suffering from. I want to display ARR
as a colourmap in the ViewBox, hence I transform it to a RGBA array.
import os, sys, matplotlib, matplotlib.pyplot
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets.GraphicsLayoutWidget import GraphicsLayoutWidget
import pyqtgraph as pg
import pyqtgraph.functions as fn
import matplotlib.pyplot as plt
N = 256
ARR = np.random.random((N,N))*255
norm = plt.Normalize()
ARR_OFF = plt.cm.jet(norm(ARR))
# Change ARR_OFF to ARR to see my problem
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUserInterface()
self.setupSignals()
def setupUserInterface(self):
""" Initialise the User Interface """
# Left frame
leftFrame = QtGui.QFrame()
leftFrameLayout = QtGui.QHBoxLayout()
leftFrame.setLayout(leftFrameLayout)
leftFrame.setLineWidth(0)
leftFrame.setFrameStyle(QtGui.QFrame.Panel)
leftFrameLayout.setContentsMargins(0,0,5,0)
# Left frame contents
self.viewMain = GraphicsLayoutWidget() # A GraphicsLayout within a GraphicsView
leftFrameLayout.addWidget(self.viewMain)
self.viewMain.setMinimumSize(200,200)
self.vb = MultiRoiViewBox(lockAspect=True,enableMenu=True)
self.viewMain.addItem(self.vb)
self.vb.enableAutoRange()
# Right frame
self.sidePanel = SidePanel(self)
# UI window (containing left and right frames)
UIwindow = QtGui.QWidget(self)
UIwindowLayout = QtGui.QHBoxLayout()
UIwindowSplitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
UIwindowLayout.addWidget(UIwindowSplitter)
UIwindow.setLayout(UIwindowLayout)
self.setCentralWidget(UIwindow)
UIwindowSplitter.addWidget(leftFrame)
UIwindowSplitter.addWidget(self.sidePanel)
self.setMinimumSize(600,500)
self.resize(self.minimumSize())
def setupSignals(self):
""" Setup signals """
self.sidePanel.buttImageAdd.clicked.connect(self.showImage)
def showImage(self,imageFilename):
""" Shows image in main view """
self.vb.showImage(ARR)
class ViewMode():
def __init__(self,id,cmap):
self.id = id
self.cmap = cmap
self.getLookupTable()
def getLookupTable(self):
lut = [ [ int(255*val) for val in self.cmap(i)[:3] ] for i in xrange(256) ]
lut = np.array(lut,dtype=np.ubyte)
self.lut = lut
class MultiRoiViewBox(pg.ViewBox):
def __init__(self,parent=None,border=None,lockAspect=False,enableMouse=True,invertY=False,enableMenu=True,name=None):
pg.ViewBox.__init__(self,parent,border,lockAspect,enableMouse,invertY,enableMenu,name)
self.img = None
self.NORMAL = ViewMode(0,matplotlib.cm.gray)
self.DEXA = ViewMode(1,matplotlib.cm.jet)
self.viewMode = self.NORMAL
def showImage(self,arr):
if arr==None:
self.img = None
return
if self.img==None:
self.img = pg.ImageItem(arr,autoRange=False,autoLevels=False)
self.addItem(self.img)
self.img.setImage(arr,autoLevels=False)
self.updateView()
def updateView(self):
self.background.setBrush(fn.mkBrush(self.viewMode.lut[0]))
self.background.show()
if self.img==None: return
else: self.img.setLookupTable(self.viewMode.lut)
from pyqtgraph.Qt import QtCore,QtGui
class SidePanel(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self,parent)
self.setMinimumWidth(250)
self.buttMinimumSize = QtCore.QSize(36,36)
self.setupImageToolbox()
sidePanelLayout = QtGui.QVBoxLayout()
sidePanelLayout.addWidget(self.imageToolbox)
sidePanelLayout.setContentsMargins(0,0,0,0)
self.setLayout(sidePanelLayout)
def setupImageToolbox(self):
# Image buttons
self.buttImageAdd = QtGui.QPushButton()
imageButtons = [self.buttImageAdd]
for i in xrange(len(imageButtons)):
image = imageButtons[i]
image.setMinimumSize(self.buttMinimumSize)
self.imageFileTools = QtGui.QFrame()
imageFileToolsLayout = QtGui.QHBoxLayout()
self.imageFileTools.setLayout(imageFileToolsLayout)
self.imageFileTools.setLineWidth(1)
self.imageFileTools.setFrameStyle(QtGui.QFrame.StyledPanel)
imageFileToolsLayout.addWidget(self.buttImageAdd)
# Image Toolbox (containing imageFileList + imageFileList buttons)
self.imageToolbox = QtGui.QFrame()
self.imageToolbox.setLineWidth(2)
self.imageToolbox.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
imageToolboxLayout = QtGui.QVBoxLayout()
self.imageToolbox.setLayout(imageToolboxLayout)
imageToolboxLayout.addWidget(self.imageFileTools)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Notes and References for your convenience
- plt.cm.jet
- I know ImageView, which contains the ViewBox for the ImageItem does indeed support RGBA
- Reading the ImageItem docs I see that for the setImage to work with RGBA I simply need to pass it an array with dimensions specifying the RGBA channels
(numpy array) Specifies the image data. May be 2D (width, height) or 3D (width, height, RGBa). The array dtype must be integer or floating point of any bit depth. For 3D arrays, the third dimension must be of length 3 (RGB) or 4 (RGBA).
- The traceback does not contain a line of my code. Here is what I see in my full program
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/pyqtgraph/graphicsItems/ImageItem.py", line 309, in paint
self.render()
File "/usr/lib/python2.7/dist-packages/pyqtgraph/graphicsItems/ImageItem.py", line 301, in render
argb, alpha = fn.makeARGB(image.transpose((1, 0, 2)[:image.ndim]), lut=lut, levels=self.levels)
File "/usr/lib/python2.7/dist-packages/pyqtgraph/functions.py", line 976, in makeARGB
imgData[..., i] = data[..., order[i]]
ValueError: could not broadcast input array from shape (256,256,4) into shape (256,256)
The pyqt app doesn't crash and remains responsive to other actions after this error traceback. My ViewBox just remains dark though
In the dubug console in
showImage
just before the call toupdateView
I have the following which seems to indicate all is in order.
>>> self.img <pyqtgraph.graphicsItems.ImageItem.ImageItem object at 0x7fc7140dbd60> >> arr.ndim 3
- This makes me think that the problem is in
updateView
. But all lines here are calling built-in pyqtgraph functions. - Here additionally are what I get in the debug console just before the call to
setLookupTable
>>> fn <module 'pyqtgraph.functions' from '/usr/lib/python2.7/dist-packages/pyqtgraph/functions.pyc'> >>> self.viewMode.lut[0] array([0, 0, 0], dtype=uint8)
- Lastly, here is a screenshot of my full app in case that helps you see something I don't. Note of course that is is working for a grayscale. I owe a great deal to Micheal Hogg for letting me modify his code for my purposes.