#!/usr/bin/env python # Contributed by Tomaz Curk in a bug report showing that the stack order of the # curves was dependent on the number of curves. This has been fixed in Qwt. # # BarCurve is an idea of Tomaz Curk. # # Beautified and expanded by Gerard Vermeulen. # for debugging, requires: python configure.py --trace ... if False: import sip sip.settracemask(0x3f) import random import sys import PyQt4.Qt as Qt import PyQt4.Qwt5 as Qwt class Spy(Qt.QObject): def __init__(self, parent): Qt.QObject.__init__(self, parent) parent.setMouseTracking(True) parent.installEventFilter(self) # __init__() def eventFilter(self, _, event): if event.type() == Qt.QEvent.MouseMove: self.emit(Qt.SIGNAL("MouseMove"), event.pos()) return False # eventFilter() # class Spy class BarCurve(Qwt.QwtPlotCurve): def __init__(self, penColor=Qt.Qt.black, brushColor=Qt.Qt.white): Qwt.QwtPlotCurve.__init__(self) self.penColor = penColor self.brushColor = brushColor # __init__() def drawFromTo(self, painter, xMap, yMap, start, stop): """Draws rectangles with the corners taken from the x- and y-arrays. """ painter.setPen(Qt.QPen(self.penColor, 2)) painter.setBrush(self.brushColor) if stop == -1: stop = self.dataSize() # force 'start' and 'stop' to be even and positive if start & 1: start -= 1 if stop & 1: stop -= 1 start = max(start, 0) stop = max(stop, 0) for i in range(start, stop, 2): px1 = xMap.transform(self.x(i)) py1 = yMap.transform(self.y(i)) px2 = xMap.transform(self.x(i+1)) py2 = yMap.transform(self.y(i+1)) painter.drawRect(px1, py1, (px2 - px1), (py2 - py1)) # drawFromTo() # class BarCurve class BarPlotMainWindow(Qt.QMainWindow): colors = (Qt.Qt.red, Qt.Qt.green, Qt.Qt.blue, Qt.Qt.cyan, Qt.Qt.magenta, Qt.Qt.yellow, ) def __init__(self, parent=None): Qt.QMainWindow.__init__(self, parent) # Initialize a QwPlot central widget self.plot = Qwt.QwtPlot(self) self.plot.setTitle('left-click & drag to zoom') self.plot.setCanvasBackground(Qt.Qt.white) self.plot.plotLayout().setCanvasMargin(0) self.plot.plotLayout().setAlignCanvasToScales(True) self.setCentralWidget(self.plot) grid = Qwt.QwtPlotGrid() pen = Qt.QPen(Qt.Qt.DotLine) pen.setColor(Qt.Qt.black) pen.setWidth(0) grid.setPen(pen) grid.attach(self.plot) self.__initTracking() self.__initZooming() self.__initToolBar() # Finalize self.counter.setValue(10) self.go(self.counter.value()) # __init__() def __initTracking(self): """Initialize tracking """ self.connect(Spy(self.plot.canvas()), Qt.SIGNAL("MouseMove"), self.showCoordinates) self.statusBar().showMessage( 'Mouse movements in the plot canvas are shown in the status bar') # __initTracking() def showCoordinates(self, position): self.statusBar().showMessage( 'x = %+.6g, y = %.6g' % (self.plot.invTransform(Qwt.QwtPlot.xBottom, position.x()), self.plot.invTransform(Qwt.QwtPlot.yLeft, position.y()))) # showCoordinates() def __initZooming(self): """Initialize zooming """ self.zoomer = Qwt.QwtPlotZoomer(Qwt.QwtPlot.xBottom, Qwt.QwtPlot.yLeft, Qwt.QwtPicker.DragSelection, Qwt.QwtPicker.AlwaysOff, self.plot.canvas()) self.zoomer.setRubberBandPen(Qt.QPen(Qt.Qt.black)) # __initZooming() def setZoomerMousePattern(self, index): """Set the mouse zoomer pattern. """ if index == 0: pattern = [ Qwt.QwtEventPattern.MousePattern(Qt.Qt.LeftButton, Qt.Qt.NoModifier), Qwt.QwtEventPattern.MousePattern(Qt.Qt.MidButton, Qt.Qt.NoModifier), Qwt.QwtEventPattern.MousePattern(Qt.Qt.RightButton, Qt.Qt.NoModifier), Qwt.QwtEventPattern.MousePattern(Qt.Qt.LeftButton, Qt.Qt.ShiftModifier), Qwt.QwtEventPattern.MousePattern(Qt.Qt.MidButton, Qt.Qt.ShiftModifier), Qwt.QwtEventPattern.MousePattern(Qt.Qt.RightButton, Qt.Qt.ShiftModifier), ] self.zoomer.setMousePattern(pattern) elif index in (1, 2, 3): self.zoomer.initMousePattern(index) else: raise ValueError, 'index must be in (0, 1, 2, 3)' # setZoomerMousePattern() def __initToolBar(self): """Initialize the toolbar """ toolBar = Qt.QToolBar(self) self.addToolBar(toolBar) toolBar.addWidget(Qt.QLabel('Bars', toolBar)) self.counter = Qwt.QwtCounter(toolBar) self.counter.setRange(0, 10000, 1) self.counter.setNumButtons(3) toolBar.addWidget(self.counter) toolBar.addSeparator() toolBar.addWidget(Qt.QLabel('Mouse', toolBar)) mouseComboBox = Qt.QComboBox(toolBar) for name in ('3 buttons (PyQwt)', '1 button', '2 buttons', '3 buttons (Qwt)'): mouseComboBox.addItem(name) mouseComboBox.setCurrentIndex(0) toolBar.addWidget(mouseComboBox) toolBar.addSeparator() self.setZoomerMousePattern(0) toolBar.addAction(Qt.QWhatsThis.createAction(toolBar)) self.plot.canvas().setWhatsThis( 'A QwtPlotZoomer lets you zoom infinitely deep ' 'by saving the zoom states on a stack.\n\n' 'You can:\n' '- select a zoom region\n' '- unzoom all\n' '- walk down the stack\n' '- walk up the stack.\n\n' 'The combo box in the toolbar lets you attach ' 'different sets of mouse events to those actions.' ) self.counter.setWhatsThis( 'Select the number of bars' ) mouseComboBox.setWhatsThis( 'Configure the zoomer mouse buttons.\n\n' '3 buttons (PyQwt style):\n' '- left-click & drag to zoom\n' '- middle-click to unzoom all\n' '- right-click to walk down the stack\n' '- shift-right-click to walk up the stack.\n' '1 button:\n' '- click & drag to zoom\n' '- control-click to unzoom all\n' '- alt-click to walk down the stack\n' '- shift-alt-click to walk up the stack.\n' '2 buttons:\n' '- left-click & drag to zoom\n' '- right-click to unzoom all\n' '- alt-left-click to walk down the stack\n' '- alt-shift-left-click to walk up the stack.\n' '3 buttons (Qwt style):\n' '- left-click & drag to zoom\n' '- right-click to unzoom all\n' '- middle-click to walk down the stack\n' '- shift-middle-click to walk up the stack.\n\n' 'If some of those key combinations interfere with ' 'your Window manager, press the:\n' '- escape-key to unzoom all\n' '- minus-key to walk down the stack\n' '- plus-key to walk up the stack.' ) self.connect(self.counter, Qt.SIGNAL('valueChanged(double)'), self.go) self.connect(mouseComboBox, Qt.SIGNAL('activated(int)'), self.setZoomerMousePattern) # __initToolBar() def go(self, value): """Create and plot a sequence of bars taking into account the controls """ n = int(value) for bar in self.plot.itemList(): if isinstance(bar, BarCurve): bar.detach() for i in range(n): bar = BarCurve( self.colors[random.randint(0, len(self.colors)-1)], self.colors[random.randint(0, len(self.colors)-1)], ) bar.attach(self.plot) bar.setData([i, i+1.4], [0.3*i, 5.0+0.3*i]) self.clearZoomStack() # go() def clearZoomStack(self): """Auto scale and clear the zoom stack """ self.plot.setAxisAutoScale(Qwt.QwtPlot.xBottom) self.plot.setAxisAutoScale(Qwt.QwtPlot.yLeft) self.plot.replot() self.zoomer.setZoomBase() # clearZoomStack() # class BarPlotMainWindow def make(): demo = BarPlotMainWindow() demo.resize(500, 500) demo.show() return demo # make() def main(args): app = Qt.QApplication(args) demo = make() sys.exit(app.exec_()) # main() # Admire! if __name__ == '__main__': main(sys.argv) # Local Variables: *** # mode: python *** # End: ***