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,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
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue