use qpolygonf underlying buffer as backstore
This commit is contained in:
parent
270fc59cab
commit
8f4104a9ab
@ -1703,10 +1703,26 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
|||||||
path = QtGui.QPainterPath()
|
path = QtGui.QPainterPath()
|
||||||
n = x.shape[0]
|
n = x.shape[0]
|
||||||
|
|
||||||
|
connect_array = None
|
||||||
|
if isinstance(connect, np.ndarray):
|
||||||
|
# make connect argument contain only str type
|
||||||
|
connect_array, connect = connect, 'array'
|
||||||
|
|
||||||
|
qtver = [int(x) for x in QtVersion.split('.')]
|
||||||
|
qt6 = qtver[0] == 6
|
||||||
|
|
||||||
|
use_qpolygonf = connect == 'all' or (qt6 and connect in ['pairs', 'finite'])
|
||||||
|
|
||||||
|
if use_qpolygonf:
|
||||||
|
backstore = create_qpolygonf(n)
|
||||||
|
arr = np.frombuffer(ndarray_from_qpolygonf(backstore), dtype=[('x', 'f8'), ('y', 'f8')])
|
||||||
|
else:
|
||||||
backstore = bytearray(4 + n*20 + 8)
|
backstore = bytearray(4 + n*20 + 8)
|
||||||
arr = np.frombuffer(backstore, dtype=[('c', '>i4'), ('x', '>f8'), ('y', '>f8')],
|
arr = np.frombuffer(backstore, dtype=[('c', '>i4'), ('x', '>f8'), ('y', '>f8')],
|
||||||
count=n, offset=4)
|
count=n, offset=4)
|
||||||
struct.pack_into('>i', backstore, 0, n)
|
struct.pack_into('>i', backstore, 0, n)
|
||||||
|
# cStart, fillRule (Qt.OddEvenFill)
|
||||||
|
struct.pack_into('>ii', backstore, 4+n*20, 0, 0)
|
||||||
|
|
||||||
# Fill array with vertex values
|
# Fill array with vertex values
|
||||||
arr['x'] = x
|
arr['x'] = x
|
||||||
@ -1715,10 +1731,8 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
|||||||
# inf/nans completely prevent the plot from being displayed starting on
|
# inf/nans completely prevent the plot from being displayed starting on
|
||||||
# Qt version 5.12.3; these must now be manually cleaned out.
|
# Qt version 5.12.3; these must now be manually cleaned out.
|
||||||
isfinite = None
|
isfinite = None
|
||||||
qtver = [int(x) for x in QtVersion.split('.')]
|
|
||||||
qt6 = qtver[0] == 6
|
|
||||||
|
|
||||||
if eq(connect, 'finite') and qt6:
|
if connect == 'finite' and qt6:
|
||||||
# we must preserve NaN values here
|
# we must preserve NaN values here
|
||||||
pass
|
pass
|
||||||
elif qtver >= [5, 12, 3] and finiteCheck:
|
elif qtver >= [5, 12, 3] and finiteCheck:
|
||||||
@ -1736,29 +1750,23 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
|||||||
arr[:] = arr[:][idx]
|
arr[:] = arr[:][idx]
|
||||||
|
|
||||||
# decide which points are connected by lines
|
# decide which points are connected by lines
|
||||||
if eq(connect, 'all'):
|
if connect == 'all':
|
||||||
polygon = arrayToQPolygonF(
|
path.addPolygon(backstore)
|
||||||
arr['x'],
|
|
||||||
arr['y']
|
|
||||||
)
|
|
||||||
path.addPolygon(polygon)
|
|
||||||
return path
|
return path
|
||||||
elif eq(connect, 'pairs'):
|
elif connect == 'pairs':
|
||||||
if qt6:
|
if qt6:
|
||||||
|
if n % 2 == 1:
|
||||||
|
arr = arr[:-1]
|
||||||
nans = np.broadcast_to(np.nan, (n // 2, 1))
|
nans = np.broadcast_to(np.nan, (n // 2, 1))
|
||||||
if n % 2 == 0:
|
|
||||||
xs = np.column_stack([arr['x'].reshape((-1, 2)), nans]).ravel()
|
xs = np.column_stack([arr['x'].reshape((-1, 2)), nans]).ravel()
|
||||||
ys = np.column_stack([arr['y'].reshape((-1, 2)), nans]).ravel()
|
ys = np.column_stack([arr['y'].reshape((-1, 2)), nans]).ravel()
|
||||||
else:
|
|
||||||
xs = np.column_stack([arr['x'][:-1].reshape((-1, 2)), nans]).ravel()
|
|
||||||
ys = np.column_stack([arr['y'][:-1].reshape((-1, 2)), nans]).ravel()
|
|
||||||
polygon = arrayToQPolygonF(xs, ys)
|
polygon = arrayToQPolygonF(xs, ys)
|
||||||
path.addPolygon(polygon)
|
path.addPolygon(polygon)
|
||||||
return path
|
return path
|
||||||
else:
|
else:
|
||||||
arr[:]['c'][::2] = 0
|
arr['c'][::2] = 0
|
||||||
arr[:]['c'][1::2] = 1 # connect every 2nd point to every 1st one
|
arr['c'][1::2] = 1 # connect every 2nd point to every 1st one
|
||||||
elif eq(connect, 'finite'):
|
elif connect == 'finite':
|
||||||
# Let's call a point with either x or y being nan is an invalid point.
|
# Let's call a point with either x or y being nan is an invalid point.
|
||||||
# A point will anyway not connect to an invalid point regardless of the
|
# A point will anyway not connect to an invalid point regardless of the
|
||||||
# 'c' value of the invalid point. Therefore, we should set 'c' to 0 for
|
# 'c' value of the invalid point. Therefore, we should set 'c' to 0 for
|
||||||
@ -1769,24 +1777,21 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
|||||||
argNaNs = np.argwhere(isfinite)
|
argNaNs = np.argwhere(isfinite)
|
||||||
first = 0 if len(argNaNs) == 0 else argNaNs.item(0)
|
first = 0 if len(argNaNs) == 0 else argNaNs.item(0)
|
||||||
|
|
||||||
# if found, use the portion of the array from that point on
|
# if found, set first element to first found finite element
|
||||||
polygon = arrayToQPolygonF(x[first:], y[first:])
|
arr[0] = arr[first]
|
||||||
path.addPolygon(polygon)
|
path.addPolygon(backstore)
|
||||||
return path
|
return path
|
||||||
else:
|
else:
|
||||||
if isfinite is None:
|
if isfinite is None:
|
||||||
isfinite = np.isfinite(x) & np.isfinite(y)
|
isfinite = np.isfinite(x) & np.isfinite(y)
|
||||||
arr[1:]['c'] = isfinite[:-1]
|
arr[1:]['c'] = isfinite[:-1]
|
||||||
elif isinstance(connect, np.ndarray):
|
elif connect == 'array':
|
||||||
arr[1:]['c'] = connect[:-1]
|
arr[1:]['c'] = connect_array[:-1]
|
||||||
else:
|
else:
|
||||||
raise Exception('connect argument must be "all", "pairs", "finite", or array')
|
raise Exception('connect argument must be "all", "pairs", "finite", or array')
|
||||||
|
|
||||||
arr[0]['c'] = 0 # the first vertex has no previous vertex to connect
|
arr[0]['c'] = 0 # the first vertex has no previous vertex to connect
|
||||||
|
|
||||||
# cStart, fillRule (Qt.OddEvenFill)
|
|
||||||
struct.pack_into('>ii', backstore, 4+n*20, 0, 0)
|
|
||||||
|
|
||||||
# create QDataStream object and stream into QPainterPath
|
# create QDataStream object and stream into QPainterPath
|
||||||
path.strn = backstore
|
path.strn = backstore
|
||||||
if QT_LIB == "PyQt6":
|
if QT_LIB == "PyQt6":
|
||||||
@ -1799,6 +1804,29 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True):
|
|||||||
ds >> path
|
ds >> path
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
def ndarray_from_qpolygonf(polyline):
|
||||||
|
nbytes = 2 * len(polyline) * 8
|
||||||
|
if QT_LIB == "PySide2":
|
||||||
|
buffer = Qt.shiboken2.VoidPtr(polyline.data(), nbytes, True)
|
||||||
|
elif QT_LIB == "PySide6":
|
||||||
|
buffer = Qt.shiboken6.VoidPtr(polyline.data(), nbytes, True)
|
||||||
|
else:
|
||||||
|
buffer = polyline.data()
|
||||||
|
buffer.setsize(nbytes)
|
||||||
|
memory = np.frombuffer(buffer, np.double).reshape((-1, 2))
|
||||||
|
return memory
|
||||||
|
|
||||||
|
def create_qpolygonf(size):
|
||||||
|
if QtVersion.startswith("5"):
|
||||||
|
polyline = QtGui.QPolygonF(size)
|
||||||
|
else:
|
||||||
|
polyline = QtGui.QPolygonF()
|
||||||
|
if QT_LIB == "PySide6":
|
||||||
|
polyline.resize(size)
|
||||||
|
else:
|
||||||
|
polyline.fill(QtCore.QPointF(), size)
|
||||||
|
return polyline
|
||||||
|
|
||||||
def arrayToQPolygonF(x, y):
|
def arrayToQPolygonF(x, y):
|
||||||
"""
|
"""
|
||||||
Utility function to convert two 1D-NumPy arrays representing curve data
|
Utility function to convert two 1D-NumPy arrays representing curve data
|
||||||
@ -1831,24 +1859,8 @@ def arrayToQPolygonF(x, y):
|
|||||||
):
|
):
|
||||||
raise ValueError("Arguments must be 1D and the same size")
|
raise ValueError("Arguments must be 1D and the same size")
|
||||||
size = x.size
|
size = x.size
|
||||||
if QtVersion.startswith("5"):
|
polyline = create_qpolygonf(size)
|
||||||
polyline = QtGui.QPolygonF(size)
|
memory = ndarray_from_qpolygonf(polyline)
|
||||||
else:
|
|
||||||
polyline = QtGui.QPolygonF()
|
|
||||||
if QT_LIB == "PySide6":
|
|
||||||
polyline.resize(size)
|
|
||||||
else:
|
|
||||||
polyline.fill(QtCore.QPointF(), size)
|
|
||||||
nbytes = 2 * size * 8
|
|
||||||
if QT_LIB == "PySide2":
|
|
||||||
buffer = Qt.shiboken2.VoidPtr(polyline.data(), nbytes, True)
|
|
||||||
elif QT_LIB == "PySide6":
|
|
||||||
buffer = Qt.shiboken6.VoidPtr(polyline.data(), nbytes, True)
|
|
||||||
else:
|
|
||||||
buffer = polyline.data()
|
|
||||||
buffer.setsize(nbytes)
|
|
||||||
|
|
||||||
memory = np.frombuffer(buffer, np.double).reshape((-1, 2))
|
|
||||||
memory[:, 0] = x
|
memory[:, 0] = x
|
||||||
memory[:, 1] = y
|
memory[:, 1] = y
|
||||||
return polyline
|
return polyline
|
||||||
|
Loading…
Reference in New Issue
Block a user