Merge pull request #338 from pikers/update_last_datums_in_view
Fix: update last datums in view by `uppx` indexinguppx_slice_fix
						commit
						7ddebf6773
					
				| 
						 | 
				
			
			@ -379,7 +379,7 @@ class Curve(pg.GraphicsObject):
 | 
			
		|||
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        # default line draw last call
 | 
			
		||||
        with self.reset_cache():
 | 
			
		||||
        # with self.reset_cache():
 | 
			
		||||
        x = render_data['index']
 | 
			
		||||
        y = render_data[array_key]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -426,71 +426,6 @@ def graphics_update_cycle(
 | 
			
		|||
 | 
			
		||||
            profiler('view incremented')
 | 
			
		||||
 | 
			
		||||
        if vlm_chart:
 | 
			
		||||
            # always update y-label
 | 
			
		||||
            ds.vlm_sticky.update_from_data(
 | 
			
		||||
                *array[-1][['index', 'volume']]
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            if (
 | 
			
		||||
                (
 | 
			
		||||
                    do_rt_update
 | 
			
		||||
                    or do_append
 | 
			
		||||
                    and liv
 | 
			
		||||
                )
 | 
			
		||||
                or trigger_all
 | 
			
		||||
            ):
 | 
			
		||||
                # TODO: make it so this doesn't have to be called
 | 
			
		||||
                # once the $vlm is up?
 | 
			
		||||
                vlm_chart.update_graphics_from_flow(
 | 
			
		||||
                    'volume',
 | 
			
		||||
                    # UGGGh, see ``maxmin()`` impl in `._fsp` for
 | 
			
		||||
                    # the overlayed plotitems... we need a better
 | 
			
		||||
                    # bay to invoke a maxmin per overlay..
 | 
			
		||||
                    render=False,
 | 
			
		||||
                    # XXX: ^^^^ THIS IS SUPER IMPORTANT! ^^^^
 | 
			
		||||
                    # without this, since we disable the
 | 
			
		||||
                    # 'volume' (units) chart after the $vlm starts
 | 
			
		||||
                    # up we need to be sure to enable this
 | 
			
		||||
                    # auto-ranging otherwise there will be no handler
 | 
			
		||||
                    # connected to update accompanying overlay
 | 
			
		||||
                    # graphics..
 | 
			
		||||
                )
 | 
			
		||||
                profiler('`vlm_chart.update_graphics_from_flow()`')
 | 
			
		||||
 | 
			
		||||
                if (
 | 
			
		||||
                    mx_vlm_in_view != vars['last_mx_vlm']
 | 
			
		||||
                ):
 | 
			
		||||
                    yrange = (0, mx_vlm_in_view * 1.375)
 | 
			
		||||
                    vlm_chart.view._set_yrange(
 | 
			
		||||
                        yrange=yrange,
 | 
			
		||||
                    )
 | 
			
		||||
                    profiler('`vlm_chart.view._set_yrange()`')
 | 
			
		||||
                    # print(f'mx vlm: {last_mx_vlm} -> {mx_vlm_in_view}')
 | 
			
		||||
                    vars['last_mx_vlm'] = mx_vlm_in_view
 | 
			
		||||
 | 
			
		||||
                for curve_name, flow in vlm_chart._flows.items():
 | 
			
		||||
 | 
			
		||||
                    if not flow.render:
 | 
			
		||||
                        continue
 | 
			
		||||
 | 
			
		||||
                    update_fsp_chart(
 | 
			
		||||
                        vlm_chart,
 | 
			
		||||
                        flow,
 | 
			
		||||
                        curve_name,
 | 
			
		||||
                        array_key=curve_name,
 | 
			
		||||
                        # do_append=uppx < update_uppx,
 | 
			
		||||
                        do_append=do_append,
 | 
			
		||||
                    )
 | 
			
		||||
                    # is this even doing anything?
 | 
			
		||||
                    # (pretty sure it's the real-time
 | 
			
		||||
                    # resizing from last quote?)
 | 
			
		||||
                    fvb = flow.plot.vb
 | 
			
		||||
                    fvb._set_yrange(
 | 
			
		||||
                        # autoscale_linked_plots=False,
 | 
			
		||||
                        name=curve_name,
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
        ticks_frame = quote.get('ticks', ())
 | 
			
		||||
 | 
			
		||||
        frames_by_type: dict[str, dict] = {}
 | 
			
		||||
| 
						 | 
				
			
			@ -540,15 +475,16 @@ def graphics_update_cycle(
 | 
			
		|||
            or do_append
 | 
			
		||||
            or trigger_all
 | 
			
		||||
        ):
 | 
			
		||||
            # TODO: we should always update the "last" datum
 | 
			
		||||
            # since the current range should at least be updated
 | 
			
		||||
            # to it's max/min on the last pixel.
 | 
			
		||||
            chart.update_graphics_from_flow(
 | 
			
		||||
                chart.name,
 | 
			
		||||
                # do_append=uppx < update_uppx,
 | 
			
		||||
                do_append=do_append,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        # NOTE: we always update the "last" datum
 | 
			
		||||
        # since the current range should at least be updated
 | 
			
		||||
        # to it's max/min on the last pixel.
 | 
			
		||||
 | 
			
		||||
        # iterate in FIFO order per tick-frame
 | 
			
		||||
        for typ, tick in lasts.items():
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -653,11 +589,106 @@ def graphics_update_cycle(
 | 
			
		|||
        vars['last_mx'], vars['last_mn'] = mx, mn
 | 
			
		||||
 | 
			
		||||
        # run synchronous update on all linked flows
 | 
			
		||||
        # TODO: should the "main" (aka source) flow be special?
 | 
			
		||||
        for curve_name, flow in chart._flows.items():
 | 
			
		||||
            # update any overlayed fsp flows
 | 
			
		||||
            if curve_name != chart.data_key:
 | 
			
		||||
                update_fsp_chart(
 | 
			
		||||
                    chart,
 | 
			
		||||
                    flow,
 | 
			
		||||
                    curve_name,
 | 
			
		||||
                    array_key=curve_name,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            # even if we're downsampled bigly
 | 
			
		||||
            # draw the last datum in the final
 | 
			
		||||
            # px column to give the user the mx/mn
 | 
			
		||||
            # range of that set.
 | 
			
		||||
            if (
 | 
			
		||||
                not do_append
 | 
			
		||||
                # and not do_rt_update
 | 
			
		||||
                and liv
 | 
			
		||||
            ):
 | 
			
		||||
                flow.draw_last(
 | 
			
		||||
                    array_key=curve_name,
 | 
			
		||||
                    only_last_uppx=True,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
        # volume chart logic..
 | 
			
		||||
        # TODO: can we unify this with the above loop?
 | 
			
		||||
        if vlm_chart:
 | 
			
		||||
            # always update y-label
 | 
			
		||||
            ds.vlm_sticky.update_from_data(
 | 
			
		||||
                *array[-1][['index', 'volume']]
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            if (
 | 
			
		||||
                not (do_rt_update or do_append)
 | 
			
		||||
                (
 | 
			
		||||
                    do_rt_update
 | 
			
		||||
                    or do_append
 | 
			
		||||
                    and liv
 | 
			
		||||
                )
 | 
			
		||||
                or trigger_all
 | 
			
		||||
            ):
 | 
			
		||||
                # TODO: make it so this doesn't have to be called
 | 
			
		||||
                # once the $vlm is up?
 | 
			
		||||
                vlm_chart.update_graphics_from_flow(
 | 
			
		||||
                    'volume',
 | 
			
		||||
                    # UGGGh, see ``maxmin()`` impl in `._fsp` for
 | 
			
		||||
                    # the overlayed plotitems... we need a better
 | 
			
		||||
                    # bay to invoke a maxmin per overlay..
 | 
			
		||||
                    render=False,
 | 
			
		||||
                    # XXX: ^^^^ THIS IS SUPER IMPORTANT! ^^^^
 | 
			
		||||
                    # without this, since we disable the
 | 
			
		||||
                    # 'volume' (units) chart after the $vlm starts
 | 
			
		||||
                    # up we need to be sure to enable this
 | 
			
		||||
                    # auto-ranging otherwise there will be no handler
 | 
			
		||||
                    # connected to update accompanying overlay
 | 
			
		||||
                    # graphics..
 | 
			
		||||
                )
 | 
			
		||||
                profiler('`vlm_chart.update_graphics_from_flow()`')
 | 
			
		||||
 | 
			
		||||
                if (
 | 
			
		||||
                    mx_vlm_in_view != vars['last_mx_vlm']
 | 
			
		||||
                ):
 | 
			
		||||
                    yrange = (0, mx_vlm_in_view * 1.375)
 | 
			
		||||
                    vlm_chart.view._set_yrange(
 | 
			
		||||
                        yrange=yrange,
 | 
			
		||||
                    )
 | 
			
		||||
                    profiler('`vlm_chart.view._set_yrange()`')
 | 
			
		||||
                    # print(f'mx vlm: {last_mx_vlm} -> {mx_vlm_in_view}')
 | 
			
		||||
                    vars['last_mx_vlm'] = mx_vlm_in_view
 | 
			
		||||
 | 
			
		||||
            for curve_name, flow in vlm_chart._flows.items():
 | 
			
		||||
 | 
			
		||||
                if (
 | 
			
		||||
                    curve_name != 'volume' and
 | 
			
		||||
                    flow.render and (
 | 
			
		||||
                        liv and
 | 
			
		||||
                        do_rt_update or do_append
 | 
			
		||||
                    )
 | 
			
		||||
                ):
 | 
			
		||||
                    update_fsp_chart(
 | 
			
		||||
                        vlm_chart,
 | 
			
		||||
                        flow,
 | 
			
		||||
                        curve_name,
 | 
			
		||||
                        array_key=curve_name,
 | 
			
		||||
                        # do_append=uppx < update_uppx,
 | 
			
		||||
                        do_append=do_append,
 | 
			
		||||
                    )
 | 
			
		||||
                    # is this even doing anything?
 | 
			
		||||
                    # (pretty sure it's the real-time
 | 
			
		||||
                    # resizing from last quote?)
 | 
			
		||||
                    fvb = flow.plot.vb
 | 
			
		||||
                    fvb._set_yrange(
 | 
			
		||||
                        name=curve_name,
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                elif (
 | 
			
		||||
                    curve_name != 'volume'
 | 
			
		||||
                    and not do_append
 | 
			
		||||
                    and liv
 | 
			
		||||
                    and uppx >= 1
 | 
			
		||||
                    # even if we're downsampled bigly
 | 
			
		||||
                    # draw the last datum in the final
 | 
			
		||||
                    # px column to give the user the mx/mn
 | 
			
		||||
| 
						 | 
				
			
			@ -665,19 +696,9 @@ def graphics_update_cycle(
 | 
			
		|||
                ):
 | 
			
		||||
                    # always update the last datum-element
 | 
			
		||||
                    # graphic for all flows
 | 
			
		||||
                    # print(f'drawing last {flow.name}')
 | 
			
		||||
                    flow.draw_last(array_key=curve_name)
 | 
			
		||||
 | 
			
		||||
            # TODO: should the "main" (aka source) flow be special?
 | 
			
		||||
            if curve_name == chart.data_key:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            update_fsp_chart(
 | 
			
		||||
                chart,
 | 
			
		||||
                flow,
 | 
			
		||||
                curve_name,
 | 
			
		||||
                array_key=curve_name,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def display_symbol_data(
 | 
			
		||||
    godwidget: GodWidget,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -175,6 +175,7 @@ def render_baritems(
 | 
			
		|||
            name=f'{flow.name}_ds_ohlc',
 | 
			
		||||
            color=bars._color,
 | 
			
		||||
        )
 | 
			
		||||
        flow.ds_graphics = curve
 | 
			
		||||
        curve.hide()
 | 
			
		||||
        self.plot.addItem(curve)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,18 +193,20 @@ def render_baritems(
 | 
			
		|||
    uppx = curve.x_uppx()
 | 
			
		||||
    in_line = should_line = curve.isVisible()
 | 
			
		||||
    if (
 | 
			
		||||
        should_line
 | 
			
		||||
        in_line
 | 
			
		||||
        and uppx < x_gt
 | 
			
		||||
    ):
 | 
			
		||||
        # print('FLIPPING TO BARS')
 | 
			
		||||
        should_line = False
 | 
			
		||||
        flow._in_ds = False
 | 
			
		||||
 | 
			
		||||
    elif (
 | 
			
		||||
        not should_line
 | 
			
		||||
        not in_line
 | 
			
		||||
        and uppx >= x_gt
 | 
			
		||||
    ):
 | 
			
		||||
        # print('FLIPPING TO LINE')
 | 
			
		||||
        should_line = True
 | 
			
		||||
        flow._in_ds = True
 | 
			
		||||
 | 
			
		||||
    profiler(f'ds logic complete line={should_line}')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +336,13 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
    '''
 | 
			
		||||
    name: str
 | 
			
		||||
    plot: pg.PlotItem
 | 
			
		||||
    graphics: Curve
 | 
			
		||||
    graphics: Union[Curve, BarItems]
 | 
			
		||||
 | 
			
		||||
    # in some cases a flow may want to change its
 | 
			
		||||
    # graphical "type" or, "form" when downsampling,
 | 
			
		||||
    # normally this is just a plain line.
 | 
			
		||||
    ds_graphics: Optional[Curve] = None
 | 
			
		||||
 | 
			
		||||
    _shm: ShmArray
 | 
			
		||||
 | 
			
		||||
    is_ohlc: bool = False
 | 
			
		||||
| 
						 | 
				
			
			@ -540,6 +549,7 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
        should_redraw: bool = False
 | 
			
		||||
        rkwargs = {}
 | 
			
		||||
 | 
			
		||||
        should_line = False
 | 
			
		||||
        if isinstance(graphics, BarItems):
 | 
			
		||||
            # XXX: special case where we change out graphics
 | 
			
		||||
            # to a line after a certain uppx threshold.
 | 
			
		||||
| 
						 | 
				
			
			@ -556,8 +566,8 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
                profiler,
 | 
			
		||||
                **kwargs,
 | 
			
		||||
            )
 | 
			
		||||
            # bars = True
 | 
			
		||||
            should_redraw = changed_to_line or not should_line
 | 
			
		||||
            self._in_ds = should_line
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            r = self._src_r
 | 
			
		||||
| 
						 | 
				
			
			@ -661,6 +671,17 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
                # assign output paths to graphicis obj
 | 
			
		||||
                graphics.path = r.path
 | 
			
		||||
                graphics.fast_path = r.fast_path
 | 
			
		||||
 | 
			
		||||
                # XXX: we don't need this right?
 | 
			
		||||
                # graphics.draw_last_datum(
 | 
			
		||||
                #     path,
 | 
			
		||||
                #     src_array,
 | 
			
		||||
                #     data,
 | 
			
		||||
                #     reset,
 | 
			
		||||
                #     array_key,
 | 
			
		||||
                # )
 | 
			
		||||
                # graphics.update()
 | 
			
		||||
                # profiler('.update()')
 | 
			
		||||
        else:
 | 
			
		||||
            # assign output paths to graphicis obj
 | 
			
		||||
            graphics.path = r.path
 | 
			
		||||
| 
						 | 
				
			
			@ -673,16 +694,15 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
            reset,
 | 
			
		||||
            array_key,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # TODO: is this ever better?
 | 
			
		||||
        # graphics.prepareGeometryChange()
 | 
			
		||||
        # profiler('.prepareGeometryChange()')
 | 
			
		||||
        graphics.update()
 | 
			
		||||
        profiler('.update()')
 | 
			
		||||
 | 
			
		||||
        # TODO: does this actuallly help us in any way (prolly should
 | 
			
		||||
        # look at the source / ask ogi). I think it avoid artifacts on
 | 
			
		||||
        # wheel-scroll downsampling curve updates?
 | 
			
		||||
        graphics.update()
 | 
			
		||||
        profiler('.update()')
 | 
			
		||||
        # TODO: is this ever better?
 | 
			
		||||
        # graphics.prepareGeometryChange()
 | 
			
		||||
        # profiler('.prepareGeometryChange()')
 | 
			
		||||
 | 
			
		||||
        # track downsampled state
 | 
			
		||||
        self._in_ds = r._in_ds
 | 
			
		||||
| 
						 | 
				
			
			@ -692,6 +712,7 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
    def draw_last(
 | 
			
		||||
        self,
 | 
			
		||||
        array_key: Optional[str] = None,
 | 
			
		||||
        only_last_uppx: bool = False,
 | 
			
		||||
 | 
			
		||||
    ) -> None:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -711,19 +732,34 @@ class Flow(msgspec.Struct):  # , frozen=True):
 | 
			
		|||
            array_key,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if self._in_ds:
 | 
			
		||||
        # the renderer is downsampling we choose
 | 
			
		||||
        # to always try and updadte a single (interpolating)
 | 
			
		||||
        # line segment that spans and tries to display
 | 
			
		||||
        # the las uppx's worth of datums.
 | 
			
		||||
        # we only care about the last pixel's
 | 
			
		||||
        # worth of data since that's all the screen
 | 
			
		||||
        # can represent on the last column where
 | 
			
		||||
        # the most recent datum is being drawn.
 | 
			
		||||
        if self._in_ds or only_last_uppx:
 | 
			
		||||
            dsg = self.ds_graphics or self.graphics
 | 
			
		||||
 | 
			
		||||
            # XXX: pretty sure we don't need this?
 | 
			
		||||
            # if isinstance(g, Curve):
 | 
			
		||||
            #     with dsg.reset_cache():
 | 
			
		||||
            uppx = self._last_uppx
 | 
			
		||||
            y = y[-uppx:]
 | 
			
		||||
            ymn, ymx = y.min(), y.max()
 | 
			
		||||
            # print(f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}')
 | 
			
		||||
            g._last_line = QLineF(
 | 
			
		||||
                x[-2], ymn,
 | 
			
		||||
            dsg._last_line = QLineF(
 | 
			
		||||
                x[-uppx], ymn,
 | 
			
		||||
                x[-1], ymx,
 | 
			
		||||
            )
 | 
			
		||||
            # print(f'updating DS curve {self.name}')
 | 
			
		||||
            dsg.update()
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            # print(f'updating NOT DS curve {self.name}')
 | 
			
		||||
            g.update()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def by_index_and_key(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue