Skip to content

Commit 5402648

Browse files
committed
Curve plotting: fixed bugs/performance issues (dots)
1 parent b487dc8 commit 5402648

File tree

2 files changed

+86
-76
lines changed

2 files changed

+86
-76
lines changed

qwt/painter.py

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -309,37 +309,28 @@ def drawPoint(self, painter, pos):
309309
return
310310
painter.drawPoint(pos)
311311

312-
def drawPoints(self, painter, points, pointCount):
313-
deviceClipping, clipRect = qwtIsClippingNeeded(painter)
314-
if isinstance(points[0], QPointF):
315-
if deviceClipping:
316-
clippedPolygon = QPolygonF(pointCount)
317-
clippedData = clippedPolygon.data()
318-
numClippedPoints = 0
319-
for point in points:
320-
if clipRect.contains(point):
321-
clippedData[numClippedPoints] = point
322-
numClippedPoints += 1
323-
painter.drawPoints(clippedData, numClippedPoints)
324-
else:
325-
painter.drawPoints(points, pointCount)
312+
def drawPoints(self, painter, *args):
313+
if len(args) == 2:
314+
points, pointCount = args
326315
else:
327-
if deviceClipping:
316+
polygon, = args
317+
points, pointCount = polygon.data(), polygon.size()
318+
if isinstance(polygon, QPolygonF):
319+
points.setsize(pointCount*np.finfo(float).dtype.itemsize)
320+
else:
321+
points.setsize(pointCount*np.iinfo(int).dtype.itemsize)
322+
deviceClipping, clipRect = qwtIsClippingNeeded(painter)
323+
if deviceClipping:
324+
if isinstance(polygon, QPointF):
328325
minX = np.ceil(clipRect.left())
329326
maxX = np.floor(clipRect.right())
330327
minY = np.ceil(clipRect.top())
331328
maxY = np.floor(clipRect.bottom())
332-
r = QRect(minX, minY, maxX-minX, maxY-minY)
333-
clippedPolygon = QPolygon(pointCount)
334-
clippedData = clippedPolygon.data()
335-
numClippedPoints = 0
336-
for point in points:
337-
if r.contains(point):
338-
clippedData[numClippedPoints] = point
339-
numClippedPoints += 1
340-
painter.drawPoints(clippedData, numClippedPoints)
341-
else:
342-
painter.drawPoints(points, pointCount)
329+
clipRect = QRect(minX, minY, maxX-minX, maxY-minY)
330+
clippedPolygon = polygon.intersected(QPolygon(clipRect))
331+
painter.drawPoints(clippedPolygon)
332+
else:
333+
painter.drawPoints(polygon)
343334

344335
def drawImage(self, painter, rect, image):
345336
alignedRect = rect.toAlignedRect()

qwt/point_mapper.py

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,21 @@
1010
from qwt.qt.QtGui import QPolygon, QPolygonF, QImage, QPainter
1111
from qwt.qt.QtCore import QThread, Qt, QPoint, QPointF, QRectF
1212

13-
from qwt.pixel_matrix import QwtPixelMatrix
13+
#from qwt.pixel_matrix import QwtPixelMatrix
1414

1515
import numpy as np
1616

1717

18+
def qwtNoRoundF(data):
19+
return data
20+
21+
def qwtRoundF(data):
22+
return np.rint(data)
23+
24+
def qwtRoundI(data):
25+
return np.array(np.rint(data), dtype=np.int)
26+
27+
1828
class QwtDotsCommand(object):
1929
def __init__(self):
2030
self.series = None
@@ -39,26 +49,31 @@ def qwtRenderDots(xMap, yMap, command, pos, image):
3949

