Merge branch 'new_markers' into develop

This commit is contained in:
Luke Campagnola 2016-02-14 23:16:47 -08:00
commit f988f0522d
3 changed files with 176 additions and 126 deletions

38
examples/Symbols.py Executable file
View File

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"""
This example shows all the scatter plot symbols available in pyqtgraph.
These symbols are used to mark point locations for scatter plots and some line
plots, similar to "markers" in matplotlib and vispy.
"""
import initExample ## Add path to library (just for examples; you do not need this)
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="Scatter Plot Symbols")
win.resize(1000,600)
pg.setConfigOptions(antialias=True)
plot = win.addPlot(title="Plotting with symbols")
plot.addLegend()
plot.plot([0, 1, 2, 3, 4], pen=(0,0,200), symbolBrush=(0,0,200), symbolPen='w', symbol='o', symbolSize=14, name="symbol='o'")
plot.plot([1, 2, 3, 4, 5], pen=(0,128,0), symbolBrush=(0,128,0), symbolPen='w', symbol='t', symbolSize=14, name="symbol='t'")
plot.plot([2, 3, 4, 5, 6], pen=(19,234,201), symbolBrush=(19,234,201), symbolPen='w', symbol='t1', symbolSize=14, name="symbol='t1'")
plot.plot([3, 4, 5, 6, 7], pen=(195,46,212), symbolBrush=(195,46,212), symbolPen='w', symbol='t2', symbolSize=14, name="symbol='t2'")
plot.plot([4, 5, 6, 7, 8], pen=(250,194,5), symbolBrush=(250,194,5), symbolPen='w', symbol='t3', symbolSize=14, name="symbol='t3'")
plot.plot([5, 6, 7, 8, 9], pen=(54,55,55), symbolBrush=(55,55,55), symbolPen='w', symbol='s', symbolSize=14, name="symbol='s'")
plot.plot([6, 7, 8, 9, 10], pen=(0,114,189), symbolBrush=(0,114,189), symbolPen='w', symbol='p', symbolSize=14, name="symbol='p'")
plot.plot([7, 8, 9, 10, 11], pen=(217,83,25), symbolBrush=(217,83,25), symbolPen='w', symbol='h', symbolSize=14, name="symbol='h'")
plot.plot([8, 9, 10, 11, 12], pen=(237,177,32), symbolBrush=(237,177,32), symbolPen='w', symbol='star', symbolSize=14, name="symbol='star'")
plot.plot([9, 10, 11, 12, 13], pen=(126,47,142), symbolBrush=(126,47,142), symbolPen='w', symbol='+', symbolSize=14, name="symbol='+'")
plot.plot([10, 11, 12, 13, 14], pen=(119,172,48), symbolBrush=(119,172,48), symbolPen='w', symbol='d', symbolSize=14, name="symbol='d'")
plot.setXRange(-2, 4)
## 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_()

View File

