Toy with caching ds data, probably will revert..
							parent
							
								
									54a1397d2c
								
							
						
					
					
						commit
						9befc1fb1a
					
				| 
						 | 
				
			
			@ -223,9 +223,9 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
        lbar = max(l, start)
 | 
			
		||||
        rbar = min(r, stop)
 | 
			
		||||
 | 
			
		||||
        return vb.mapViewToDevice(
 | 
			
		||||
        return round(vb.mapViewToDevice(
 | 
			
		||||
            QLineF(lbar, 0, rbar, 0)
 | 
			
		||||
        ).length()
 | 
			
		||||
        ).length())
 | 
			
		||||
 | 
			
		||||
    # def should_ds_or_redraw(
 | 
			
		||||
    #     self,
 | 
			
		||||
| 
						 | 
				
			
			@ -297,7 +297,7 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
        y = y.flatten()
 | 
			
		||||
 | 
			
		||||
        # presumably?
 | 
			
		||||
        self._in_ds = True
 | 
			
		||||
        # self._in_ds = True
 | 
			
		||||
        return x, y
 | 
			
		||||
 | 
			
		||||
    def maybe_downsample(
 | 
			
		||||
| 
						 | 
				
			
			@ -339,29 +339,30 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
            gt=ms_slower_then,
 | 
			
		||||
        )
 | 
			
		||||
        flip_cache = False
 | 
			
		||||
 | 
			
		||||
        if self._xrange:
 | 
			
		||||
            istart, istop = self._xrange
 | 
			
		||||
        else:
 | 
			
		||||
            self._xrange = istart, istop = x[0], x[-1]
 | 
			
		||||
        # print(f"xrange: {self._xrange}")
 | 
			
		||||
        draw_full_path = True
 | 
			
		||||
 | 
			
		||||
        # XXX: lol brutal, the internals of `CurvePoint` (inherited by
 | 
			
		||||
        # our `LineDot`) required ``.getData()`` to work..
 | 
			
		||||
        self.xData = x
 | 
			
		||||
        self.yData = y
 | 
			
		||||
 | 
			
		||||
        # update internal array refs
 | 
			
		||||
        self._x, self._y = x, y
 | 
			
		||||
 | 
			
		||||
        # _, x_last = self._xrange = x[0], x[-1]
 | 
			
		||||
        # vr = self.viewRect()
 | 
			
		||||
        # l, r = int(vr.left()), int(vr.right())
 | 
			
		||||
        # l, r = self.view_range()
 | 
			
		||||
        # array = self._arrays[self.name]
 | 
			
		||||
        # start_index = ohlc[0]['index']
 | 
			
		||||
        # lbar = max(l, start_index) - start_index
 | 
			
		||||
        # rbar = min(r, ohlc[-1]['index']) - start_index
 | 
			
		||||
        # compute the length diffs between the first/last index entry in
 | 
			
		||||
        # the input data and the last indexes we have on record from the
 | 
			
		||||
        # last time we updated the curve index.
 | 
			
		||||
        if self._xrange:
 | 
			
		||||
            istart, istop = self._xrange
 | 
			
		||||
        else:
 | 
			
		||||
            self._xrange = istart, istop = x[0], x[-1]
 | 
			
		||||
 | 
			
		||||
        prepend_length = int(istart - x[0])
 | 
			
		||||
        append_length = int(x[-1] - istop)
 | 
			
		||||
 | 
			
		||||
        # print(f"xrange: {self._xrange}")
 | 
			
		||||
        if view_range:
 | 
			
		||||
            # lbar, rbar = view_range
 | 
			
		||||
            li, ri = view_range
 | 
			
		||||
            # x, y = x[lbar:rbar], y[lbar:rbar]
 | 
			
		||||
            # x, y = x_iv, y_iv
 | 
			
		||||
            profiler(f'view range slice {view_range}')
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +374,6 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
        uppx = self.x_uppx()
 | 
			
		||||
        px_width = self.px_width()
 | 
			
		||||
        uppx_diff = (uppx - self._last_uppx)
 | 
			
		||||
        self._last_uppx = uppx
 | 
			
		||||
 | 
			
		||||
        # step mode: draw flat top discrete "step"
 | 
			
		||||
        # over the index space for each datum.
 | 
			
		||||