4050
def qwtToPoints(boundingRect, xMap, yMap, series, from_, to, round_,
4151
Polygon):
42-
Point = QPointF if isinstance(Polygon, QPolygonF) else QPoint
43-
points = []
44-
if boundingRect.isValid():
45-
for i in range(from_, to+1):
46-
sample = series.sample(i)
47-
x = xMap.transform(sample.x())
48-
y = yMap.transform(sample.y())
49-
if boundingRect.contains(x, y):
50-
points.append(Point(round_(x), round_(y)))
51-
else:
52-
for i in range(from_, to+1):
53-
sample = series.sample(i)
54-
x = xMap.transform(sample.x())
55-
y = yMap.transform(sample.y())
56-
points.append(Point(round_(x), round_(y)))
57-
return Polygon(list(set(points)))
52+
Point = QPointF if Polygon is QPolygonF else QPoint
53+
polygon = qwtToPolylineFiltered(xMap, yMap, series, from_, to, round_,
54+
Polygon, Point)
55+
return polygon
56+
# # Pure Python implementation (catastophic performance)
57+
# Point = QPointF if Polygon is QPolygonF else QPoint
58+
# points = []
59+
# if boundingRect.isValid():
60+
# for i in range(from_, to+1):
61+
# sample = series.sample(i)
62+
# x = xMap.transform(sample.x())
63+
# y = yMap.transform(sample.y())
64+
# if boundingRect.contains(x, y):
65+
# points.append(Point(round_(x), round_(y)))
66+
# else:
67+
# for i in range(from_, to+1):
68+
# sample = series.sample(i)
69+
# x = xMap.transform(sample.x())
70+
# y = yMap.transform(sample.y())
71+
# points.append(Point(round_(x), round_(y)))
72+
# return Polygon(list(set(points)))
5873

5974
def qwtToPointsI(boundingRect, xMap, yMap, series, from_, to):
60-
return qwtToPoints(boundingRect, xMap, yMap, series, from_, to, round,
61-
QPolygon)
75+
return qwtToPoints(boundingRect, xMap, yMap, series, from_, to,
76+
qwtNoRoundF, QPolygon)
6277

6378
def qwtToPointsF(boundingRect, xMap, yMap, series, from_, to, round_):
6479
return qwtToPoints(boundingRect, xMap, yMap, series, from_, to, round_,
@@ -69,14 +84,18 @@ def qwtToPolylineFiltered(xMap, yMap, series, from_, to, round_,
6984
Polygon, Point):
7085
polyline = Polygon(to-from_+1)
7186
pointer = polyline.data()
72-
dtype = np.float if Polygon is QPolygonF else np.int
73-
pointer.setsize(2*polyline.size()*np.finfo(dtype).dtype.itemsize)
87+
if Polygon is QPolygonF:
88+
dtype, tinfo = np.float, np.finfo
89+
else:
90+
dtype, tinfo = np.int, np.iinfo
91+
pointer.setsize(2*polyline.size()*tinfo(dtype).dtype.itemsize)
7492
memory = np.frombuffer(pointer, dtype)
75-
memory[from_*2:to*2+1:2] =\
76-
np.round(xMap.transform(series.xData()))[from_:to+1]
77-
memory[from_*2+1:to*2+2:2] =\
78-
np.round(yMap.transform(series.yData()))[from_:to+1]
93+
memory[:(to-from_)*2+1:2] =\
94+
round_(xMap.transform(series.xData()))[from_:to+1]
95+
memory[1:(to-from_)*2+2:2] =\
96+
round_(yMap.transform(series.yData()))[from_:to+1]
7997
return polyline
98+
# # Pure Python implementation (catastophic performance)
8099
# points = polyline.data()
81100
# sample0 = series.sample(from_)
82101
# points[0].setX(round_(xMap.transform(sample0.x())))
@@ -93,7 +112,7 @@ def qwtToPolylineFiltered(xMap, yMap, series, from_, to, round_,
93112
# return polyline
94113

95114
def qwtToPolylineFilteredI(xMap, yMap, series, from_, to):
96-
return qwtToPolylineFiltered(xMap, yMap, series, from_, to, round,
115+
return qwtToPolylineFiltered(xMap, yMap, series, from_, to, qwtRoundI,
97116
QPolygon, QPoint)
98117

99118
def qwtToPolylineFilteredF(xMap, yMap, series, from_, to, round_):
@@ -104,18 +123,22 @@ def qwtToPolylineFilteredF(xMap, yMap, series, from_, to, round_):
104123
def qwtToPointsFiltered(boundingRect, xMap, yMap, series, from_, to,
105124
Polygon):
106125
Point = QPointF if isinstance(Polygon, QPolygonF) else QPoint
107-
if isinstance(boundingRect, QRectF):
108-
pixelMatrix = QwtPixelMatrix(boundingRect.toAlignedRect())
109-
else:
110-
pixelMatrix = QwtPixelMatrix(boundingRect)
111-
points = []
112-
for i in range(from_, to+1):
113-
sample = series.sample(i)
114-
x = int(round(xMap.transform(sample.x())))
115-
y = int(round(yMap.transform(sample.y())))
116-
if pixelMatrix.testAndSetPixel(x, y, True) == False:
117-
points.append(Point(x, y))
118-
return Polygon(list(points))
126+
return qwtToPolylineFiltered(xMap, yMap, series, from_, to, qwtRoundI,
127+
Polygon, Point)
128+
# # Pure Python implementation (catastophic performance)
129+
# Point = QPointF if Polygon is QPolygonF else QPoint
130+
# if isinstance(boundingRect, QRectF):
131+
# pixelMatrix = QwtPixelMatrix(boundingRect.toAlignedRect())
132+
# else:
133+
# pixelMatrix = QwtPixelMatrix(boundingRect)
134+
# points = []
135+
# for i in range(from_, to+1):
136+
# sample = series.sample(i)
137+
# x = int(round(xMap.transform(sample.x())))
138+
# y = int(round(yMap.transform(sample.y())))
139+
# if pixelMatrix.testAndSetPixel(x, y, True) == False:
140+
# points.append(Point(x, y))
141+
# return Polygon(list(points))
119142

120143
def qwtToPointsFilteredI(boundingRect, xMap, yMap, series, from_, to):
121144
return qwtToPointsFiltered(boundingRect, xMap, yMap, series, from_, to,
@@ -163,22 +186,20 @@ def boundingRect(self):
163186
return self.__data.boundingRect
164187

165188
def toPolygonF(self, xMap, yMap, series, from_, to):
166-
round_ = round
167-
no_round = lambda x: x
168189
if self.__data.flags & QwtPointMapper.WeedOutPoints:
169190
if self.__data.flags & QwtPointMapper.RoundPoints:
170191
polyline = qwtToPolylineFilteredF(xMap, yMap, series,
171-
from_, to, round_)
192+
from_, to, qwtRoundF)
172193
else:
173194
polyline = qwtToPolylineFilteredF(xMap, yMap, series,
174-
from_, to, no_round)
195+
from_, to, qwtNoRoundF)
175196
else:
176197
if self.__data.flags & QwtPointMapper.RoundPoints:
177198
polyline = qwtToPointsF(self.qwtInvalidRect, xMap, yMap,
178-
series, from_, to, round_)
199+
series, from_, to, qwtRoundF)
179200
else:
180201
polyline = qwtToPointsF(self.qwtInvalidRect, xMap, yMap,
181-
series, from_, to, no_round)
202+
series, from_, to, qwtNoRoundF)
182203
return polyline
183204

