WIP incrementally update step array format
							parent
							
								
									5ca0d1a19d
								
							
						
					
					
						commit
						447549e1af
					
				| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue