1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
import math
import numpy as np
from .. import functions as fn
from .. import mkBrush, mkPen
from ..colormap import ColorMap
from ..Qt import QtCore, QtGui
from .GraphicsObject import GraphicsObject
__all__ = ['NonUniformImage']
class NonUniformImage(GraphicsObject):
"""
**Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>`
GraphicsObject displaying an image with non-uniform sample points. It's
commonly used to display 2-d or slices of higher dimensional data that
have a regular but non-uniform grid e.g. measurements or simulation results.
"""
def __init__(self, x, y, z, border=None):
GraphicsObject.__init__(self)
# convert to numpy arrays
x = np.asarray(x, dtype=np.float64)
y = np.asarray(y, dtype=np.float64)
z = np.asarray(z, dtype=np.float64)
if x.ndim != 1 or y.ndim != 1:
raise Exception("x and y must be 1-d arrays.")
if np.any(np.diff(x) < 0) or np.any(np.diff(y) < 0):
raise Exception("The values in x and y must be monotonically increasing.")
if len(z.shape) != 2 or z.shape != (x.size, y.size):
raise Exception("The length of x and y must match the shape of z.")
# default colormap (black - white)
self.cmap = ColorMap(pos=[0.0, 1.0], color=[(0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0, 1.0)])
self.data = (x, y, z)
self.lut = None
self.border = border
self.generatePicture()
def setLookupTable(self, lut, autoLevel=False):
lut.sigLevelsChanged.connect(self.generatePicture)
lut.gradient.sigGradientChanged.connect(self.generatePicture)
self.lut = lut
if autoLevel:
_, _, z = self.data
f = z[np.isfinite(z)]
lut.setLevels(f.min(), f.max())
self.generatePicture()
def setColorMap(self, cmap):
self.cmap = cmap
self.generatePicture()
def getHistogram(self, **kwds):
"""Returns x and y arrays containing the histogram values for the current image.
For an explanation of the return format, see numpy.histogram().
"""
z = self.data[2]
z = z[np.isfinite(z)]
hist = np.histogram(z, **kwds)
return hist[1][:-1], hist[0]
def generatePicture(self):
x, y, z = self.data
self.picture = QtGui.QPicture()
p = QtGui.QPainter(self.picture)
p.setPen(mkPen(None))
# normalize
if self.lut is not None:
mn, mx = self.lut.getLevels()
else:
f = z[np.isfinite(z)]
mn = f.min()
mx = f.max()
# draw the tiles
for i in range(x.size):
for j in range(y.size):
value = z[i, j]
if np.isneginf(value):
value = 0.0
elif np.isposinf(value):
value = 1.0
elif math.isnan(value):
continue # ignore NaN
else:
value = (value - mn) / (mx - mn) # normalize
if self.lut:
color = self.lut.gradient.getColor(value)
else:
color = self.cmap.mapToQColor(value)
p.setBrush(mkBrush(color))
# left, right, bottom, top
l = x[0] if i == 0 else (x[i - 1] + x[i]) / 2
r = (x[i] + x[i + 1]) / 2 if i < x.size - 1 else x[-1]
b = y[0] if j == 0 else (y[j - 1] + y[j]) / 2
t = (y[j] + y[j + 1]) / 2 if j < y.size - 1 else y[-1]
p.drawRect(QtCore.QRectF(l, t, r - l, b - t))
if self.border is not None:
p.setPen(self.border)
p.setBrush(fn.mkBrush(None))
p.drawRect(self.boundingRect())
p.end()
self.update()
def paint(self, p, *args):
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
return QtCore.QRectF(self.picture.boundingRect())
|