184205
def toPolygon(self, xMap, yMap, series, from_, to):
@@ -190,26 +211,24 @@ def toPolygon(self, xMap, yMap, series, from_, to):
190211
return polyline
191212

192213
def toPointsF(self, xMap, yMap, series, from_, to):
193-
round_ = round
194-
no_round = lambda x: x
195214
if self.__data.flags & QwtPointMapper.WeedOutPoints:
196215
if self.__data.flags & QwtPointMapper.RoundPoints:
197216
if self.__data.boundingRect.isValid():
198217
points = qwtToPointsFilteredF(self.__data.boundingRect,
199218
xMap, yMap, series, from_, to)
200219
else:
201220
points = qwtToPolylineFilteredF(xMap, yMap, series,
202-
from_, to, round_)
221+
from_, to, qwtRoundF)
203222
else:
204223
points = qwtToPolylineFilteredF(xMap, yMap, series,
205-
from_, to, no_round)
224+
from_, to, qwtNoRoundF)
206225
else:
207226
if self.__data.flags & QwtPointMapper.RoundPoints:
208227
points = qwtToPointsF(self.__data.boundingRect,
209-
xMap, yMap, series, from_, to, round_)
228+
xMap, yMap, series, from_, to, qwtRoundF)
210229
else:
211230
points = qwtToPointsF(self.__data.boundingRect,
212-
xMap, yMap, series, from_, to, no_round)
231+
xMap, yMap, series, from_, to, qwtNoRoundF)
213232
return points
214233

215234
def toPoints(self, xMap, yMap, series, from_, to):

0 commit comments

Comments
 (0)