#!/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.
#
# QwtBarCurve is an idea of Tomaz Curk.
#
# Beautified and expanded by Gerard Vermeulen.
import math
import random
import sys
from qt import *
from Qwt4.Qwt import *
class QwtBarCurve(QwtPlotCurve):
def __init__(self, parent, penColor=Qt.black, brushColor=Qt.white):
QwtPlotCurve.__init__(self, parent)
self.penColor = penColor
self.brushColor = brushColor
# __init__()
def draw(self, painter, xMap, yMap, start, stop):
"""Draws rectangles with the corners taken from the x- and y-arrays.
"""
if type(self.penColor) == type(Qt.black):
painter.setPen(QPen(self.penColor, 2))
else:
painter.setPen(QPen(Qt.NoPen))
if type(self.brushColor) == type(Qt.white):
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))
# draw()
# class QwtBarCurve
class QwtBarPlotDemo(QMainWindow):
table = {
'none': None,
'black': Qt.black,
'blue': Qt.blue,
'cyan': Qt.cyan,
'gray': Qt.gray,
'green': Qt.green,
'magenta': Qt.magenta,
'red': Qt.red,
'white': Qt.white,
'yellow': Qt.yellow,
}
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
# Initialize a QwPlot central widget
self.plot = QwtPlot('left-click & drag to zoom'
' -- '
'use the ?-pointer for help',
self)
self.plot.plotLayout().setCanvasMargin(0)
self.plot.plotLayout().setAlignCanvasToScales(True)
self.setCentralWidget(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(self.plot,
SIGNAL('plotMouseMoved(const QMouseEvent&)'),
self.onMouseMoved)
self.plot.canvas().setMouseTracking(True)
self.statusBar().message(
'Plot cursor movements are tracked in the status bar')
# __initTracking()
def onMouseMoved(self, e):
self.statusBar().message(
'x = %+.6g, y = %.6g'
% (self.plot.invTransform(QwtPlot.xBottom, e.pos().x()),
self.plot.invTransform(QwtPlot.yLeft, e.pos().y())))
# onMouseMoved()
def __initZooming(self):
"""Initialize zooming
"""
self.zoomer = QwtPlotZoomer(QwtPlot.xBottom,
QwtPlot.yLeft,
QwtPicker.DragSelection,
QwtPicker.AlwaysOff,
self.plot.canvas())
self.zoomer.setRubberBandPen(QPen(Qt.black))
# __initZooming()
def setZoomerMousePattern(self, index):
"""Set the mouse zoomer pattern.
"""
if index == 0:
pattern = [
QwtEventPattern.MousePattern(Qt.LeftButton, Qt.NoButton),
QwtEventPattern.MousePattern(Qt.MidButton, Qt.NoButton),
QwtEventPattern.MousePattern(Qt.RightButton, Qt.NoButton),
QwtEventPattern.MousePattern(Qt.LeftButton, Qt.ShiftButton),
QwtEventPattern.MousePattern(Qt.MidButton, Qt.ShiftButton),
QwtEventPattern.MousePattern(Qt.RightButton, Qt.ShiftButton),
]
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
"""
self.toolBar = QToolBar(self)
QLabel('Pen', self.toolBar)
self.penComboBox = QComboBox(self.toolBar)
for name in self.table.keys():
self.penComboBox.insertItem(name)
self.penComboBox.setCurrentItem(
random.randint(0, self.penComboBox.count()-1))
self.penComboBox.setMaximumWidth(75)
self.toolBar.addSeparator()
QLabel('Brush', self.toolBar)
self.brushComboBox = QComboBox(self.toolBar)
for name in self.table.keys():
self.brushComboBox.insertItem(name)
self.brushComboBox.setCurrentItem(
random.randint(0, self.brushComboBox.count()-1))
self.brushComboBox.setMaximumWidth(75)
self.toolBar.addSeparator()
QLabel('Bars', self.toolBar)
self.counter = QwtCounter(self.toolBar)
self.counter.setRange(0, 10000, 1)
self.counter.setNumButtons(3)
self.toolBar.addSeparator()
QLabel('Mouse', self.toolBar)
mouseComboBox = QComboBox(self.toolBar)
for name in ('3 buttons (PyQwt)',
'1 button',
'2 buttons',
'3 buttons (Qwt)'):
mouseComboBox.insertItem(name)
mouseComboBox.setCurrentItem(0)
self.toolBar.addSeparator()
self.setZoomerMousePattern(0)
QWhatsThis.whatsThisButton(self.toolBar)
QWhatsThis.add(
self.plot.canvas(),
'A QwtPlotZoomer lets you zoom infinitely deep\n'
'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'
'One of the combo boxes in the toolbar lets you attach\n'
'different sets of mouse events to those actions.'
)
QWhatsThis.add(
self.penComboBox,
'Select the pen color of the bars.'
)
QWhatsThis.add(
self.brushComboBox,
'Select the brush color of the bars'
)
QWhatsThis.add(
self.counter,
'Select the number of bars'
)
QWhatsThis.add(
mouseComboBox,
'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\n'
'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, SIGNAL('valueChanged(double)'), self.go)
self.connect(self.penComboBox, SIGNAL('activated(int)'), self.go)
self.connect(self.brushComboBox, SIGNAL('activated(int)'), self.go)
self.connect(mouseComboBox, SIGNAL('activated(int)'),
self.setZoomerMousePattern)
# __initToolBar()
def go(self, x):
"""Create and plot a sequence of bars taking into account the controls
"""
n = int(self.counter.value())
penColor = self.table[str(self.penComboBox.currentText())]
brushColor = self.table[str(self.brushComboBox.currentText())]
self.plot.removeCurves()
for i in range(n):
curve = QwtBarCurve(self.plot, penColor, brushColor)
key = self.plot.insertCurve(curve)
self.plot.setCurveStyle(key, QwtCurve.UserCurve)
self.plot.setCurveData(key, [i, i+1.4], [0.3*i, 5.0+0.3*i])
if type(x) == type(0.0):
# SIGNAL("valueChanged(double)")
self.clearZoomStack()
else:
self.plot.replot()
# go()
def clearZoomStack(self):
"""Auto scale and clear the zoom stack
"""
self.plot.setAxisAutoScale(QwtPlot.xBottom)
self.plot.setAxisAutoScale(QwtPlot.yLeft)
self.plot.replot()
self.zoomer.setZoomBase()
# clearZoomStack()
# class StackOrderDemo
def main(args):
app = QApplication(args)
demo = make()
app.setMainWidget(demo)
app.exec_loop()
# main()
def make():
demo = QwtBarPlotDemo()
demo.resize(600, 600)
demo.show()
return demo
# make()
# Admire!
if __name__ == '__main__':
main(sys.argv)
# Local Variables: ***
# mode: python ***
# End: ***