| 
						 | 
				
			
			@ -401,6 +401,30 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
        x_to_path, y_to_path = x_iv_out, y_iv_out
 | 
			
		||||
 | 
			
		||||
        ds_key = px_width, uppx
 | 
			
		||||
 | 
			
		||||
        # always re-ds if we were dsed but the input range changes.
 | 
			
		||||
        if self._in_ds:
 | 
			
		||||
            # slice out the portion of the downsampled data that is
 | 
			
		||||
            # "in view" and **only** draw a path for that.
 | 
			
		||||
 | 
			
		||||
            entry = self._ds_cache.get(ds_key)
 | 
			
		||||
            if entry:
 | 
			
		||||
                x_ds_out, y_ds_out, first_i, last_i = entry
 | 
			
		||||
 | 
			
		||||
                # if last_i == x[-1]:
 | 
			
		||||
                log.info(
 | 
			
		||||
                    f'{self._name} has cached ds {ds_key} -> {entry}'
 | 
			
		||||
                )
 | 
			
		||||
                prepend_length = int(first_i - ri)
 | 
			
		||||
                append_length = int(ri - last_i)
 | 
			
		||||
 | 
			
		||||
                # x_to_path = x_ds_out
 | 
			
		||||
                # y_to_path = y_ds_out
 | 
			
		||||
 | 
			
		||||
                # else:
 | 
			
		||||
                #     log.warn(f'{self._name} ds updates unhandled!')
 | 
			
		||||
                    # DS only the new part?
 | 
			
		||||
 | 
			
		||||
        # check for downsampling conditions
 | 
			
		||||
        if (
 | 
			
		||||
            # std m4 downsample conditions
 | 
			
		||||
| 
						 | 
				
			
			@ -408,10 +432,13 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
            or uppx_diff <= -2
 | 
			
		||||
            or self._step_mode and abs(uppx_diff) >= 2
 | 
			
		||||
 | 
			
		||||
            # or self._in_ds and px_width > 1
 | 
			
		||||
        ):
 | 
			
		||||
            # if not uppx_diff >= 1:
 | 
			
		||||
            log.info(
 | 
			
		||||
                f'{self._name} sampler change: {self._last_uppx} -> {uppx}'
 | 
			
		||||
            )
 | 
			
		||||
            self._last_uppx = uppx
 | 
			
		||||
            # should_ds = {'px_width': px_width, 'uppx': uppx}
 | 
			
		||||
 | 
			
		||||
            # if self._step_mode:
 | 
			
		||||
