Merge pull request #623 from termim/ScatterPlot

Scatter plot
This commit is contained in:
Luke Campagnola 2018-01-29 18:55:19 -08:00 committed by GitHub
commit 1f9acd1502
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 18 deletions

View File

@ -11,6 +11,7 @@ import initExample
from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg import pyqtgraph as pg
import numpy as np import numpy as np
from collections import namedtuple
app = QtGui.QApplication([]) app = QtGui.QApplication([])
mw = QtGui.QMainWindow() mw = QtGui.QMainWindow()
@ -62,10 +63,30 @@ s1.sigClicked.connect(clicked)
## overhead and memory usage since each spot generates its own pre-rendered ## overhead and memory usage since each spot generates its own pre-rendered
## image. ## image.
TextSymbol = namedtuple("TextSymbol", "label symbol scale")
def createLabel(label, angle):
symbol = QtGui.QPainterPath()
#symbol.addText(0, 0, QFont("San Serif", 10), label)
f = QtGui.QFont()
f.setPointSize(10)
symbol.addText(0, 0, f, label)
br = symbol.boundingRect()
scale = min(1. / br.width(), 1. / br.height())
tr = QtGui.QTransform()
tr.scale(scale, scale)
tr.rotate(angle)
tr.translate(-br.x() - br.width()/2., -br.y() - br.height()/2.)
return TextSymbol(label, tr.map(symbol), 0.1 / scale)
random_str = lambda : (''.join([chr(np.random.randint(ord('A'),ord('z'))) for i in range(np.random.randint(1,5))]), np.random.randint(0, 360))
s2 = pg.ScatterPlotItem(size=10, pen=pg.mkPen('w'), pxMode=True) s2 = pg.ScatterPlotItem(size=10, pen=pg.mkPen('w'), pxMode=True)
pos = np.random.normal(size=(2,n), scale=1e-5) pos = np.random.normal(size=(2,n), scale=1e-5)
spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': i%5, 'size': 5+i/10.} for i in range(n)] spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': i%5, 'size': 5+i/10.} for i in range(n)]
s2.addPoints(spots) s2.addPoints(spots)
spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': label[1], 'size': label[2]*(5+i/10.)} for (i, label) in [(i, createLabel(*random_str())) for i in range(n)]]
s2.addPoints(spots)
w2.addItem(s2) w2.addItem(s2)
s2.sigClicked.connect(clicked) s2.sigClicked.connect(clicked)

View File

@ -126,7 +126,7 @@ class SymbolAtlas(object):
keyi = None keyi = None
sourceRecti = None sourceRecti = None
for i, rec in enumerate(opts): for i, rec in enumerate(opts):
key = (rec[3], rec[2], id(rec[4]), id(rec[5])) # TODO: use string indexes? key = (id(rec[3]), rec[2], id(rec[4]), id(rec[5])) # TODO: use string indexes?
if key == keyi: if key == keyi:
sourceRect[i] = sourceRecti sourceRect[i] = sourceRecti
else: else:
@ -136,6 +136,7 @@ class SymbolAtlas(object):
newRectSrc = QtCore.QRectF() newRectSrc = QtCore.QRectF()
newRectSrc.pen = rec['pen'] newRectSrc.pen = rec['pen']
newRectSrc.brush = rec['brush'] newRectSrc.brush = rec['brush']
newRectSrc.symbol = rec[3]
self.symbolMap[key] = newRectSrc self.symbolMap[key] = newRectSrc
self.atlasValid = False self.atlasValid = False
sourceRect[i] = newRectSrc sourceRect[i] = newRectSrc
@ -151,7 +152,7 @@ class SymbolAtlas(object):
images = [] images = []
for key, sourceRect in self.symbolMap.items(): for key, sourceRect in self.symbolMap.items():
if sourceRect.width() == 0: if sourceRect.width() == 0:
img = renderSymbol(key[0], key[1], sourceRect.pen, sourceRect.brush) img = renderSymbol(sourceRect.symbol, key[1], sourceRect.pen, sourceRect.brush)
images.append(img) ## we only need this to prevent the images being garbage collected immediately images.append(img) ## we only need this to prevent the images being garbage collected immediately
arr = fn.imageToArray(img, copy=False, transpose=False) arr = fn.imageToArray(img, copy=False, transpose=False)
else: else:

View File

@ -1,3 +1,4 @@
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg import pyqtgraph as pg
import numpy as np import numpy as np
app = pg.mkQApp() app = pg.mkQApp()
@ -10,6 +11,13 @@ def test_scatterplotitem():
# set view range equal to its bounding rect. # set view range equal to its bounding rect.
# This causes plots to look the same regardless of pxMode. # This causes plots to look the same regardless of pxMode.
plot.setRange(rect=plot.boundingRect()) plot.setRange(rect=plot.boundingRect())
# test SymbolAtlas accepts custom symbol
s = pg.ScatterPlotItem()
symbol = QtGui.QPainterPath()
symbol.addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1))
s.addPoints([{'pos': [0,0], 'data': 1, 'symbol': symbol}])
for i, pxMode in enumerate([True, False]): for i, pxMode in enumerate([True, False]):
for j, useCache in enumerate([True, False]): for j, useCache in enumerate([True, False]):
s = pg.ScatterPlotItem() s = pg.ScatterPlotItem()