merged updates from acq4
This commit is contained in:
parent
4839998574
commit
cefb4f9828
38
examples/ScatterPlotWidget.py
Normal file
38
examples/ScatterPlotWidget.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import initExample ## Add path to library (just for examples; you do not need this)
|
||||||
|
|
||||||
|
import pyqtgraph as pg
|
||||||
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
pg.mkQApp()
|
||||||
|
|
||||||
|
spw = pg.ScatterPlotWidget()
|
||||||
|
spw.show()
|
||||||
|
|
||||||
|
data = np.array([
|
||||||
|
(1, 1, 3, 4, 'x'),
|
||||||
|
(2, 3, 3, 7, 'y'),
|
||||||
|
(3, 2, 5, 2, 'z'),
|
||||||
|
(4, 4, 6, 9, 'z'),
|
||||||
|
(5, 3, 6, 7, 'x'),
|
||||||
|
(6, 5, 2, 6, 'y'),
|
||||||
|
(7, 5, 7, 2, 'z'),
|
||||||
|
], dtype=[('col1', float), ('col2', float), ('col3', int), ('col4', int), ('col5', 'S10')])
|
||||||
|
|
||||||
|
spw.setFields([
|
||||||
|
('col1', {'units': 'm'}),
|
||||||
|
('col2', {'units': 'm'}),
|
||||||
|
('col3', {}),
|
||||||
|
('col4', {}),
|
||||||
|
('col5', {'mode': 'enum', 'values': ['x', 'y', 'z']}),
|
||||||
|
])
|
||||||
|
|
||||||
|
spw.setData(data)
|
||||||
|
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
|
QtGui.QApplication.instance().exec_()
|
@ -523,6 +523,15 @@ class ConnectionItem(GraphicsObject):
|
|||||||
self.hovered = False
|
self.hovered = False
|
||||||
self.path = None
|
self.path = None
|
||||||
self.shapePath = None
|
self.shapePath = None
|
||||||
|
self.style = {
|
||||||
|
'shape': 'line',
|
||||||
|
'color': (100, 100, 250),
|
||||||
|
'width': 1.0,
|
||||||
|
'hoverColor': (150, 150, 250),
|
||||||
|
'hoverWidth': 1.0,
|
||||||
|
'selectedColor': (200, 200, 0),
|
||||||
|
'selectedWidth': 3.0,
|
||||||
|
}
|
||||||
#self.line = QtGui.QGraphicsLineItem(self)
|
#self.line = QtGui.QGraphicsLineItem(self)
|
||||||
self.source.getViewBox().addItem(self)
|
self.source.getViewBox().addItem(self)
|
||||||
self.updateLine()
|
self.updateLine()
|
||||||
@ -537,6 +546,13 @@ class ConnectionItem(GraphicsObject):
|
|||||||
self.target = target
|
self.target = target
|
||||||
self.updateLine()
|
self.updateLine()
|
||||||
|
|
||||||
|
def setStyle(self, **kwds):
|
||||||
|
self.style.update(kwds)
|
||||||
|
if 'shape' in kwds:
|
||||||
|
self.updateLine()
|
||||||
|
else:
|
||||||
|
self.update()
|
||||||
|
|
||||||
def updateLine(self):
|
def updateLine(self):
|
||||||
start = Point(self.source.connectPoint())
|
start = Point(self.source.connectPoint())
|
||||||
if isinstance(self.target, TerminalGraphicsItem):
|
if isinstance(self.target, TerminalGraphicsItem):
|
||||||
@ -547,19 +563,20 @@ class ConnectionItem(GraphicsObject):
|
|||||||
return
|
return
|
||||||
self.prepareGeometryChange()
|
self.prepareGeometryChange()
|
||||||
|
|
||||||
self.path = QtGui.QPainterPath()
|
self.path = self.generatePath(start, stop)
|
||||||
self.path.moveTo(start)
|
|
||||||
self.path.cubicTo(Point(stop.x(), start.y()), Point(start.x(), stop.y()), Point(stop.x(), stop.y()))
|
|
||||||
self.shapePath = None
|
self.shapePath = None
|
||||||
#self.resetTransform()
|
|
||||||
#ang = (stop-start).angle(Point(0, 1))
|
|
||||||
#if ang is None:
|
|
||||||
#ang = 0
|
|
||||||
#self.rotate(ang)
|
|
||||||
#self.setPos(start)
|
|
||||||
#self.length = (start-stop).length()
|
|
||||||
self.update()
|
self.update()
|
||||||
#self.line.setLine(start.x(), start.y(), stop.x(), stop.y())
|
|
||||||
|
def generatePath(self, start, stop):
|
||||||
|
path = QtGui.QPainterPath()
|
||||||
|
path.moveTo(start)
|
||||||
|
if self.style['shape'] == 'line':
|
||||||
|
path.lineTo(stop)
|
||||||
|
elif self.style['shape'] == 'cubic':
|
||||||
|
path.cubicTo(Point(stop.x(), start.y()), Point(start.x(), stop.y()), Point(stop.x(), stop.y()))
|
||||||
|
else:
|
||||||
|
raise Exception('Invalid shape "%s"; options are "line" or "cubic"' % self.style['shape'])
|
||||||
|
return path
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
def keyPressEvent(self, ev):
|
||||||
if ev.key() == QtCore.Qt.Key_Delete or ev.key() == QtCore.Qt.Key_Backspace:
|
if ev.key() == QtCore.Qt.Key_Delete or ev.key() == QtCore.Qt.Key_Backspace:
|
||||||
@ -609,12 +626,12 @@ class ConnectionItem(GraphicsObject):
|
|||||||
|
|
||||||
def paint(self, p, *args):
|
def paint(self, p, *args):
|
||||||
if self.isSelected():
|
if self.isSelected():
|
||||||
p.setPen(fn.mkPen(200, 200, 0, width=3))
|
p.setPen(fn.mkPen(self.style['selectedColor'], width=self.style['selectedWidth']))
|
||||||
else:
|
else:
|
||||||
if self.hovered:
|
if self.hovered:
|
||||||
p.setPen(fn.mkPen(150, 150, 250, width=1))
|
p.setPen(fn.mkPen(self.style['hoverColor'], width=self.style['hoverWidth']))
|
||||||
else:
|
else:
|
||||||
p.setPen(fn.mkPen(100, 100, 250, width=1))
|
p.setPen(fn.mkPen(self.style['color'], width=self.style['width']))
|
||||||
|
|
||||||
#p.drawLine(0, 0, 0, self.length)
|
#p.drawLine(0, 0, 0, self.length)
|
||||||
|
|
||||||
|
@ -84,13 +84,24 @@ class PlotDataItem(GraphicsObject):
|
|||||||
|
|
||||||
**Optimization keyword arguments:**
|
**Optimization keyword arguments:**
|
||||||
|
|
||||||
========== =====================================================================
|
============ =====================================================================
|
||||||
antialias (bool) By default, antialiasing is disabled to improve performance.
|
antialias (bool) By default, antialiasing is disabled to improve performance.
|
||||||
Note that in some cases (in particluar, when pxMode=True), points
|
Note that in some cases (in particluar, when pxMode=True), points
|
||||||
will be rendered antialiased even if this is set to False.
|
will be rendered antialiased even if this is set to False.
|
||||||
|
decimate (int) Sub-sample data by selecting every nth sample before plotting
|
||||||
|
onlyVisible (bool) If True, only plot data that is visible within the X range of
|
||||||
|
the containing ViewBox. This can improve performance when plotting
|
||||||
|
very large data sets where only a fraction of the data is visible
|
||||||
|
at any time.
|
||||||
|
autoResample (bool) If True, resample the data before plotting to avoid plotting
|
||||||
|
multiple line segments per pixel. This can improve performance when
|
||||||
|
viewing very high-density data, but increases the initial overhead
|
||||||
|
and memory usage.
|
||||||
|
sampleRate (float) The sample rate of the data along the X axis (for data with
|
||||||
|
a fixed sample rate). Providing this value improves performance of
|
||||||
|
the *onlyVisible* and *autoResample* options.
|
||||||
identical *deprecated*
|
identical *deprecated*
|
||||||
decimate (int) sub-sample data by selecting every nth sample before plotting
|
============ =====================================================================
|
||||||
========== =====================================================================
|
|
||||||
|
|
||||||
**Meta-info keyword arguments:**
|
**Meta-info keyword arguments:**
|
||||||
|
|
||||||
|
@ -677,15 +677,12 @@ class ScatterPlotItem(GraphicsObject):
|
|||||||
pts[1] = self.data['y']
|
pts[1] = self.data['y']
|
||||||
pts = fn.transformCoordinates(tr, pts)
|
pts = fn.transformCoordinates(tr, pts)
|
||||||
self.fragments = []
|
self.fragments = []
|
||||||
pts = np.clip(pts, -2**31, 2**31) ## prevent Qt segmentation fault.
|
pts = np.clip(pts, -2**30, 2**30) ## prevent Qt segmentation fault.
|
||||||
## Still won't be able to render correctly, though.
|
## Still won't be able to render correctly, though.
|
||||||
for i in xrange(len(self.data)):
|
for i in xrange(len(self.data)):
|
||||||
rec = self.data[i]
|
rec = self.data[i]
|
||||||
pos = QtCore.QPointF(pts[0,i], pts[1,i])
|
pos = QtCore.QPointF(pts[0,i], pts[1,i])
|
||||||
x,y,w,h = rec['fragCoords']
|
x,y,w,h = rec['fragCoords']
|
||||||
if abs(w) > 10000 or abs(h) > 10000:
|
|
||||||
print self.data
|
|
||||||
raise Exception("fragment corrupt")
|
|
||||||
rect = QtCore.QRectF(y, x, h, w)
|
rect = QtCore.QRectF(y, x, h, w)
|
||||||
self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect))
|
self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect))
|
||||||
|
|
||||||
|
@ -104,6 +104,10 @@ class EnumFilterItem(ptree.types.SimpleParameter):
|
|||||||
ch = ptree.Parameter.create(name=str(v), type='bool', value=True)
|
ch = ptree.Parameter.create(name=str(v), type='bool', value=True)
|
||||||
ch.maskValue = v
|
ch.maskValue = v
|
||||||
childs.append(ch)
|
childs.append(ch)
|
||||||
|
ch = ptree.Parameter.create(name='(other)', type='bool', value=True)
|
||||||
|
ch.maskValue = '__other__'
|
||||||
|
childs.append(ch)
|
||||||
|
|
||||||
ptree.types.SimpleParameter.__init__(self,
|
ptree.types.SimpleParameter.__init__(self,
|
||||||
name=name, autoIncrementName=True, type='bool', value=True, removable=True, renamable=True,
|
name=name, autoIncrementName=True, type='bool', value=True, removable=True, renamable=True,
|
||||||
children=childs)
|
children=childs)
|
||||||
@ -111,9 +115,14 @@ class EnumFilterItem(ptree.types.SimpleParameter):
|
|||||||
def generateMask(self, data):
|
def generateMask(self, data):
|
||||||
vals = data[self.fieldName]
|
vals = data[self.fieldName]
|
||||||
mask = np.ones(len(data), dtype=bool)
|
mask = np.ones(len(data), dtype=bool)
|
||||||
|
otherMask = np.ones(len(data), dtype=bool)
|
||||||
for c in self:
|
for c in self:
|
||||||
if c.value() is True:
|
|
||||||
continue
|
|
||||||
key = c.maskValue
|
key = c.maskValue
|
||||||
mask &= vals != key
|
if key == '__other__':
|
||||||
|
m = ~otherMask
|
||||||
|
else:
|
||||||
|
m = vals != key
|
||||||
|
otherMask &= m
|
||||||
|
if c.value() is False:
|
||||||
|
mask &= m
|
||||||
return mask
|
return mask
|
||||||
|
@ -48,13 +48,15 @@ class ScatterPlotWidget(QtGui.QSplitter):
|
|||||||
self.addWidget(self.plot)
|
self.addWidget(self.plot)
|
||||||
|
|
||||||
self.data = None
|
self.data = None
|
||||||
|
self.mouseOverField = None
|
||||||
|
self.scatterPlot = None
|
||||||
self.style = dict(pen=None, symbol='o')
|
self.style = dict(pen=None, symbol='o')
|
||||||
|
|
||||||
self.fieldList.itemSelectionChanged.connect(self.fieldSelectionChanged)
|
self.fieldList.itemSelectionChanged.connect(self.fieldSelectionChanged)
|
||||||
self.filter.sigFilterChanged.connect(self.filterChanged)
|
self.filter.sigFilterChanged.connect(self.filterChanged)
|
||||||
self.colorMap.sigColorMapChanged.connect(self.updatePlot)
|
self.colorMap.sigColorMapChanged.connect(self.updatePlot)
|
||||||
|
|
||||||
def setFields(self, fields):
|
def setFields(self, fields, mouseOverField=None):
|
||||||
"""
|
"""
|
||||||
Set the list of field names/units to be processed.
|
Set the list of field names/units to be processed.
|
||||||
|
|
||||||
@ -62,6 +64,7 @@ class ScatterPlotWidget(QtGui.QSplitter):
|
|||||||
:func:`ColorMapWidget.setFields <pyqtgraph.widgets.ColorMapWidget.ColorMapParameter.setFields>`
|
:func:`ColorMapWidget.setFields <pyqtgraph.widgets.ColorMapWidget.ColorMapParameter.setFields>`
|
||||||
"""
|
"""
|
||||||
self.fields = OrderedDict(fields)
|
self.fields = OrderedDict(fields)
|
||||||
|
self.mouseOverField = mouseOverField
|
||||||
self.fieldList.clear()
|
self.fieldList.clear()
|
||||||
for f,opts in fields:
|
for f,opts in fields:
|
||||||
item = QtGui.QListWidgetItem(f)
|
item = QtGui.QListWidgetItem(f)
|
||||||
@ -158,7 +161,7 @@ class ScatterPlotWidget(QtGui.QSplitter):
|
|||||||
axis = self.plot.getAxis(['bottom', 'left'][i])
|
axis = self.plot.getAxis(['bottom', 'left'][i])
|
||||||
if xy[i] is not None and xy[i].dtype.kind in ('S', 'O'):
|
if xy[i] is not None and xy[i].dtype.kind in ('S', 'O'):
|
||||||
vals = self.fields[sel[i]].get('values', list(set(xy[i])))
|
vals = self.fields[sel[i]].get('values', list(set(xy[i])))
|
||||||
xy[i] = np.array([vals.index(x) if x in vals else None for x in xy[i]], dtype=float)
|
xy[i] = np.array([vals.index(x) if x in vals else len(vals) for x in xy[i]], dtype=float)
|
||||||
axis.setTicks([list(enumerate(vals))])
|
axis.setTicks([list(enumerate(vals))])
|
||||||
else:
|
else:
|
||||||
axis.setTicks(None) # reset to automatic ticking
|
axis.setTicks(None) # reset to automatic ticking
|
||||||
@ -179,7 +182,16 @@ class ScatterPlotWidget(QtGui.QSplitter):
|
|||||||
else:
|
else:
|
||||||
y = y[mask]
|
y = y[mask]
|
||||||
|
|
||||||
|
if self.scatterPlot is not None:
|
||||||
self.plot.plot(x, y, **style)
|
try:
|
||||||
|
self.scatterPlot.sigPointsClicked.disconnect(self.plotClicked)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.scatterPlot = self.plot.plot(x, y, data=data[mask], **style)
|
||||||
|
self.scatterPlot.sigPointsClicked.connect(self.plotClicked)
|
||||||
|
|
||||||
|
|
||||||
|
def plotClicked(self, plot, points):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user