ScatterPlotItem minor performance fixes

SpinBox bugfix - improper handling of arguments to setOpts in integer mode
This commit is contained in:
Luke Campagnola 2012-04-30 18:20:27 -04:00
parent d436f4b634
commit 9b5c8d0ada
8 changed files with 195 additions and 96 deletions

View File

@ -0,0 +1,55 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
## Add path to library (just for examples; you do not need this)
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from pyqtgraph.ptime import time
#QtGui.QApplication.setGraphicsSystem('raster')
app = QtGui.QApplication([])
#mw = QtGui.QMainWindow()
#mw.resize(800,800)
p = pg.plot()
p.setRange(QtCore.QRectF(0, -10, 5000, 20))
p.setLabel('bottom', 'Index', units='B')
#curve.setFillBrush((0, 0, 100, 100))
#curve.setFillLevel(0)
#lr = pg.LinearRegionItem([100, 4900])
#p.addItem(lr)
data = np.random.normal(size=(50,5000))
ptr = 0
lastTime = time()
fps = None
def update():
global curve, data, ptr, p, lastTime, fps
p.clear()
curve = pg.ScatterPlotItem(x=data[ptr%10], y=data[(ptr+1)%10], pen='w', brush='b', size=10, pxMode=True, identical=True)
p.addItem(curve)
ptr += 1
now = time()
dt = now - lastTime
lastTime = now
if fps is None:
fps = 1.0/dt
else:
s = np.clip(dt*3., 0, 1)
fps = fps * (1-s) + (1.0/dt) * s
p.setTitle('%0.2f fps' % fps)
app.processEvents() ## force complete redraw for every plot
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
## Start Qt event loop unless running in interactive mode.
if sys.flags.interactive != 1:
app.exec_()

View File

@ -277,10 +277,10 @@ def mkPen(*args, **kargs):
pen.setStyle(style)
return pen
def hsvColor(h, s=1.0, v=1.0, a=1.0):
"""Generate a QColor from HSVa values."""
def hsvColor(hue, sat=1.0, val=1.0, alpha=1.0):
"""Generate a QColor from HSVa values. (all arguments are float 0.0-1.0)"""
c = QtGui.QColor()
c.setHsvF(h, s, v, a)
c.setHsvF(hue, sat, val, alpha)
return c

View File

