#!/usr/bin/env python import sys from qt import * from Qwt4.Qwt import * from Qwt4.anynumpy import * # from scipy.pilutil def bytescale(data, cmin=None, cmax=None, high=255, low=0): if ((hasattr(data, 'dtype') and data.dtype.char == UInt8) or (hasattr(data, 'typecode') and data.typecode == UInt8) ): return data high = high - low if cmin is None: cmin = min(ravel(data)) if cmax is None: cmax = max(ravel(data)) scale = high * 1.0 / (cmax-cmin or 1) bytedata = ((data*1.0-cmin)*scale + 0.4999).astype(UInt8) return bytedata + asarray(low).astype(UInt8) # bytescale() def linearX(nx, ny): return repeat(arange(nx, typecode = Float32)[:, NewAxis], ny, -1) # linearX() def linearY(nx, ny): return repeat(arange(ny, typecode = Float32)[NewAxis, :], nx, 0) # linearY() def square(n, min, max): t = arange(min, max, float(max-min)/(n-1)) #return outer(cos(t), sin(t)) return cos(t)*sin(t)[:,NewAxis] # square() class QwtPlotImage(QwtPlotMappedItem): def __init__(self, parent): QwtPlotItem.__init__(self, parent) self.xyzs = None self.plot = parent # __init__() def setData(self, xyzs, xScale = None, yScale = None): self.xyzs = xyzs shape = xyzs.shape if xScale: self.xMap = QwtDiMap(0, shape[0], xScale[0], xScale[1]) self.plot.setAxisScale(QwtPlot.xBottom, *xScale) else: self.xMap = QwtDiMap(0, shape[0], 0, shape[0]) self.plot.setAxisScale(QwtPlot.xBottom, 0, shape[0]) if yScale: self.yMap = QwtDiMap(0, shape[1], yScale[0], yScale[1]) self.plot.setAxisScale(QwtPlot.yLeft, *yScale) else: self.yMap = QwtDiMap(0, shape[1], 0, shape[1]) self.plot.setAxisScale(QwtPlot.yLeft, 0, shape[1]) self.image = toQImage(bytescale(self.xyzs)).mirror(0, 1) for i in range(0, 256): self.image.setColor(i, qRgb(i, 0, 255-i)) # setData() def drawImage(self, painter, xMap, yMap): """Paint image to zooming to xMap, yMap Calculate (x1, y1, x2, y2) so that it contains at least 1 pixel, and copy the visible region to scale it to the canvas. """ # calculate y1, y2 # the scanline order (index y) is inverted with respect to the y-axis y1 = y2 = self.image.height() y1 *= (self.yMap.d2() - yMap.d2()) y1 /= (self.yMap.d2() - self.yMap.d1()) y1 = max(0, int(y1-0.5)) y2 *= (self.yMap.d2() - yMap.d1()) y2 /= (self.yMap.d2() - self.yMap.d1()) y2 = min(self.image.height(), int(y2+0.5)) # calculate x1, x2 -- the pixel order (index x) is normal x1 = x2 = self.image.width() x1 *= (xMap.d1() - self.xMap.d1()) x1 /= (self.xMap.d2() - self.xMap.d1()) x1 = max(0, int(x1-0.5)) x2 *= (xMap.d2() - self.xMap.d1()) x2 /= (self.xMap.d2() - self.xMap.d1()) x2 = min(self.image.width(), int(x2+0.5)) # copy image = self.image.copy(x1, y1, x2-x1, y2-y1) # zoom image = image.smoothScale(xMap.i2()-xMap.i1()+1, yMap.i1()-yMap.i2()+1) # draw painter.drawImage(xMap.i1(), yMap.i2(), image) # drawImage() # class QwtPlotImage class QwtImagePlot(QwtPlot): def __init__(self, *args): QwtPlot.__init__(self, *args) # make a QwtPlot widget self.plotLayout().setMargin(0) self.plotLayout().setCanvasMargin(0) self.plotLayout().setAlignCanvasToScales(1) self.setTitle('QwtImagePlot: (un)zoom & (un)hide') self.setAutoLegend(1) self.setLegendPos(Qwt.Right) # set axis titles self.setAxisTitle(QwtPlot.xBottom, 'time (s)') self.setAxisTitle(QwtPlot.yLeft, 'frequency (Hz)') # insert a few curves cSin = self.insertCurve('y = pi*sin(x)') cCos = self.insertCurve('y = 4*pi*sin(x)*cos(x)**2') # set curve styles self.setCurvePen(cSin, QPen(Qt.green, 2)) self.setCurvePen(cCos, QPen(Qt.black, 2)) # calculate 3 NumPy arrays x = arange(-2*pi, 2*pi, 0.01) y = pi*sin(x) z = 4*pi*cos(x)*cos(x)*sin(x) # copy the data self.setCurveData(cSin, x, y) self.setCurveData(cCos, x, z) # insert a horizontal marker at y = 0 mY = self.insertLineMarker('y = 0', QwtPlot.yLeft) self.setMarkerYPos(mY, 0.0) # insert a vertical marker at x = pi mX = self.insertLineMarker('x = pi', QwtPlot.xBottom) self.setMarkerXPos(mX, pi) # image self.plotImage = QwtPlotImage(self) #self.plotImage.setData(bytescale(linearX(512, 512)+linearY(512, 512))) self.plotImage.setData( square(512,-2*pi, 2*pi), (-2*pi, 2*pi), (-2*pi, 2*pi)) self.zoomStack = [] self.connect(self, SIGNAL('plotMouseMoved(const QMouseEvent&)'), self.onMouseMoved) self.connect(self, SIGNAL('plotMousePressed(const QMouseEvent&)'), self.onMousePressed) self.connect(self, SIGNAL('plotMouseReleased(const QMouseEvent&)'), self.onMouseReleased) self.connect(self, SIGNAL("legendClicked(long)"), self.toggleCurve) # replot self.replot() # __init__() def drawCanvasItems(self, painter, rectangle, maps, filter): self.plotImage.drawImage( painter, maps[QwtPlot.xBottom], maps[QwtPlot.yLeft]) QwtPlot.drawCanvasItems(self, painter, rectangle, maps, filter) # drawCanvasItems() def onMouseMoved(self, e): pass # onMouseMoved() def onMousePressed(self, e): if Qt.LeftButton == e.button(): # Python semantics: self.pos = e.pos() does not work; force a copy self.xpos = e.pos().x() self.ypos = e.pos().y() self.enableOutline(1) self.setOutlinePen(QPen(Qt.black)) self.setOutlineStyle(Qwt.Rect) self.zooming = 1 if self.zoomStack == []: self.zoomState = ( self.axisScale(QwtPlot.xBottom).lBound(), self.axisScale(QwtPlot.xBottom).hBound(), self.axisScale(QwtPlot.yLeft).lBound(), self.axisScale(QwtPlot.yLeft).hBound(), ) elif Qt.RightButton == e.button(): self.zooming = 0 # fake a mouse move to show the cursor position self.onMouseMoved(e) # onMousePressed() def onMouseReleased(self, e): if Qt.LeftButton == e.button(): xmin = min(self.xpos, e.pos().x()) xmax = max(self.xpos, e.pos().x()) ymin = min(self.ypos, e.pos().y()) ymax = max(self.ypos, e.pos().y()) self.setOutlineStyle(Qwt.Cross) xmin = self.invTransform(QwtPlot.xBottom, xmin) xmax = self.invTransform(QwtPlot.xBottom, xmax) ymin = self.invTransform(QwtPlot.yLeft, ymin) ymax = self.invTransform(QwtPlot.yLeft, ymax) if xmin == xmax or ymin == ymax: return self.zoomStack.append(self.zoomState) self.zoomState = (xmin, xmax, ymin, ymax) self.enableOutline(0) elif Qt.RightButton == e.button(): if len(self.zoomStack): xmin, xmax, ymin, ymax = self.zoomStack.pop() else: return self.setAxisScale(QwtPlot.xBottom, xmin, xmax) self.setAxisScale(QwtPlot.yLeft, ymin, ymax) self.replot() # onMouseReleased() def toggleCurve(self, key): curve = self.curve(key) if curve: curve.setEnabled(not curve.enabled()) self.replot() # toggleCurve() # class QwtImagePlot def make(): demo = QwtImagePlot() demo.resize(500, 300) demo.show() return demo # make() def main(args): app = QApplication(args) demo = make() app.setMainWidget(demo) app.exec_loop() # main() # Admire if __name__ == '__main__': main(sys.argv)