@ -22,6 +22,7 @@ examples = OrderedDict([
('Console', 'ConsoleWidget.py'),
('Histograms', 'histogram.py'),
('Beeswarm plot', 'beeswarm.py'),
('Symbols', 'Symbols.py'),
('Auto-range', 'PlotAutoRange.py'),
('Remote Plotting', 'RemoteSpeedTest.py'),
('Scrolling plots', 'scrollingPlots.py'),

View File

@ -19,17 +19,28 @@ __all__ = ['ScatterPlotItem', 'SpotItem']
## Build all symbol paths
Symbols = OrderedDict([(name, QtGui.QPainterPath()) for name in ['o', 's', 't', 'd', '+', 'x']])
Symbols = OrderedDict([(name, QtGui.QPainterPath()) for name in ['o', 's', 't', 't1', 't2', 't3','d', '+', 'x', 'p', 'h', 'star']])
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)],
't1': [(-0.5, 0.5), (0, -0.5), (0.5, 0.5)],
't2': [(-0.5, -0.5), (-0.5, 0.5), (0.5, 0)],
't3': [(0.5, 0.5), (0.5, -0.5), (-0.5, 0)],
'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.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)
],
'p': [(0, -0.5), (-0.4755, -0.1545), (-0.2939, 0.4045),
(0.2939, 0.4045), (0.4755, -0.1545)],
'h': [(0.433, 0.25), (0., 0.5), (-0.433, 0.25), (-0.433, -0.25),
(0, -0.5), (0.433, -0.25)],
'star': [(0, -0.5), (-0.1123, -0.1545), (-0.4755, -0.1545),
(-0.1816, 0.059), (-0.2939, 0.4045), (0, 0.1910),
(0.2939, 0.4045), (0.1816, 0.059), (0.4755, -0.1545),
(0.1123, -0.1545)]
}
for k, c in coords.items():
Symbols[k].moveTo(*c[0])
@ -40,7 +51,7 @@ tr = QtGui.QTransform()
tr.rotate(45)
Symbols['x'] = tr.map(Symbols['+'])
def drawSymbol(painter, symbol, size, pen, brush):
if symbol is None:
return
@ -53,13 +64,13 @@ def drawSymbol(painter, symbol, size, pen, brush):
symbol = list(Symbols.values())[symbol % len(Symbols)]
painter.drawPath(symbol)
def renderSymbol(symbol, size, pen, brush, device=None):
"""
Render a symbol specification to QImage.
Symbol may be either a QPainterPath or one of the keys in the Symbols dict.
If *device* is None, a new QPixmap will be returned. Otherwise,
the symbol will be rendered into the device specified (See QPainter documentation
the symbol will be rendered into the device specified (See QPainter documentation
for more information).
"""
## Render a spot with the given parameters to a pixmap
@ -80,33 +91,33 @@ def makeSymbolPixmap(size, pen, brush, symbol):
## deprecated
img = renderSymbol(symbol, size, pen, brush)
return QtGui.QPixmap(img)
class SymbolAtlas(object):
"""
Used to efficiently construct a single QPixmap containing all rendered symbols
for a ScatterPlotItem. This is required for fragment rendering.
Use example:
atlas = SymbolAtlas()
sc1 = atlas.getSymbolCoords('o', 5, QPen(..), QBrush(..))
sc2 = atlas.getSymbolCoords('t', 10, QPen(..), QBrush(..))
pm = atlas.getAtlas()
"""
def __init__(self):
# symbol key : QRect(...) coordinates where symbol can be found in atlas.
# note that the coordinate list will always be the same list object as
# note that the coordinate list will always be the same list object as
# long as the symbol is in the atlas, but the coordinates may
# change if the atlas is rebuilt.
# weak value; if all external refs to this list disappear,
# weak value; if all external refs to this list disappear,
# the symbol will be forgotten.
self.symbolMap = weakref.WeakValueDictionary()
self.atlasData = None # numpy array of atlas image
self.atlas = None # atlas as QPixmap
self.atlasValid = False
self.max_width=0
def getSymbolCoords(self, opts):
"""
Given a list of spot records, return an object representing the coordinates of that symbol within the atlas
@ -131,7 +142,7 @@ class SymbolAtlas(object):
keyi = key
sourceRecti = newRectSrc
return sourceRect
def buildAtlas(self):
# get rendered array for all symbols, keep track of avg/max width
rendered = {}
@ -150,7 +161,7 @@ class SymbolAtlas(object):
w = arr.shape[0]
avgWidth += w
maxWidth = max(maxWidth, w)
nSymbols = len(rendered)
if nSymbols > 0:
avgWidth /= nSymbols
@ -158,10 +169,10 @@ class SymbolAtlas(object):
else:
avgWidth = 0
width = 0
# sort symbols by height
symbols = sorted(rendered.keys(), key=lambda x: rendered[x].shape[1], reverse=True)
self.atlasRows = []
x = width
@ -187,7 +198,7 @@ class SymbolAtlas(object):
self.atlas = None
self.atlasValid = True
self.max_width = maxWidth
def getAtlas(self):
if not self.atlasValid:
self.buildAtlas()
@ -197,27 +208,27 @@ class SymbolAtlas(object):
img = fn.makeQImage(self.atlasData, copy=False, transpose=False)
self.atlas = QtGui.QPixmap(img)
return self.atlas
class ScatterPlotItem(GraphicsObject):
"""
Displays a set of x/y points. Instances of this class are created
automatically as part of PlotDataItem; these rarely need to be instantiated
directly.
The size, shape, pen, and fill brush may be set for each point individually
or for all points.
The size, shape, pen, and fill brush may be set for each point individually
or for all points.
======================== ===============================================
**Signals:**
sigPlotChanged(self) Emitted when the data being plotted has changed
sigClicked(self, points) Emitted when the curve is clicked. Sends a list
of all the points under the mouse pointer.
======================== ===============================================
"""
#sigPointClicked = QtCore.Signal(object, object)
sigClicked = QtCore.Signal(object, object) ## self, points
@ -228,17 +239,17 @@ class ScatterPlotItem(GraphicsObject):
"""
profiler = debug.Profiler()
GraphicsObject.__init__(self)
self.picture = None # QPicture used for rendering when pxmode==False
self.fragmentAtlas = SymbolAtlas()
self.data = np.empty(0, dtype=[('x', float), ('y', float), ('size', float), ('symbol', object), ('pen', object), ('brush', object), ('data', object), ('item', object), ('sourceRect', object), ('targetRect', object), ('width', float)])
self.bounds = [None, None] ## caches data bounds
self._maxSpotWidth = 0 ## maximum size of the scale-variant portion of all spots
self._maxSpotPxWidth = 0 ## maximum size of the scale-invariant portion of all spots
self.opts = {
'pxMode': True,
'useCache': True, ## If useCache is False, symbols are re-drawn on every paint.
'pxMode': True,
'useCache': True, ## If useCache is False, symbols are re-drawn on every paint.
'antialias': getConfigOption('antialias'),
'name': None,
}
@ -252,14 +263,14 @@ class ScatterPlotItem(GraphicsObject):
profiler('setData')
#self.setCacheMode(self.DeviceCoordinateCache)
def setData(self, *args, **kargs):
"""
**Ordered Arguments:**
* If there is only one unnamed argument, it will be interpreted like the 'spots' argument.
* If there are two unnamed arguments, they will be interpreted as sequences of x and y values.
====================== ===============================================================================================
**Keyword Arguments:**
*spots* Optional list of dicts. Each dict specifies parameters for a single spot:
@ -285,8 +296,8 @@ class ScatterPlotItem(GraphicsObject):
it is in the item's local coordinate system.
*data* a list of python objects used to uniquely identify each spot.
*identical* *Deprecated*. This functionality is handled automatically now.
*antialias* Whether to draw symbols with antialiasing. Note that if pxMode is True, symbols are
always rendered with antialiasing (since the rendered symbols can be cached, this
*antialias* Whether to draw symbols with antialiasing. Note that if pxMode is True, symbols are
always rendered with antialiasing (since the rendered symbols can be cached, this
incurs very little performance cost)
*name* The name of this item. Names are used for automatically
generating LegendItem entries and by some exporters.
@ -298,10 +309,10 @@ class ScatterPlotItem(GraphicsObject):
def addPoints(self, *args, **kargs):
"""
Add new points to the scatter plot.
Add new points to the scatter plot.
Arguments are the same as setData()
"""
## deal with non-keyword arguments
if len(args) == 1:
kargs['spots'] = args[0]
@ -310,7 +321,7 @@ class ScatterPlotItem(GraphicsObject):
kargs['y'] = args[1]
elif len(args) > 2:
raise Exception('Only accepts up to two non-keyword arguments.')
## convert 'pos' argument to 'x' and 'y'
if 'pos' in kargs:
pos = kargs['pos']
@ -329,7 +340,7 @@ class ScatterPlotItem(GraphicsObject):
y.append(p[1])
kargs['x'] = x
kargs['y'] = y
## determine how many spots we have
if 'spots' in kargs:
numPts = len(kargs['spots'])
@ -339,16 +350,16 @@ class ScatterPlotItem(GraphicsObject):
kargs['x'] = []
kargs['y'] = []
numPts = 0
## Extend record array
oldData = self.data
self.data = np.empty(len(oldData)+numPts, dtype=self.data.dtype)
## note that np.empty initializes object fields to None and string fields to ''
self.data[:len(oldData)] = oldData
#for i in range(len(oldData)):
#oldData[i]['item']._data = self.data[i] ## Make sure items have proper reference to new array
newData = self.data[len(oldData):]
newData['size'] = -1 ## indicates to use default size
@ -376,12 +387,12 @@ class ScatterPlotItem(GraphicsObject):
elif 'y' in kargs:
newData['x'] = kargs['x']
newData['y'] = kargs['y']
if 'pxMode' in kargs:
self.setPxMode(kargs['pxMode'])
if 'antialias' in kargs:
self.opts['antialias'] = kargs['antialias']
## Set any extra parameters provided in keyword arguments
for k in ['pen', 'brush', 'symbol', 'size']:
if k in kargs:
@ -397,32 +408,32 @@ class ScatterPlotItem(GraphicsObject):
self.invalidate()
self.updateSpots(newData)
self.sigPlotChanged.emit(self)
def invalidate(self):
## clear any cached drawing state
self.picture = None
self.update()
def getData(self):
return self.data['x'], self.data['y']
return self.data['x'], self.data['y']
def setPoints(self, *args, **kargs):
##Deprecated; use setData
return self.setData(*args, **kargs)
def implements(self, interface=None):
ints = ['plotData']
if interface is None:
return ints
return interface in ints
def name(self):
return self.opts.get('name', None)
def setPen(self, *args, **kargs):
"""Set the pen(s) used to draw the outline around each spot.
"""Set the pen(s) used to draw the outline around each spot.
If a list or array is provided, then the pen for each spot will be set separately.
Otherwise, the arguments are passed to pg.mkPen and used as the default pen for
Otherwise, the arguments are passed to pg.mkPen and used as the default pen for
all spots which do not have a pen explicitly set."""
update = kargs.pop('update', True)
dataSet = kargs.pop('dataSet', self.data)
@ -436,19 +447,19 @@ class ScatterPlotItem(GraphicsObject):
dataSet['pen'] = pens
else:
self.opts['pen'] = fn.mkPen(*args, **kargs)
dataSet['sourceRect'] = None
if update:
self.updateSpots(dataSet)
def setBrush(self, *args, **kargs):
"""Set the brush(es) used to fill the interior of each spot.
"""Set the brush(es) used to fill the interior of each spot.
If a list or array is provided, then the brush for each spot will be set separately.
Otherwise, the arguments are passed to pg.mkBrush and used as the default brush for
Otherwise, the arguments are passed to pg.mkBrush and used as the default brush for
all spots which do not have a brush explicitly set."""
update = kargs.pop('update', True)
dataSet = kargs.pop('dataSet', self.data)
if len(args) == 1 and (isinstance(args[0], np.ndarray) or isinstance(args[0], list)):
brushes = args[0]
if 'mask' in kargs and kargs['mask'] is not None:
@ -459,19 +470,19 @@ class ScatterPlotItem(GraphicsObject):
else:
self.opts['brush'] = fn.mkBrush(*args, **kargs)
#self._spotPixmap = None
dataSet['sourceRect'] = None
if update:
self.updateSpots(dataSet)
def setSymbol(self, symbol, update=True, dataSet=None, mask=None):
"""Set the symbol(s) used to draw each spot.
"""Set the symbol(s) used to draw each spot.
If a list or array is provided, then the symbol for each spot will be set separately.
Otherwise, the argument will be used as the default symbol for
Otherwise, the argument will be used as the default symbol for
all spots which do not have a symbol explicitly set."""
if dataSet is None:
dataSet = self.data
if isinstance(symbol, np.ndarray) or isinstance(symbol, list):
symbols = symbol
if mask is not None:
@ -482,19 +493,19 @@ class ScatterPlotItem(GraphicsObject):
else:
self.opts['symbol'] = symbol
self._spotPixmap = None
dataSet['sourceRect'] = None
if update:
self.updateSpots(dataSet)
def setSize(self, size, update=True, dataSet=None, mask=None):
"""Set the size(s) used to draw each spot.
"""Set the size(s) used to draw each spot.
If a list or array is provided, then the size for each spot will be set separately.
Otherwise, the argument will be used as the default size for
Otherwise, the argument will be used as the default size for
all spots which do not have a size explicitly set."""
if dataSet is None:
dataSet = self.data
if isinstance(size, np.ndarray) or isinstance(size, list):
sizes = size
if mask is not None:
@ -505,21 +516,21 @@ class ScatterPlotItem(GraphicsObject):
else:
self.opts['size'] = size
self._spotPixmap = None
dataSet['sourceRect'] = None
if update:
self.updateSpots(dataSet)
def setPointData(self, data, dataSet=None, mask=None):
if dataSet is None:
dataSet = self.data
if isinstance(data, np.ndarray) or isinstance(data, list):
if mask is not None:
data = data[mask]
if len(data) != len(dataSet):
raise Exception("Length of meta data does not match number of points (%d != %d)" % (len(data), len(dataSet)))
## Bug: If data is a numpy record array, then items from that array must be copied to dataSet one at a time.
## (otherwise they are converted to tuples and thus lose their field names.
if isinstance(data, np.ndarray) and (data.dtype.fields is not None)and len(data.dtype.fields) > 1:
@ -527,14 +538,14 @@ class ScatterPlotItem(GraphicsObject):
dataSet['data'][i] = rec
else:
dataSet['data'] = data
def setPxMode(self, mode):
if self.opts['pxMode'] == mode:
return
self.opts['pxMode'] = mode
self.invalidate()
def updateSpots(self, dataSet=None):
if dataSet is None:
dataSet = self.data
@ -547,9 +558,9 @@ class ScatterPlotItem(GraphicsObject):
opts = self.getSpotOpts(dataSet[mask])
sourceRect = self.fragmentAtlas.getSymbolCoords(opts)
dataSet['sourceRect'][mask] = sourceRect
self.fragmentAtlas.getAtlas() # generate atlas so source widths are available.
dataSet['width'] = np.array(list(imap(QtCore.QRectF.width, dataSet['sourceRect'])))/2
dataSet['targetRect'] = None
self._maxSpotPxWidth = self.fragmentAtlas.max_width
@ -585,9 +596,9 @@ class ScatterPlotItem(GraphicsObject):
recs['pen'][np.equal(recs['pen'], None)] = fn.mkPen(self.opts['pen'])
recs['brush'][np.equal(recs['brush'], None)] = fn.mkBrush(self.opts['brush'])
return recs
def measureSpotSizes(self, dataSet):
for rec in dataSet:
## keep track of the maximum spot size and pixel size
@ -605,8 +616,8 @@ class ScatterPlotItem(GraphicsObject):
self._maxSpotWidth = max(self._maxSpotWidth, width)
self._maxSpotPxWidth = max(self._maxSpotPxWidth, pxWidth)
self.bounds = [None, None]
def clear(self):
"""Remove all spots from the scatter plot"""
#self.clearItems()
@ -617,23 +628,23 @@ class ScatterPlotItem(GraphicsObject):
def dataBounds(self, ax, frac=1.0, orthoRange=None):
if frac >= 1.0 and orthoRange is None and self.bounds[ax] is not None:
return self.bounds[ax]
#self.prepareGeometryChange()
if self.data is None or len(self.data) == 0:
return (None, None)
if ax == 0:
d = self.data['x']
d2 = self.data['y']
elif ax == 1:
d = self.data['y']
d2 = self.data['x']
if orthoRange is not None:
mask = (d2 >= orthoRange[0]) * (d2 <= orthoRange[1])
d = d[mask]
d2 = d2[mask]
if frac >= 1.0:
self.bounds[ax] = (np.nanmin(d) - self._maxSpotWidth*0.7072, np.nanmax(d) + self._maxSpotWidth*0.7072)
return self.bounds[ax]
@ -656,11 +667,11 @@ class ScatterPlotItem(GraphicsObject):
if ymn is None or ymx is None:
ymn = 0
ymx = 0
px = py = 0.0
pxPad = self.pixelPadding()
if pxPad > 0:
# determine length of pixel in local x, y directions
# determine length of pixel in local x, y directions
px, py = self.pixelVectors()
try:
px = 0 if px is None else px.length()
@ -670,7 +681,7 @@ class ScatterPlotItem(GraphicsObject):
py = 0 if py is None else py.length()
except OverflowError:
py = 0
# return bounds expanded by pixel size
px *= pxPad
py *= pxPad
@ -688,7 +699,7 @@ class ScatterPlotItem(GraphicsObject):
def mapPointsToDevice(self, pts):
# Map point locations to device
# Map point locations to device
tr = self.deviceTransform()
if tr is None:
return None
@ -699,7 +710,7 @@ class ScatterPlotItem(GraphicsObject):
pts = fn.transformCoordinates(tr, pts)
pts -= self.data['width']
pts = np.clip(pts, -2**30, 2**30) ## prevent Qt segmentation fault.
return pts
def getViewMask(self, pts):
@ -713,48 +724,48 @@ class ScatterPlotItem(GraphicsObject):
mask = ((pts[0] + w > viewBounds.left()) &
(pts[0] - w < viewBounds.right()) &
(pts[1] + w > viewBounds.top()) &
(pts[1] - w < viewBounds.bottom())) ## remove out of view points
(pts[1] - w < viewBounds.bottom())) ## remove out of view points
return mask
@debug.warnOnException ## raising an exception here causes crash
def paint(self, p, *args):
#p.setPen(fn.mkPen('r'))
#p.drawRect(self.boundingRect())
if self._exportOpts is not False:
aa = self._exportOpts.get('antialias', True)
scale = self._exportOpts.get('resolutionScale', 1.0) ## exporting to image; pixel resolution may have changed
else:
aa = self.opts['antialias']
scale = 1.0
if self.opts['pxMode'] is True:
p.resetTransform()
# Map point coordinates to device
pts = np.vstack([self.data['x'], self.data['y']])
pts = self.mapPointsToDevice(pts)
if pts is None:
return
# Cull points that are outside view
viewMask = self.getViewMask(pts)
#pts = pts[:,mask]
#data = self.data[mask]
if self.opts['useCache'] and self._exportOpts is False:
# Draw symbols from pre-rendered atlas
atlas = self.fragmentAtlas.getAtlas()
# Update targetRects if necessary
updateMask = viewMask & np.equal(self.data['targetRect'], None)
if np.any(updateMask):
updatePts = pts[:,updateMask]
width = self.data[updateMask]['width']*2
self.data['targetRect'][updateMask] = list(imap(QtCore.QRectF, updatePts[0,:], updatePts[1,:], width, width))
data = self.data[viewMask]
if USE_PYSIDE or USE_PYQT5:
list(imap(p.drawPixmap, data['targetRect'], repeat(atlas), data['sourceRect']))
@ -782,16 +793,16 @@ class ScatterPlotItem(GraphicsObject):
p2.translate(rec['x'], rec['y'])
drawSymbol(p2, *self.getSpotOpts(rec, scale))
p2.end()
p.setRenderHint(p.Antialiasing, aa)
self.picture.play(p)
def points(self):
for rec in self.data:
if rec['item'] is None:
rec['item'] = SpotItem(rec, self)
return self.data['item']
def pointsAt(self, pos):
x = pos.x()
y = pos.y()
@ -814,7 +825,7 @@ class ScatterPlotItem(GraphicsObject):
#print "No hit:", (x, y), (sx, sy)
#print " ", (sx-s2x, sy-s2y), (sx+s2x, sy+s2y)
return pts[::-1]
def mouseClickEvent(self, ev):
if ev.button() == QtCore.Qt.LeftButton:
@ -833,7 +844,7 @@ class ScatterPlotItem(GraphicsObject):
class SpotItem(object):
"""
Class referring to individual spots in a scatter plot.
These can be retrieved by calling ScatterPlotItem.points() or
These can be retrieved by calling ScatterPlotItem.points() or
by connecting to the ScatterPlotItem's click signals.
"""
@ -844,34 +855,34 @@ class SpotItem(object):
#self.setParentItem(plot)
#self.setPos(QtCore.QPointF(data['x'], data['y']))
#self.updateItem()
def data(self):
"""Return the user data associated with this spot."""
return self._data['data']
def size(self):
"""Return the size of this spot.
"""Return the size of this spot.
If the spot has no explicit size set, then return the ScatterPlotItem's default size instead."""
if self._data['size'] == -1:
return self._plot.opts['size']
else:
return self._data['size']
def pos(self):
return Point(self._data['x'], self._data['y'])
def viewPos(self):
return self._plot.mapToView(self.pos())
def setSize(self, size):
"""Set the size of this spot.
If the size is set to -1, then the ScatterPlotItem's default size
"""Set the size of this spot.
If the size is set to -1, then the ScatterPlotItem's default size
will be used instead."""
self._data['size'] = size
self.updateItem()
def symbol(self):
"""Return the symbol of this spot.
"""Return the symbol of this spot.
If the spot has no explicit symbol set, then return the ScatterPlotItem's default symbol instead.
"""
symbol = self._data['symbol']
@ -883,7 +894,7 @@ class SpotItem(object):
except:
pass
return symbol
def setSymbol(self, symbol):
"""Set the symbol for this spot.
If the symbol is set to '', then the ScatterPlotItem's default symbol will be used instead."""
@ -895,35 +906,35 @@ class SpotItem(object):
if pen is None:
pen = self._plot.opts['pen']
return fn.mkPen(pen)
def setPen(self, *args, **kargs):
"""Set the outline pen for this spot"""
pen = fn.mkPen(*args, **kargs)
self._data['pen'] = pen
self.updateItem()
def resetPen(self):
"""Remove the pen set for this spot; the scatter plot's default pen will be used instead."""
self._data['pen'] = None ## Note this is NOT the same as calling setPen(None)
self.updateItem()
def brush(self):
brush = self._data['brush']
if brush is None:
brush = self._plot.opts['brush']
return fn.mkBrush(brush)
def setBrush(self, *args, **kargs):
"""Set the fill brush for this spot"""
brush = fn.mkBrush(*args, **kargs)
self._data['brush'] = brush
self.updateItem()
def resetBrush(self):
"""Remove the brush set for this spot; the scatter plot's default brush will be used instead."""
self._data['brush'] = None ## Note this is NOT the same as calling setBrush(None)
self.updateItem()
def setData(self, data):
"""Set the user-data associated with this spot"""
self._data['data'] = data
@ -938,14 +949,14 @@ class SpotItem(object):
#QtGui.QGraphicsPixmapItem.__init__(self)
#self.setFlags(self.flags() | self.ItemIgnoresTransformations)
#SpotItem.__init__(self, data, plot)
#def setPixmap(self, pixmap):
#QtGui.QGraphicsPixmapItem.setPixmap(self, pixmap)
#self.setOffset(-pixmap.width()/2.+0.5, -pixmap.height()/2.)
#def updateItem(self):
#symbolOpts = (self._data['pen'], self._data['brush'], self._data['size'], self._data['symbol'])
### If all symbol options are default, use default pixmap
#if symbolOpts == (None, None, -1, ''):
#pixmap = self._plot.defaultSpotPixmap()