| 
						 | 
				
			
			@ -430,10 +457,18 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
                px_width=px_width,
 | 
			
		||||
                uppx=uppx,
 | 
			
		||||
            )
 | 
			
		||||
            profiler(f'path downsample ds_key={ds_key}')
 | 
			
		||||
            profiler(
 | 
			
		||||
                f'path downsample ds_key={ds_key}\n'
 | 
			
		||||
                f'{x_iv_out.size}, {y_iv_out.size}'
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # cache downsampled outputs
 | 
			
		||||
            self._ds_cache[ds_key] = x_ds_out, y_ds_out, x[-1]
 | 
			
		||||
            self._ds_cache[ds_key] = (
 | 
			
		||||
                x_ds_out,
 | 
			
		||||
                y_ds_out,
 | 
			
		||||
                x[0],
 | 
			
		||||
                x[-1],
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            x_to_path = x_ds_out
 | 
			
		||||
            y_to_path = y_ds_out
 | 
			
		||||
| 
						 | 
				
			
			@ -458,38 +493,18 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
 | 
			
		||||
            self._in_ds = False
 | 
			
		||||
 | 
			
		||||
        # always re-ds if we were dsed but the input range changes.
 | 
			
		||||
        elif (
 | 
			
		||||
            self._in_ds  # and self._last_vr != view_range
 | 
			
		||||
        ):
 | 
			
		||||
            # slice out the portion of the downsampled data that is
 | 
			
		||||
            # "in view" and **only** draw a path for that.
 | 
			
		||||
 | 
			
		||||
            entry = self._ds_cache.get(ds_key)
 | 
			
		||||
            if entry:
 | 
			
		||||
                x_ds_out, y_ds_out, last_i = entry
 | 
			
		||||
 | 
			
		||||
                # if last_i == x[-1]:
 | 
			
		||||
                log.info(
 | 
			
		||||
                    f'{self._name} has cached ds {ds_key} -> {entry}'
 | 
			
		||||
                )
 | 
			
		||||
                # x_to_path = x_ds_out
 | 
			
		||||
                # y_to_path = y_ds_out
 | 
			
		||||
 | 
			
		||||
                # else:
 | 
			
		||||
                #     log.warn(f'{self._name} ds updates unhandled!')
 | 
			
		||||
                    # DS only the new part?
 | 
			
		||||
 | 
			
		||||
        # render path graphics
 | 
			
		||||
        log.info(
 | 
			
		||||
            # f'{self._name}: last sizes {x_to_path.size}, {y_to_path.size}',
 | 
			
		||||
            f'{self._name}: sizes {x_to_path.size}, {y_to_path.size}',
 | 
			
		||||
        )
 | 
			
		||||
        # log.info(
 | 
			
		||||
        #     # f'{self._name}: last sizes {x_to_path.size}, {y_to_path.size}',
 | 
			
		||||
        #     f'{self._name}: sizes {x_to_path.size}, {y_to_path.size}',
 | 
			
		||||
        # )
 | 
			
		||||
 | 
			
		||||
        self._last_topaths = x_to_path, y_to_path
 | 
			
		||||
 | 
			
		||||
        no_path_yet = self.path is None
 | 
			
		||||
 | 
			
		||||
        if draw_full_path:
 | 
			
		||||
            self.path = pg.functions.arrayToQPath(
 | 
			
		||||
                x_to_path,
 | 
			
		||||
                y_to_path,
 | 
			
		||||
| 
						 | 
				
			
			@ -497,9 +512,8 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
                finiteCheck=False,
 | 
			
		||||
                path=self.path,
 | 
			
		||||
            )
 | 
			
		||||
        profiler(f'DRAW PATH IN VIEW -> {self._name}')
 | 
			
		||||
            profiler('generated FULL PATH -> {self._name}')
 | 
			
		||||
 | 
			
		||||
        self._last_vr = view_range
 | 
			
		||||
        # reserve mem allocs see:
 | 
			
		||||
        # - https://doc.qt.io/qt-5/qpainterpath.html#reserve
 | 
			
		||||
        # - https://doc.qt.io/qt-5/qpainterpath.html#capacity
 | 
			
		||||
| 
						 | 
				
			
			@ -510,82 +524,7 @@ class FastAppendCurve(pg.GraphicsObject):
 | 
			
		|||
        if no_path_yet:
 | 
			
		||||
            self.path.reserve(int(500e3))
 | 
			
		||||
 | 
			
		||||
        profiler('generated fresh path')
 | 
			
		||||
 | 
			
		||||
        # if should_redraw and not should_ds:
 | 
			
		||||
        #     log.info(f'DEDOWN -> {self._name}')
 | 
			
		||||
        #     self._in_ds = False
 | 
			
		||||
 | 
			
		||||
        # should_ds, should_redraw = self.should_ds_or_redraw()
 | 
			
		||||
        # print(
 | 
			
		||||
        #     f'{self._name} should ds: {should_ds}')
 | 
			
		||||
 | 
			
		||||
        # if self._in_ds:
 | 
			
		||||
        # if should_ds or view_range:
 | 
			
		||||
 | 
			
		||||
        # compute the length diffs between the first/last index entry in
 | 
			
		||||
        # the input data and the last indexes we have on record from the
 | 
			
		||||
        # last time we updated the curve index.
 | 
			
		||||
        prepend_length = int(istart - x[0])
 | 
			
		||||
 | 
			
		||||
        # append_length = int(x[-1] - istop)
 | 
			
		||||
 | 
			
		||||
        # if (
 | 
			
		||||
        #     view_range
 | 
			
		||||
        #     or should_redraw or should_ds
 | 
			
		||||
        #     or self.path is None
 | 
			
		||||
        #     or prepend_length > 0
 | 
			
		||||
        # ):
 | 
			
		||||
        #     # 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[:-1], y[:-1]
 | 
			
		||||
        #         )
 | 
			
		||||
        #         # TODO: numba this bish
 | 
			
		||||
        #         profiler('generated step arrays')
 | 
			
		||||
 | 
			
		||||
        #     else:
 | 
			
		||||
        #         # by default we only pull data up to the last (current) index
 | 
			
		||||
        #         x_out, y_out = x[:-1], y[:-1]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        #     if should_redraw:
 | 
			
		||||
        #         profiler('path reversion to non-ds')
 | 
			
		||||
        #         if self.path:
 | 
			
		||||
        #             self.path.clear()
 | 
			
		||||
 | 
			
		||||
        #         if self.fast_path:
 | 
			
		||||
        #             self.fast_path.clear()
 | 
			
		||||
 | 
			
		||||
        #     if should_redraw and not should_ds:
 | 
			
		||||
        #         log.info(f'DEDOWN -> {self._name}')
 | 
			
		||||
        #         self._in_ds = False
 | 
			
		||||
 | 
			
		||||
        # self.path = pg.functions.arrayToQPath(
 | 
			
		||||
        #     x_out,
 | 
			
		||||
        #     y_out,
 | 
			
		||||
        #     connect='all',
 | 
			
		||||
        #     finiteCheck=False,
 | 
			
		||||
        #     path=self.path,
 | 
			
		||||
        # )
 | 
			
		||||
        # profiler(f'DRAW PATH IN VIEW -> {self._name}')
 | 
			
		||||
 | 
			
		||||
        # self._last_vr = view_range
 | 
			
		||||
        # # reserve mem allocs see:
 | 
			
		||||
        # # - https://doc.qt.io/qt-5/qpainterpath.html#reserve
 | 
			
		||||
        # # - https://doc.qt.io/qt-5/qpainterpath.html#capacity
 | 
			
		||||
        # # - https://doc.qt.io/qt-5/qpainterpath.html#clear
 | 
			
		||||
        # # XXX: right now this is based on had hoc checks on a
 | 
			
		||||
        # # hidpi 3840x2160 4k monitor but we should optimize for
 | 
			
		||||
        # # the target display(s) on the sys.
 | 
			
		||||
        # # if no_path_yet:
 | 
			
		||||
        # #     self.path.reserve(int(500e3))
 | 
			
		||||
 | 
			
		||||
        # profiler('generated fresh path')
 | 
			
		||||
 | 
			
		||||
                # if self._step_mode:
 | 
			
		||||
                #     self.path.closeSubpath()
 | 
			
		||||
        self._last_vr = view_range
 | 
			
		||||
 | 
			
		||||
        # TODO: get this piecewise prepend working - right now it's
 | 
			
		||||
        # giving heck on vwap...
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue