1# -*- coding: utf-8 -*-
2"""
3Example demonstrating a variety of scatter plot features.
4"""
5
6
7
8## Add path to library (just for examples; you do not need this)
9import initExample
10
11from pyqtgraph.Qt import QtGui, QtCore
12import pyqtgraph as pg
13import numpy as np
14from collections import namedtuple
15from itertools import chain
16
17app = pg.mkQApp("Scatter Plot Item Example")
18mw = QtGui.QMainWindow()
19mw.resize(800,800)
20view = pg.GraphicsLayoutWidget()  ## GraphicsView with GraphicsLayout inserted by default
21mw.setCentralWidget(view)
22mw.show()
23mw.setWindowTitle('pyqtgraph example: ScatterPlot')
24
25## create four areas to add plots
26w1 = view.addPlot()
27w2 = view.addViewBox()
28w2.setAspectLocked(True)
29view.nextRow()
30w3 = view.addPlot()
31w4 = view.addPlot()
32print("Generating data, this takes a few seconds...")
33
34## Make all plots clickable
35clickedPen = pg.mkPen('b', width=2)
36lastClicked = []
37def clicked(plot, points):
38    global lastClicked
39    for p in lastClicked:
40        p.resetPen()
41    print("clicked points", points)
42    for p in points:
43        p.setPen(clickedPen)
44    lastClicked = points
45
46
47## There are a few different ways we can draw scatter plots; each is optimized for different types of data:
48
49## 1) All spots identical and transform-invariant (top-left plot).
50## In this case we can get a huge performance boost by pre-rendering the spot
51## image and just drawing that image repeatedly.
52
53n = 300
54s1 = pg.ScatterPlotItem(size=10, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120))
55pos = np.random.normal(size=(2,n), scale=1e-5)
56spots = [{'pos': pos[:,i], 'data': 1} for i in range(n)] + [{'pos': [0,0], 'data': 1}]
57s1.addPoints(spots)
58w1.addItem(s1)
59s1.sigClicked.connect(clicked)
60
61
62## 2) Spots are transform-invariant, but not identical (top-right plot).
63## In this case, drawing is almsot as fast as 1), but there is more startup
64## overhead and memory usage since each spot generates its own pre-rendered
65## image.
66
67TextSymbol = namedtuple("TextSymbol", "label symbol scale")
68
69def createLabel(label, angle):
70    symbol = QtGui.QPainterPath()
71    #symbol.addText(0, 0, QFont("San Serif", 10), label)
72    f = QtGui.QFont()
73    f.setPointSize(10)
74    symbol.addText(0, 0, f, label)
75    br = symbol.boundingRect()
76    scale = min(1. / br.width(), 1. / br.height())
77    tr = QtGui.QTransform()
78    tr.scale(scale, scale)
79    tr.rotate(angle)
80    tr.translate(-br.x() - br.width()/2., -br.y() - br.height()/2.)
81    return TextSymbol(label, tr.map(symbol), 0.1 / scale)
82
83random_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))
84
85s2 = pg.ScatterPlotItem(size=10, pen=pg.mkPen('w'), pxMode=True)
86pos = np.random.normal(size=(2,n), scale=1e-5)
87spots = [{'pos': pos[:,i], 'data': 1, 'brush':pg.intColor(i, n), 'symbol': i%10, 'size': 5+i/10.} for i in range(n)]
88s2.addPoints(spots)
89spots = [{'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)]]
90s2.addPoints(spots)
91w2.addItem(s2)
92s2.sigClicked.connect(clicked)
93
94
95## 3) Spots are not transform-invariant, not identical (bottom-left).
96## This is the slowest case, since all spots must be completely re-drawn
97## every time because their apparent transformation may have changed.
98
99s3 = pg.ScatterPlotItem(
100    pxMode=False,  # Set pxMode=False to allow spots to transform with the view
101    hoverable=True,
102    hoverPen=pg.mkPen('g'),
103    hoverSize=1e-6
104)
105spots3 = []
106for i in range(10):
107    for j in range(10):
108        spots3.append({'pos': (1e-6*i, 1e-6*j), 'size': 1e-6, 'pen': {'color': 'w', 'width': 2}, 'brush':pg.intColor(i*10+j, 100)})
109s3.addPoints(spots3)
110w3.addItem(s3)
111s3.sigClicked.connect(clicked)
112
113## Test performance of large scatterplots
114
115s4 = pg.ScatterPlotItem(
116    size=10,
117    pen=pg.mkPen(None),
118    brush=pg.mkBrush(255, 255, 255, 20),
119    hoverable=True,
120    hoverSymbol='s',
121    hoverSize=15,
122    hoverPen=pg.mkPen('r', width=2),
123    hoverBrush=pg.mkBrush('g'),
124)
125n = 10000
126pos = np.random.normal(size=(2, n), scale=1e-9)
127s4.addPoints(
128    x=pos[0],
129    y=pos[1],
130    # size=(np.random.random(n) * 20.).astype(int),
131    # brush=[pg.mkBrush(x) for x in np.random.randint(0, 256, (n, 3))],
132    data=np.arange(n)
133)
134w4.addItem(s4)
135s4.sigClicked.connect(clicked)
136
137if __name__ == '__main__':
138    pg.exec()
139