Use `Viz.draw_last()` inside `.update_graphics()`
In an effort to ensure uniform and uppx-optimized last datum graphics
updates call this method directly instead of the equivalent graphics
object thus ensuring we only update the last pixel column according with
the appropriate max/min computed from the last uppx's worth of data.
Fixes / improvements to enable `.draw_last()` usage include,
- change `Viz._render_table` -> `._alt_r: tuple[Renderer, pg.GraphicsItem] | None`
  which holds an alternative (usually downsampled) render and graphics
  obj.
- extend the `.draw_last()` signature to include:
  - `last_read` to allow passing in the already read data from
    `.update_graphics()`, if it isn't passed then a manual read is done
    internally.
  - `reset_cache: bool` which is passed through to the graphics obj.
- use the new `Formatter.flat_index_ratio: float` when indexing into xy
  1d data to compute the max/min for that px column.
Other,
- drop `bars_range` input from `maxmin()` since it's unused.
			
			
				multichartz
			
			
		
							parent
							
								
									b762cf0456
								
							
						
					
					
						commit
						65434e2e67
					
				| 
						 | 
					@ -132,9 +132,9 @@ def render_baritems(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # baseline "line" downsampled OHLC curve that should
 | 
					        # baseline "line" downsampled OHLC curve that should
 | 
				
			||||||
        # kick on only when we reach a certain uppx threshold.
 | 
					        # kick on only when we reach a certain uppx threshold.
 | 
				
			||||||
        self._render_table = (ds_curve_r, curve)
 | 
					        self._alt_r = (ds_curve_r, curve)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ds_r, curve = self._render_table
 | 
					    ds_r, curve = self._alt_r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # print(
 | 
					    # print(
 | 
				
			||||||
    #     f'r: {r.fmtr.xy_slice}\n'
 | 
					    #     f'r: {r.fmtr.xy_slice}\n'
 | 
				
			||||||
| 
						 | 
					@ -270,11 +270,11 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
    _index_step: float | None = None
 | 
					    _index_step: float | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # map from uppx -> (downsampled data, incremental graphics)
 | 
					    # map from uppx -> (downsampled data, incremental graphics)
 | 
				
			||||||
    _src_r: Optional[Renderer] = None
 | 
					    _src_r: Renderer | None = None
 | 
				
			||||||
    _render_table: dict[
 | 
					    _alt_r: tuple[
 | 
				
			||||||
        Optional[int],
 | 
					        Renderer,
 | 
				
			||||||
        tuple[Renderer, pg.GraphicsItem],
 | 
					        pg.GraphicsItem
 | 
				
			||||||
    ] = (None, None)
 | 
					    ] | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # cache of y-range values per x-range input.
 | 
					    # cache of y-range values per x-range input.
 | 
				
			||||||
    _mxmns: dict[
 | 
					    _mxmns: dict[
 | 
				
			||||||
| 
						 | 
					@ -329,11 +329,6 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
    def maxmin(
 | 
					    def maxmin(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: drop this right?
 | 
					 | 
				
			||||||
        bars_range: Optional[tuple[
 | 
					 | 
				
			||||||
            int, int, int, int, int, int
 | 
					 | 
				
			||||||
        ]] = None,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        x_range: slice | tuple[int, int] | None = None,
 | 
					        x_range: slice | tuple[int, int] | None = None,
 | 
				
			||||||
        use_caching: bool = True,
 | 
					        use_caching: bool = True,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -366,11 +361,7 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
                rbar,
 | 
					                rbar,
 | 
				
			||||||
                _,
 | 
					                _,
 | 
				
			||||||
                r,
 | 
					                r,
 | 
				
			||||||
            ) = (
 | 
					            ) = self.datums_range()
 | 
				
			||||||
                # TODO: drop this yah?
 | 
					 | 
				
			||||||
                bars_range
 | 
					 | 
				
			||||||
                or self.datums_range()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            profiler(f'{self.name} got bars range')
 | 
					            profiler(f'{self.name} got bars range')
 | 
				
			||||||
            x_range = lbar, rbar
 | 
					            x_range = lbar, rbar
 | 
				
			||||||
| 
						 | 
					@ -816,18 +807,29 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
            with graphics.reset_cache():
 | 
					            with graphics.reset_cache():
 | 
				
			||||||
                graphics.path = r.path
 | 
					                graphics.path = r.path
 | 
				
			||||||
                graphics.fast_path = r.fast_path
 | 
					                graphics.fast_path = r.fast_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.draw_last(
 | 
				
			||||||
 | 
					                    array_key=array_key,
 | 
				
			||||||
 | 
					                    last_read=read,
 | 
				
			||||||
 | 
					                    reset_cache=reset_cache,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # assign output paths to graphicis obj
 | 
					            # assign output paths to graphicis obj
 | 
				
			||||||
            graphics.path = r.path
 | 
					            graphics.path = r.path
 | 
				
			||||||
            graphics.fast_path = r.fast_path
 | 
					            graphics.fast_path = r.fast_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        graphics.draw_last_datum(
 | 
					            self.draw_last(
 | 
				
			||||||
            path,
 | 
					                array_key=array_key,
 | 
				
			||||||
            src_array,
 | 
					                last_read=read,
 | 
				
			||||||
            reset_cache,
 | 
					                reset_cache=reset_cache,
 | 
				
			||||||
            array_key,
 | 
					            )
 | 
				
			||||||
            index_field=self.index_field,
 | 
					        # graphics.draw_last_datum(
 | 
				
			||||||
        )
 | 
					        #     path,
 | 
				
			||||||
 | 
					        #     src_array,
 | 
				
			||||||
 | 
					        #     reset_cache,
 | 
				
			||||||
 | 
					        #     array_key,
 | 
				
			||||||
 | 
					        #     index_field=self.index_field,
 | 
				
			||||||
 | 
					        # )
 | 
				
			||||||
        graphics.update()
 | 
					        graphics.update()
 | 
				
			||||||
        profiler('.update()')
 | 
					        profiler('.update()')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -845,7 +847,9 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def draw_last(
 | 
					    def draw_last(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        array_key: Optional[str] = None,
 | 
					        array_key: str | None = None,
 | 
				
			||||||
 | 
					        last_read: tuple | None = None,
 | 
				
			||||||
 | 
					        reset_cache: bool = False,
 | 
				
			||||||
        only_last_uppx: bool = False,
 | 
					        only_last_uppx: bool = False,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ) -> None:
 | 
					    ) -> None:
 | 
				
			||||||
| 
						 | 
					@ -854,17 +858,11 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
        (
 | 
					        (
 | 
				
			||||||
            xfirst, xlast, src_array,
 | 
					            xfirst, xlast, src_array,
 | 
				
			||||||
            ivl, ivr, in_view,
 | 
					            ivl, ivr, in_view,
 | 
				
			||||||
        ) = self.read()
 | 
					        ) = last_read or self.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g = self.graphics
 | 
					 | 
				
			||||||
        array_key = array_key or self.name
 | 
					        array_key = array_key or self.name
 | 
				
			||||||
        x, y = g.draw_last_datum(
 | 
					
 | 
				
			||||||
            g.path,
 | 
					        gfx = self.graphics
 | 
				
			||||||
            src_array,
 | 
					 | 
				
			||||||
            False,  # never reset path
 | 
					 | 
				
			||||||
            array_key,
 | 
					 | 
				
			||||||
            self.index_field,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # the renderer is downsampling we choose
 | 
					        # the renderer is downsampling we choose
 | 
				
			||||||
        # to always try and update a single (interpolating)
 | 
					        # to always try and update a single (interpolating)
 | 
				
			||||||
| 
						 | 
					@ -874,19 +872,28 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
        # worth of data since that's all the screen
 | 
					        # worth of data since that's all the screen
 | 
				
			||||||
        # can represent on the last column where
 | 
					        # can represent on the last column where
 | 
				
			||||||
        # the most recent datum is being drawn.
 | 
					        # the most recent datum is being drawn.
 | 
				
			||||||
 | 
					        uppx = ceil(self._last_uppx)
 | 
				
			||||||
        if (
 | 
					        if (
 | 
				
			||||||
            self._in_ds
 | 
					            (self._in_ds or only_last_uppx)
 | 
				
			||||||
            or only_last_uppx
 | 
					            and uppx > 0
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            dsg = self.ds_graphics or self.graphics
 | 
					            alt_renderer = self._alt_r
 | 
				
			||||||
 | 
					            if alt_renderer:
 | 
				
			||||||
 | 
					                renderer, gfx = alt_renderer
 | 
				
			||||||
 | 
					                fmtr = renderer.fmtr
 | 
				
			||||||
 | 
					                x = fmtr.x_1d
 | 
				
			||||||
 | 
					                y = fmtr.y_1d
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                renderer = self._src_r
 | 
				
			||||||
 | 
					                fmtr = renderer.fmtr
 | 
				
			||||||
 | 
					                x = fmtr.x_1d
 | 
				
			||||||
 | 
					                y = fmtr.y_1d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if alt_renderer:
 | 
				
			||||||
 | 
					                uppx *= fmtr.flat_index_ratio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # XXX: pretty sure we don't need this?
 | 
					 | 
				
			||||||
            # if isinstance(g, Curve):
 | 
					 | 
				
			||||||
            #     with dsg.reset_cache():
 | 
					 | 
				
			||||||
            uppx = round(self._last_uppx)
 | 
					 | 
				
			||||||
            y = y[-uppx:]
 | 
					            y = y[-uppx:]
 | 
				
			||||||
            ymn, ymx = y.min(), y.max()
 | 
					            ymn, ymx = y.min(), y.max()
 | 
				
			||||||
            # print(f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}')
 | 
					 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                iuppx = x[-uppx]
 | 
					                iuppx = x[-uppx]
 | 
				
			||||||
            except IndexError:
 | 
					            except IndexError:
 | 
				
			||||||
| 
						 | 
					@ -894,16 +901,32 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
                # datum index.
 | 
					                # datum index.
 | 
				
			||||||
                iuppx = x[0]
 | 
					                iuppx = x[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            dsg._last_line = QLineF(
 | 
					            gfx._last_line = QLineF(
 | 
				
			||||||
                iuppx, ymn,
 | 
					                iuppx, ymn,
 | 
				
			||||||
                x[-1], ymx,
 | 
					                x[-1], ymx,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            # print(f'updating DS curve {self.name}')
 | 
					            # if self.is_ohlc:
 | 
				
			||||||
            dsg.update()
 | 
					            #     times = self.shm.array['time']
 | 
				
			||||||
 | 
					            #     time_step = times[-1] - times[-2]
 | 
				
			||||||
 | 
					            #     # if 'hist' in self.shm.token['shm_name']
 | 
				
			||||||
 | 
					            #     # if self.index_step() == 1:
 | 
				
			||||||
 | 
					            #     #     breakpoint()
 | 
				
			||||||
 | 
					            #     print(
 | 
				
			||||||
 | 
					            #         f'updating DS curve {self.name}@{time_step}s\n'
 | 
				
			||||||
 | 
					            #         f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}'
 | 
				
			||||||
 | 
					            #     )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
 | 
					            x, y = gfx.draw_last_datum(
 | 
				
			||||||
 | 
					                gfx.path,
 | 
				
			||||||
 | 
					                src_array,
 | 
				
			||||||
 | 
					                reset_cache,  # never reset path
 | 
				
			||||||
 | 
					                array_key,
 | 
				
			||||||
 | 
					                self.index_field,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            # print(f'updating NOT DS curve {self.name}')
 | 
					            # print(f'updating NOT DS curve {self.name}')
 | 
				
			||||||
            g.update()
 | 
					
 | 
				
			||||||
 | 
					        gfx.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def default_view(
 | 
					    def default_view(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
| 
						 | 
					@ -1029,7 +1052,7 @@ class Viz(msgspec.Struct):  # , frozen=True):
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if do_ds:
 | 
					        if do_ds:
 | 
				
			||||||
            # view.interaction_graphics_update_cycle()
 | 
					            # view.interaction_graphics_cycle()
 | 
				
			||||||
            view.maybe_downsample_graphics()
 | 
					            view.maybe_downsample_graphics()
 | 
				
			||||||
            view._set_yrange()
 | 
					            view._set_yrange()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue