ScatterPlotItem minor performance fixes
SpinBox bugfix - improper handling of arguments to setOpts in integer mode
This commit is contained in:
parent
d436f4b634
commit
9b5c8d0ada
55
examples/ScatterPlotSpeedTest.py
Normal file
55
examples/ScatterPlotSpeedTest.py
Normal 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_()
|
@ -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
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user