@ -6,6 +6,30 @@ import numpy as np
import scipy.stats
__all__ = ['ScatterPlotItem', 'SpotItem']
## Build all symbol paths
Symbols = {name: QtGui.QPainterPath() for name in ['o', 's', 't', 'd', '+']}
Symbols['o'].addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1))
Symbols['s'].addRect(QtCore.QRectF(-0.5, -0.5, 1, 1))
coords = {
't': [(-0.5, -0.5), (0, 0.5), (0.5, -0.5)],
'd': [(0., -0.5), (-0.4, 0.), (0, 0.5), (0.4, 0)],
'+': [
(-0.5, -0.05), (-0.5, 0.05), (-0.05, 0.05), (-0.05, 0.5),
(0.05, 0.5), (0.05, 0.05), (0.5, 0.05), (0.5, -0.05),
(0.05, -0.05), (0.05, -0.5), (-0.05, -0.5), (-0.05, -0.05)
],
}
for k, c in coords.iteritems():
Symbols[k].moveTo(*c[0])
for x,y in c[1:]:
Symbols[k].lineTo(x, y)
Symbols[k].closeSubpath()
class ScatterPlotItem(GraphicsObject):
"""
Displays a set of x/y points. Instances of this class are created
@ -372,7 +396,13 @@ class ScatterPlotItem(GraphicsObject):
self.sigPlotChanged.emit(self)
def generateSpots(self):
def generateSpots(self, clear=True):
if clear:
for spot in self.spots:
self.scene().removeItem(spot)
self.spots = []
xmn = ymn = xmx = ymx = None
## apply defaults
@ -585,44 +615,7 @@ class SpotItem(GraphicsObject):
self.index = index
self.symbol = symbol
#s2 = size/2.
self.path = QtGui.QPainterPath()
if symbol == 'o':
self.path.addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1))
elif symbol == 's':
self.path.addRect(QtCore.QRectF(-0.5, -0.5, 1, 1))
elif symbol == 't' or symbol == '^':
self.path.moveTo(-0.5, -0.5)
self.path.lineTo(0, 0.5)
self.path.lineTo(0.5, -0.5)
self.path.closeSubpath()
#self.path.connectPath(self.path)
elif symbol == 'd':
self.path.moveTo(0., -0.5)
self.path.lineTo(-0.4, 0.)
self.path.lineTo(0, 0.5)
self.path.lineTo(0.4, 0)
self.path.closeSubpath()
#self.path.connectPath(self.path)
elif symbol == '+':
self.path.moveTo(-0.5, -0.01)
self.path.lineTo(-0.5, 0.01)
self.path.lineTo(-0.01, 0.01)
self.path.lineTo(-0.01, 0.5)
self.path.lineTo(0.01, 0.5)
self.path.lineTo(0.01, 0.01)
self.path.lineTo(0.5, 0.01)
self.path.lineTo(0.5, -0.01)
self.path.lineTo(0.01, -0.01)
self.path.lineTo(0.01, -0.5)
self.path.lineTo(-0.01, -0.5)
self.path.lineTo(-0.01, -0.01)
self.path.closeSubpath()
#self.path.connectPath(self.path)
#elif symbol == 'x':
else:
raise Exception("Unknown spot symbol '%s' (type=%s)" % (str(symbol), str(type(symbol))))
#self.path.addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1))
self.path = Symbols[symbol]
if pxMode:
## pre-render an image of the spot and display this rather than redrawing every time.

View File

@ -41,6 +41,8 @@ class ViewBoxMenu(QtGui.QMenu):
(ui.autoRadio.clicked, 'AutoClicked'),
(ui.autoPercentSpin.valueChanged, 'AutoSpinChanged'),
(ui.linkCombo.currentIndexChanged, 'LinkComboChanged'),
(ui.autoPanCheck.toggled, 'AutoPanToggled'),
(ui.visibleOnlyCheck.toggled, 'VisibleOnlyToggled')
]
for sig, fn in connects:
@ -162,6 +164,11 @@ class ViewBoxMenu(QtGui.QMenu):
def xLinkComboChanged(self, ind):
self.view.setXLink(str(self.ctrl[0].linkCombo.currentText()))
def xAutoPanToggled(self, b):
pass
def xVisibleOnlyToggled(self, b):
pass
def yMouseToggled(self, b):
@ -189,6 +196,13 @@ class ViewBoxMenu(QtGui.QMenu):
def yLinkComboChanged(self, ind):
self.view.setYLink(str(self.ctrl[1].linkCombo.currentText()))
def yAutoPanToggled(self, b):
pass
def yVisibleOnlyToggled(self, b):
pass
def exportMethod(self):
act = self.sender()

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'axisCtrlTemplate.ui'
#
# Created: Thu Mar 22 13:13:14 2012
# by: PyQt4 UI code generator 4.8.5
# Created: Wed Mar 28 23:29:45 2012
# by: PyQt4 UI code generator 4.8.3
#
# WARNING! All changes made in this file will be lost!
@ -17,59 +17,63 @@ except AttributeError:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(182, 120)
Form.resize(186, 137)
Form.setMaximumSize(QtCore.QSize(200, 16777215))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setMargin(0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.mouseCheck = QtGui.QCheckBox(Form)
self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8))
self.mouseCheck.setChecked(True)
self.mouseCheck.setObjectName(_fromUtf8("mouseCheck"))
self.gridLayout.addWidget(self.mouseCheck, 0, 1, 1, 2)
self.manualRadio = QtGui.QRadioButton(Form)
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
self.manualRadio.setObjectName(_fromUtf8("manualRadio"))
self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 1)
self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 2)
self.minText = QtGui.QLineEdit(Form)
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.minText.setObjectName(_fromUtf8("minText"))
self.gridLayout.addWidget(self.minText, 1, 1, 1, 1)
self.gridLayout.addWidget(self.minText, 1, 2, 1, 1)
self.maxText = QtGui.QLineEdit(Form)
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.maxText.setObjectName(_fromUtf8("maxText"))
self.gridLayout.addWidget(self.maxText, 1, 2, 1, 1)
self.gridLayout.addWidget(self.maxText, 1, 3, 1, 1)
self.autoRadio = QtGui.QRadioButton(Form)
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
self.autoRadio.setChecked(True)
self.autoRadio.setObjectName(_fromUtf8("autoRadio"))
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 1)
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 2)
self.autoPercentSpin = QtGui.QSpinBox(Form)
self.autoPercentSpin.setEnabled(True)
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
self.autoPercentSpin.setMinimum(1)
self.autoPercentSpin.setMaximum(100)
self.autoPercentSpin.setSingleStep(1)
self.autoPercentSpin.setProperty("value", 100)
self.autoPercentSpin.setProperty(_fromUtf8("value"), 100)
self.autoPercentSpin.setObjectName(_fromUtf8("autoPercentSpin"))
self.gridLayout.addWidget(self.autoPercentSpin, 2, 1, 1, 2)
self.gridLayout.addWidget(self.autoPercentSpin, 2, 2, 1, 2)
self.visibleOnlyCheck = QtGui.QCheckBox(Form)
self.visibleOnlyCheck.setObjectName(_fromUtf8("visibleOnlyCheck"))
self.gridLayout.addWidget(self.visibleOnlyCheck, 3, 1, 1, 3)
self.autoPanCheck = QtGui.QCheckBox(Form)
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
self.autoPanCheck.setObjectName(_fromUtf8("autoPanCheck"))
self.gridLayout.addWidget(self.autoPanCheck, 3, 1, 1, 2)
self.gridLayout.addWidget(self.autoPanCheck, 4, 1, 1, 3)
self.label = QtGui.QLabel(Form)
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout.addWidget(self.label, 5, 0, 1, 2)
self.linkCombo = QtGui.QComboBox(Form)
self.linkCombo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.linkCombo.setObjectName(_fromUtf8("linkCombo"))
self.gridLayout.addWidget(self.linkCombo, 4, 1, 1, 2)
self.label = QtGui.QLabel(Form)
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
self.gridLayout.addWidget(self.linkCombo, 5, 2, 1, 2)
self.mouseCheck = QtGui.QCheckBox(Form)
self.mouseCheck.setChecked(True)
self.mouseCheck.setObjectName(_fromUtf8("mouseCheck"))
self.gridLayout.addWidget(self.mouseCheck, 0, 0, 1, 4)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
pass
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
self.visibleOnlyCheck.setText(QtGui.QApplication.translate("Form", "Visible Data Only", None, QtGui.QApplication.UnicodeUTF8))
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>182</width>
<height>120</height>
<width>186</width>
<height>137</height>
</rect>
</property>
<property name="maximumSize">
@ -20,41 +20,34 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="mouseCheck">
<property name="text">
<string>Mouse Enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="manualRadio">
<property name="text">
<string>Manual</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="1" column="2">
<widget class="QLineEdit" name="minText">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="2">
<item row="1" column="3">
<widget class="QLineEdit" name="maxText">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="autoRadio">
<property name="text">
<string>Auto</string>
@ -64,7 +57,7 @@
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<item row="2" column="2" colspan="2">
<widget class="QSpinBox" name="autoPercentSpin">
<property name="enabled">
<bool>true</bool>
@ -86,24 +79,41 @@
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<item row="3" column="1" colspan="3">
<widget class="QCheckBox" name="visibleOnlyCheck">
<property name="text">
<string>Visible Data Only</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QCheckBox" name="autoPanCheck">
<property name="text">
<string>Auto Pan Only</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Link Axis:</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="2">
<widget class="QComboBox" name="linkCombo">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">
<item row="0" column="0" colspan="4">
<widget class="QCheckBox" name="mouseCheck">
<property name="text">
<string>Link Axis:</string>
<string>Mouse Enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>

View File

@ -5,7 +5,17 @@ import pyqtgraph.functions as functions
__all__ = ['ColorButton']
class ColorButton(QtGui.QPushButton):
"""
**Bases:** QtGui.QPushButton
Button displaying a color and allowing the user to select a new color.
====================== ============================================================
**Signals**:
sigColorChanging(self) emitted whenever a new color is picked in the color dialog
sigColorChanged(self) emitted when the selected color is accepted (user clicks OK)
====================== ============================================================
"""
sigColorChanging = QtCore.Signal(object) ## emitted whenever a new color is picked in the color dialog
sigColorChanged = QtCore.Signal(object) ## emitted when the selected color is accepted (user clicks OK)
@ -38,6 +48,7 @@ class ColorButton(QtGui.QPushButton):
p.end()
def setColor(self, color, finished=True):
"""Sets the button's color and emits both sigColorChanged and sigColorChanging."""
self._color = functions.mkColor(color)
if finished:
self.sigColorChanged.emit(self)

View File

@ -158,10 +158,22 @@ class SpinBox(QtGui.QAbstractSpinBox):
## sanity checks:
if self.opts['int']:
step = self.opts['step']
mStep = self.opts['minStep']
if (int(step) != step) or (self.opts['dec'] and (int(mStep) != mStep)):
raise Exception("Integer SpinBox may only have integer step and minStep.")
if 'step' in opts:
step = opts['step']
if int(step) != step:
raise Exception('Integer SpinBox must have integer step size.')
else:
self.opts['step'] = int(self.opts['step'])
if 'minStep' in opts:
step = opts['minStep']
if int(step) != step:
raise Exception('Integer SpinBox must have integer minStep size.')
else:
ms = int(self.opts.get('minStep', 1))
if ms < 1:
ms = 1
self.opts['minStep'] = ms
self.updateText()