WIP incrementally update step array format

incremental_update_paths
Tyler Goodlet 2022-04-24 12:33:25 -04:00
parent b97ec38baf
commit b2b31b8f84
2 changed files with 215 additions and 69 deletions

View File

@ -58,36 +58,55 @@ def step_path_arrays_from_1d(
'''
y_out = y.copy()
x_out = x.copy()
x2 = np.empty(
# the data + 2 endpoints on either end for
# "termination of the path".
(len(x) + 1, 2),
# we want to align with OHLC or other sampling style
# bars likely so we need fractinal values
dtype=float,
)
x2[0] = x[0] - 0.5
x2[1] = x[0] + 0.5
x2[1:] = x[:, np.newaxis] + 0.5
# x2 = np.empty(
# # the data + 2 endpoints on either end for
# # "termination of the path".
# (len(x) + 1, 2),
# # we want to align with OHLC or other sampling style
# # bars likely so we need fractinal values
# dtype=float,
# )
x2 = np.broadcast_to(
x[:, None],
(
x_out.size,
# 4, # only ohlc
2,
),
) + np.array([-0.5, 0.5])
# x2[0] = x[0] - 0.5
# x2[1] = x[0] + 0.5
# x2[0, 0] = x[0] - 0.5
# x2[0, 1] = x[0] + 0.5
# x2[1:] = x[:, np.newaxis] + 0.5
# import pdbpp
# pdbpp.set_trace()
# flatten to 1-d
x_out = x2.reshape(x2.size)
# x_out = x2.reshape(x2.size)
x_out = x2
# we create a 1d with 2 extra indexes to
# hold the start and (current) end value for the steps
# on either end
y2 = np.empty((len(y), 2), dtype=y.dtype)
y2[:] = y[:, np.newaxis]
y2[-1] = 0
y_out = np.empty(
2*len(y) + 2,
dtype=y.dtype
)
y_out = y2
# y_out = np.empty(
# 2*len(y) + 2,
# dtype=y.dtype
# )
# flatten and set 0 endpoints
y_out[1:-1] = y2.reshape(y2.size)
y_out[0] = 0
y_out[-1] = 0
# y_out[1:-1] = y2.reshape(y2.size)
# y_out[0] = 0
# y_out[-1] = 0
if not include_endpoints:
return x_out[:-1], y_out[:-1]
@ -414,16 +433,16 @@ class FastAppendCurve(pg.GraphicsObject):
# step mode: draw flat top discrete "step"
# over the index space for each datum.
if self._step_mode:
x_out, y_out = step_path_arrays_from_1d(
x_out,
y_out,
)
# self.disable_cache()
# flip_cache = True
# if self._step_mode:
# x_out, y_out = step_path_arrays_from_1d(
# x_out,
# y_out,
# )
# # self.disable_cache()
# # flip_cache = True
# TODO: numba this bish
profiler('generated step arrays')
# # TODO: numba this bish
# profiler('generated step arrays')
if should_redraw:
if self.path:
@ -501,27 +520,26 @@ class FastAppendCurve(pg.GraphicsObject):
new_y = y[-append_length - 2:-1]
profiler('sliced append path')
if self._step_mode:
new_x, new_y = step_path_arrays_from_1d(
new_x,
new_y,
)
# [1:] since we don't need the vertical line normally at
# the beginning of the step curve taking the first (x,
# y) poing down to the x-axis **because** this is an
# appended path graphic.
new_x = new_x[1:]
new_y = new_y[1:]
# if self._step_mode:
# new_x, new_y = step_path_arrays_from_1d(
# new_x,
# new_y,
# )
# # [1:] since we don't need the vertical line normally at
# # the beginning of the step curve taking the first (x,
# # y) poing down to the x-axis **because** this is an
# # appended path graphic.
# new_x = new_x[1:]
# new_y = new_y[1:]
# self.disable_cache()
# flip_cache = True
# # self.disable_cache()
# # flip_cache = True
profiler('generated step data')
# profiler('generated step data')
else:
profiler(
f'diffed array input, append_length={append_length}'
)
profiler(
f'diffed array input, append_length={append_length}'
)
# if should_ds:
# new_x, new_y = self.downsample(
@ -655,6 +673,10 @@ class FastAppendCurve(pg.GraphicsObject):
# self.disable_cache()
# self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
def reset_cache(self) -> None:
self.disable_cache()
self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
def disable_cache(self) -> None:
'''
Disable the use of the pixel coordinate cache and trigger a geo event.

View File

@ -46,6 +46,7 @@ from ._ohlc import (
)
from ._curve import (
FastAppendCurve,
step_path_arrays_from_1d,
)
from ._compression import (
# ohlc_flatten,
@ -149,8 +150,8 @@ class Flow(msgspec.Struct): # , frozen=True):
is_ohlc: bool = False
render: bool = True # toggle for display loop
flat: Optional[ShmArray] = None
x_basis: Optional[np.ndarray] = None
gy: Optional[ShmArray] = None
gx: Optional[np.ndarray] = None
_iflat_last: int = 0
_iflat_first: int = 0
@ -360,7 +361,7 @@ class Flow(msgspec.Struct): # , frozen=True):
flow=self,
# just swap in the flat view
# data_t=lambda array: self.flat.array,
# data_t=lambda array: self.gy.array,
last_read=read,
draw_path=partial(
rowarr_to_path,
@ -413,37 +414,37 @@ class Flow(msgspec.Struct): # , frozen=True):
if should_line:
fields = ['open', 'high', 'low', 'close']
if self.flat is None:
if self.gy is None:
# create a flattened view onto the OHLC array
# which can be read as a line-style format
shm = self.shm
# flat = self.flat = self.shm.unstruct_view(fields)
self.flat = self.shm.ustruct(fields)
# flat = self.gy = self.shm.unstruct_view(fields)
self.gy = self.shm.ustruct(fields)
first = self._iflat_first = self.shm._first.value
last = self._iflat_last = self.shm._last.value
# write pushed data to flattened copy
self.flat[first:last] = rfn.structured_to_unstructured(
self.gy[first:last] = rfn.structured_to_unstructured(
self.shm.array[fields]
)
# generate an flat-interpolated x-domain
self.x_basis = (
self.gx = (
np.broadcast_to(
shm._array['index'][:, None],
(
shm._array.size,
# 4, # only ohlc
self.flat.shape[1],
self.gy.shape[1],
),
) + np.array([-0.5, 0, 0, 0.5])
)
assert self.flat.any()
assert self.gy.any()
# print(f'unstruct diff: {time.time() - start}')
# profiler('read unstr view bars to line')
# start = self.flat._first.value
# start = self.gy._first.value
# update flatted ohlc copy
(
iflat_first,
@ -461,15 +462,15 @@ class Flow(msgspec.Struct): # , frozen=True):
if iflat_first != ishm_first:
# write newly prepended data to flattened copy
self.flat[
self.gy[
ishm_first:iflat_first
] = rfn.structured_to_unstructured(
self.shm.array[fields][:iflat_first]
)
self._iflat_first = ishm_first
# # flat = self.flat = self.shm.unstruct_view(fields)
# self.flat = self.shm.ustruct(fields)
# # flat = self.gy = self.shm.unstruct_view(fields)
# self.gy = self.shm.ustruct(fields)
# # self._iflat_last = self.shm._last.value
# # self._iflat_first = self.shm._first.value
@ -481,12 +482,12 @@ class Flow(msgspec.Struct): # , frozen=True):
self.shm._array[iflat:ishm_last][fields]
)
self.flat[iflat:ishm_last][:] = to_update
self.gy[iflat:ishm_last][:] = to_update
profiler('updated ustruct OHLC data')
# slice out up-to-last step contents
y_flat = self.flat[ishm_first:ishm_last]
x_flat = self.x_basis[ishm_first:ishm_last]
y_flat = self.gy[ishm_first:ishm_last]
x_flat = self.gx[ishm_first:ishm_last]
# update local last-index tracking
self._iflat_last = ishm_last
@ -577,16 +578,139 @@ class Flow(msgspec.Struct): # , frozen=True):
# graphics.draw_last(last)
else:
# ``FastAppendCurve`` case:
array_key = array_key or self.name
graphics.update_from_array(
x=array['index'],
y=array[array_key],
# ``FastAppendCurve`` case:
if graphics._step_mode and self.gy is None:
# create a flattened view onto the OHLC array
# which can be read as a line-style format
shm = self.shm
# fields = ['index', array_key]
i = shm._array['index']
out = shm._array[array_key]
self.gx, self.gy = step_path_arrays_from_1d(i, out)
# flat = self.gy = self.shm.unstruct_view(fields)
# self.gy = self.shm.ustruct(fields)
# first = self._iflat_first = self.shm._first.value
# last = self._iflat_last = self.shm._last.value
# # write pushed data to flattened copy
# self.gy[first:last] = rfn.structured_to_unstructured(
# self.shm.array[fields]
# )
# # generate an flat-interpolated x-domain
# self.gx = (
# np.broadcast_to(
# shm._array['index'][:, None],
# (
# shm._array.size,
# # 4, # only ohlc
# self.gy.shape[1],
# ),
# ) + np.array([-0.5, 0, 0, 0.5])
# )
# assert self.gy.any()
# print(f'unstruct diff: {time.time() - start}')
# profiler('read unstr view bars to line')
# start = self.gy._first.value
# update flatted ohlc copy
if graphics._step_mode:
(
iflat_first,
iflat,
ishm_last,
ishm_first,
) = (
self._iflat_first,
self._iflat_last,
self.shm._last.value,
self.shm._first.value
)
# check for shm prepend updates since last read.
if iflat_first != ishm_first:
# write newly prepended data to flattened copy
_gx, self.gy[
ishm_first:iflat_first
] = step_path_arrays_from_1d(
self.shm.array['index'][:iflat_first],
self.shm.array[array_key][:iflat_first],
)
self._iflat_first = ishm_first
# # flat = self.gy = self.shm.unstruct_view(fields)
# self.gy = self.shm.ustruct(fields)
# # self._iflat_last = self.shm._last.value
# # self._iflat_first = self.shm._first.value
# # do an update for the most recent prepend
# # index
# iflat = ishm_first
if iflat != ishm_last:
_x, to_update = step_path_arrays_from_1d(
self.shm._array[iflat:ishm_last]['index'],
self.shm._array[iflat:ishm_last][array_key],
)
# to_update = rfn.structured_to_unstructured(
# self.shm._array[iflat:ishm_last][fields]
# )
# import pdbpp
# pdbpp.set_trace()
self.gy[iflat:ishm_last-1] = to_update
self.gy[-1] = 0
print(f'updating step curve {to_update}')
profiler('updated step curve data')
# slice out up-to-last step contents
x_step = self.gx[ishm_first:ishm_last]
x = x_step.reshape(-1)
y_step = self.gy[ishm_first:ishm_last]
y = y_step.reshape(-1)
profiler('sliced step data')
# update local last-index tracking
self._iflat_last = ishm_last
# reshape to 1d for graphics rendering
# y = y_flat.reshape(-1)
# x = x_flat.reshape(-1)
# do all the same for only in-view data
y_iv = y_step[ivl:ivr].reshape(-1)
x_iv = x_step[ivl:ivr].reshape(-1)
# y_iv = y_iv_flat.reshape(-1)
# x_iv = x_iv_flat.reshape(-1)
profiler('flattened ustruct in-view OHLC data')
# legacy full-recompute-everytime method
# x, y = ohlc_flatten(array)
# x_iv, y_iv = ohlc_flatten(in_view)
# profiler('flattened OHLC data')
graphics.reset_cache()
else:
x = array['index']
y = array[array_key]
x_iv = in_view['index']
y_iv = in_view[array_key]
graphics.update_from_array(
x=x,
y=y,
x_iv=x_iv,
y_iv=y_iv,
x_iv=in_view['index'],
y_iv=in_view[array_key],
view_range=(ivl, ivr) if use_vr else None,
**kwargs