Merge pull request #338 from pikers/update_last_datums_in_view

Fix: update last datums in view by `uppx` indexing
uppx_slice_fix
goodboy 2022-06-10 09:38:26 -04:00 committed by GitHub
commit 7ddebf6773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 170 additions and 113 deletions

View File

@ -379,17 +379,17 @@ class Curve(pg.GraphicsObject):
) -> None: ) -> None:
# default line draw last call # default line draw last call
with self.reset_cache(): # with self.reset_cache():
x = render_data['index'] x = render_data['index']
y = render_data[array_key] y = render_data[array_key]
# draw the "current" step graphic segment so it # draw the "current" step graphic segment so it
# lines up with the "middle" of the current # lines up with the "middle" of the current
# (OHLC) sample. # (OHLC) sample.
self._last_line = QLineF( self._last_line = QLineF(
x[-2], y[-2], x[-2], y[-2],
x[-1], y[-1], x[-1], y[-1],
) )
return x, y return x, y

View File

@ -426,71 +426,6 @@ def graphics_update_cycle(
profiler('view incremented') 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', ()) ticks_frame = quote.get('ticks', ())
frames_by_type: dict[str, dict] = {} frames_by_type: dict[str, dict] = {}
@ -540,15 +475,16 @@ def graphics_update_cycle(
or do_append or do_append
or trigger_all 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.update_graphics_from_flow(
chart.name, chart.name,
# do_append=uppx < update_uppx, # do_append=uppx < update_uppx,
do_append=do_append, 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 # iterate in FIFO order per tick-frame
for typ, tick in lasts.items(): for typ, tick in lasts.items():
@ -653,30 +589,115 @@ def graphics_update_cycle(
vars['last_mx'], vars['last_mn'] = mx, mn vars['last_mx'], vars['last_mn'] = mx, mn
# run synchronous update on all linked flows # run synchronous update on all linked flows
# TODO: should the "main" (aka source) flow be special?
for curve_name, flow in chart._flows.items(): 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 ( if (
not (do_rt_update or do_append) (
and liv do_rt_update
# even if we're downsampled bigly or do_append
# draw the last datum in the final and liv
# px column to give the user the mx/mn )
# range of that set. or trigger_all
): ):
# always update the last datum-element # TODO: make it so this doesn't have to be called
# graphic for all flows # once the $vlm is up?
flow.draw_last(array_key=curve_name) 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()`')
# TODO: should the "main" (aka source) flow be special? if (
if curve_name == chart.data_key: mx_vlm_in_view != vars['last_mx_vlm']
continue ):
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
update_fsp_chart( for curve_name, flow in vlm_chart._flows.items():
chart,
flow, if (
curve_name, curve_name != 'volume' and
array_key=curve_name, 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
# range of that set.
):
# always update the last datum-element
# graphic for all flows
# print(f'drawing last {flow.name}')
flow.draw_last(array_key=curve_name)
async def display_symbol_data( async def display_symbol_data(

View File

@ -175,6 +175,7 @@ def render_baritems(
name=f'{flow.name}_ds_ohlc', name=f'{flow.name}_ds_ohlc',
color=bars._color, color=bars._color,
) )
flow.ds_graphics = curve
curve.hide() curve.hide()
self.plot.addItem(curve) self.plot.addItem(curve)
@ -192,18 +193,20 @@ def render_baritems(
uppx = curve.x_uppx() uppx = curve.x_uppx()
in_line = should_line = curve.isVisible() in_line = should_line = curve.isVisible()
if ( if (
should_line in_line
and uppx < x_gt and uppx < x_gt
): ):
# print('FLIPPING TO BARS') # print('FLIPPING TO BARS')
should_line = False should_line = False
flow._in_ds = False
elif ( elif (
not should_line not in_line
and uppx >= x_gt and uppx >= x_gt
): ):
# print('FLIPPING TO LINE') # print('FLIPPING TO LINE')
should_line = True should_line = True
flow._in_ds = True
profiler(f'ds logic complete line={should_line}') profiler(f'ds logic complete line={should_line}')
@ -333,7 +336,13 @@ class Flow(msgspec.Struct): # , frozen=True):
''' '''
name: str name: str
plot: pg.PlotItem 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 _shm: ShmArray
is_ohlc: bool = False is_ohlc: bool = False
@ -540,6 +549,7 @@ class Flow(msgspec.Struct): # , frozen=True):
should_redraw: bool = False should_redraw: bool = False
rkwargs = {} rkwargs = {}
should_line = False
if isinstance(graphics, BarItems): if isinstance(graphics, BarItems):
# XXX: special case where we change out graphics # XXX: special case where we change out graphics
# to a line after a certain uppx threshold. # to a line after a certain uppx threshold.
@ -556,8 +566,8 @@ class Flow(msgspec.Struct): # , frozen=True):
profiler, profiler,
**kwargs, **kwargs,
) )
# bars = True
should_redraw = changed_to_line or not should_line should_redraw = changed_to_line or not should_line
self._in_ds = should_line
else: else:
r = self._src_r r = self._src_r
@ -661,6 +671,17 @@ class Flow(msgspec.Struct): # , frozen=True):
# 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
# XXX: we don't need this right?
# graphics.draw_last_datum(
# path,
# src_array,
# data,
# reset,
# array_key,
# )
# graphics.update()
# profiler('.update()')
else: else:
# assign output paths to graphicis obj # assign output paths to graphicis obj
graphics.path = r.path graphics.path = r.path
@ -673,16 +694,15 @@ class Flow(msgspec.Struct): # , frozen=True):
reset, reset,
array_key, array_key,
) )
graphics.update()
# TODO: is this ever better? profiler('.update()')
# graphics.prepareGeometryChange()
# profiler('.prepareGeometryChange()')
# TODO: does this actuallly help us in any way (prolly should # TODO: does this actuallly help us in any way (prolly should
# look at the source / ask ogi). I think it avoid artifacts on # look at the source / ask ogi). I think it avoid artifacts on
# wheel-scroll downsampling curve updates? # wheel-scroll downsampling curve updates?
graphics.update() # TODO: is this ever better?
profiler('.update()') # graphics.prepareGeometryChange()
# profiler('.prepareGeometryChange()')
# track downsampled state # track downsampled state
self._in_ds = r._in_ds self._in_ds = r._in_ds
@ -692,6 +712,7 @@ class Flow(msgspec.Struct): # , frozen=True):
def draw_last( def draw_last(
self, self,
array_key: Optional[str] = None, array_key: Optional[str] = None,
only_last_uppx: bool = False,
) -> None: ) -> None:
@ -711,19 +732,34 @@ class Flow(msgspec.Struct): # , frozen=True):
array_key, array_key,
) )
if self._in_ds: # the renderer is downsampling we choose
# we only care about the last pixel's # to always try and updadte a single (interpolating)
# worth of data since that's all the screen # line segment that spans and tries to display
# can represent on the last column where # the las uppx's worth of datums.
# the most recent datum is being drawn. # 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 uppx = 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}') # print(f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}')
g._last_line = QLineF( dsg._last_line = QLineF(
x[-2], ymn, x[-uppx], ymn,
x[-1], ymx, 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( def by_index_and_key(