diff --git a/doc/source/graphicsItems/index.rst b/doc/source/graphicsItems/index.rst index 390d8f17..119028b1 100644 --- a/doc/source/graphicsItems/index.rst +++ b/doc/source/graphicsItems/index.rst @@ -12,6 +12,7 @@ Contents: plotdataitem plotitem imageitem + pcolormeshitem graphitem viewbox linearregionitem diff --git a/doc/source/graphicsItems/make b/doc/source/graphicsItems/make index 9d9f9954..df8dd10d 100644 --- a/doc/source/graphicsItems/make +++ b/doc/source/graphicsItems/make @@ -11,6 +11,7 @@ GraphicsWidget GridItem HistogramLUTItem ImageItem +pColorMeshItem InfiniteLine LabelItem LinearRegionItem diff --git a/examples/pColorMeshItem.py b/examples/pColorMeshItem.py new file mode 100644 index 00000000..15884dd2 --- /dev/null +++ b/examples/pColorMeshItem.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +""" +Demonstrates very basic use of pColorMeshItem +""" + +## Add path to library (just for examples; you do not need this) +import initExample + +from pyqtgraph.Qt import QtCore, QtGui +import numpy as np +import pyqtgraph as pg +import pyqtgraph.ptime as ptime + +app = QtGui.QApplication([]) + +## Create window with GraphicsView widget +win = pg.GraphicsLayoutWidget() +win.show() ## show widget alone in its own window +win.setWindowTitle('pyqtgraph example: pColorMeshItem') +view = win.addViewBox() + + +## Create data +x = np.array([[1,1,1,1], + [2,2,2,2], + [3,3,3,3], + [4,4,4,4], + [5,5,5,5]]) +y = np.array([[4,8,12,16], + [2,4,6,8], + [3,6,9,12], + [5,10,15,20], + [6,12,18,24]]) +z = np.array([[1,2,3], + [5,6,7], + [9,10,11], + [13,14,15]]) + +## Create image item +pcmi = pg.pColorMeshItem(x, y, z) +view.addItem(pcmi) + + + +fps = 1 +i = 0 + +def updateData(): + global pcmi, x, y, z, i + + ## Display the data + pcmi.setData(x-i, y, z) + + QtCore.QTimer.singleShot(fps*1000, updateData) + i += 1 + print(i) + + +updateData() + +## Start Qt event loop unless running in interactive mode. +if __name__ == '__main__': + import sys + if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + QtGui.QApplication.instance().exec_() diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index bc36e891..5b50e313 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -218,6 +218,7 @@ from .graphicsItems.BarGraphItem import * from .graphicsItems.ViewBox import * from .graphicsItems.ArrowItem import * from .graphicsItems.ImageItem import * +from .graphicsItems.pColorMeshItem import * from .graphicsItems.AxisItem import * from .graphicsItems.DateAxisItem import * from .graphicsItems.LabelItem import * diff --git a/pyqtgraph/graphicsItems/pColorMeshItem.py b/pyqtgraph/graphicsItems/pColorMeshItem.py new file mode 100644 index 00000000..31fe94d2 --- /dev/null +++ b/pyqtgraph/graphicsItems/pColorMeshItem.py @@ -0,0 +1,120 @@ +from __future__ import division + +from ..Qt import QtGui, QtCore +import numpy as np +from .. import functions as fn +from .. import debug as debug +from .GraphicsObject import GraphicsObject +from ..Point import Point +from .. import getConfigOption + +try: + from collections.abc import Callable +except ImportError: + # fallback for python < 3.3 + from collections import Callable + +__all__ = ['pColorMeshItem'] + + +import matplotlib.pyplot as plt +from matplotlib.colors import Normalize + + +class pColorMeshItem(GraphicsObject): + """ + **Bases:** :class:`GraphicsObject ` + + TODO + """ + + sigImageChanged = QtCore.Signal() + sigRemoveRequested = QtCore.Signal(object) # self; emitted when 'remove' is selected from context menu + + + def __init__(self, x=None, y=None, z=None, cmap=None): + """ + See :func:`setImage ` for all allowed initialization arguments. + """ + GraphicsObject.__init__(self) + + self.x = x + self.y = y + self.z = z + self.qpicture = None ## rendered image for display + + self.axisOrder = getConfigOption('imageAxisOrder') + + + if cmap is None: + self.cmap = plt.cm.viridis + + if x is not None and y is not None and z is not None: + self.setData(x, y, z) + + + def setData(self, x, y, z): + ## pre-computing a QPicture object allows paint() to run much more quickly, + ## rather than re-drawing the shapes every time. + profile = debug.Profiler() + + self.qpicture = QtGui.QPicture() + p = QtGui.QPainter(self.qpicture) + p.setPen(fn.mkPen('w')) + + xfn = z.shape[0] + yfn = z.shape[1] + + norm = Normalize(vmin=z.min(), vmax=z.max()) + for xi in range(xfn): + for yi in range(yfn): + + p.drawConvexPolygon(QtCore.QPointF(x[xi][yi], y[xi][yi]), + QtCore.QPointF(x[xi+1][yi], y[xi+1][yi]), + QtCore.QPointF(x[xi+1][yi+1], y[xi+1][yi+1]), + QtCore.QPointF(x[xi][yi+1], y[xi][yi+1])) + + c = self.cmap(norm(z[xi][yi]))[:-1] + p.setBrush(QtGui.QColor(c[0]*255, c[1]*255, c[2]*255)) + p.end() + + self.update() + + + + def paint(self, p, *args): + profile = debug.Profiler() + if self.z is None: + return + + profile('p.drawPicture') + p.drawPicture(0, 0, self.qpicture) + + + + def setBorder(self, b): + self.border = fn.mkPen(b) + self.update() + + + + def width(self): + if self.x is None: + return None + return len(self.x) + + + + def height(self): + if self.y is None: + return None + return len(self.y) + + + + + def boundingRect(self): + + if self.z is None: + return QtCore.QRectF(0., 0., 0., 0.) + return QtCore.QRectF(0., 0., float(self.width()), float(self.height())) \ No newline at end of file