Add global `i_step` per overlay to `DisplayState`
Using a global "last index step" (via module var) obviously has problems when working with multiple feed sets in a single global app instance: any separate feed-set will be incremented according to an app-global index-step and thus won't correctly calc per-feed-set-step update info. Impl deatz: - drop `DisplayState.incr_info()` (since previously moved to `Viz`) and call that method on each appropriate `Viz` instance where necessary; further ensure the appropriate `DisplayState` instance is passed in to each call and make sure to pass a `state: DisplayState`. - add `DisplayState.hist_vars: dict` for history chart (sets) to determine the per-feed (not set) current slow chart (time) step. - add `DisplayState.globalz: dict` to house a common per-feed-set state and use it inside the new `Viz.incr_info()` such that a `should_increment: bool` can be returned and used by the display loop to determine whether to x-shift the current chart.epoch_indexing_and_dataviz_layer
parent
14104185d2
commit
530b2731ba
|
@ -128,10 +128,6 @@ def chart_maxmin(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_i_last: int = 0
|
|
||||||
_i_last_append: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
class DisplayState(Struct):
|
class DisplayState(Struct):
|
||||||
'''
|
'''
|
||||||
Chart-local real-time graphics state container.
|
Chart-local real-time graphics state container.
|
||||||
|
@ -154,113 +150,33 @@ class DisplayState(Struct):
|
||||||
hist_last_price_sticky: YAxisLabel
|
hist_last_price_sticky: YAxisLabel
|
||||||
|
|
||||||
# misc state tracking
|
# misc state tracking
|
||||||
vars: dict[str, Any] = field(default_factory=lambda: {
|
vars: dict[str, Any] = field(
|
||||||
'tick_margin': 0,
|
default_factory=lambda: {
|
||||||
'i_last': 0,
|
'tick_margin': 0,
|
||||||
'i_last_append': 0,
|
'i_last': 0,
|
||||||
'last_mx_vlm': 0,
|
'i_last_append': 0,
|
||||||
'last_mx': 0,
|
'last_mx_vlm': 0,
|
||||||
'last_mn': 0,
|
'last_mx': 0,
|
||||||
})
|
'last_mn': 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
hist_vars: dict[str, Any] = field(
|
||||||
|
default_factory=lambda: {
|
||||||
|
'tick_margin': 0,
|
||||||
|
'i_last': 0,
|
||||||
|
'i_last_append': 0,
|
||||||
|
'last_mx_vlm': 0,
|
||||||
|
'last_mx': 0,
|
||||||
|
'last_mn': 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
globalz: None | dict[str, Any] = None
|
||||||
|
|
||||||
vlm_chart: Optional[ChartPlotWidget] = None
|
vlm_chart: Optional[ChartPlotWidget] = None
|
||||||
vlm_sticky: Optional[YAxisLabel] = None
|
vlm_sticky: Optional[YAxisLabel] = None
|
||||||
wap_in_history: bool = False
|
wap_in_history: bool = False
|
||||||
|
|
||||||
def incr_info(
|
|
||||||
self,
|
|
||||||
chart: Optional[ChartPlotWidget] = None,
|
|
||||||
shm: Optional[ShmArray] = None,
|
|
||||||
state: Optional[dict] = None, # pass in a copy if you don't
|
|
||||||
|
|
||||||
update_state: bool = True,
|
|
||||||
update_uppx: float = 16,
|
|
||||||
is_1m: bool = False,
|
|
||||||
|
|
||||||
) -> tuple:
|
|
||||||
|
|
||||||
shm = shm or self.ohlcv
|
|
||||||
chart = chart or self.chart
|
|
||||||
# state = state or self.vars
|
|
||||||
|
|
||||||
if (
|
|
||||||
not update_state
|
|
||||||
and state
|
|
||||||
):
|
|
||||||
state = state.copy()
|
|
||||||
|
|
||||||
# compute the first available graphic's x-units-per-pixel
|
|
||||||
uppx = chart.view.x_uppx()
|
|
||||||
|
|
||||||
# NOTE: this used to be implemented in a dedicated
|
|
||||||
# "increment task": ``check_for_new_bars()`` but it doesn't
|
|
||||||
# make sense to do a whole task switch when we can just do
|
|
||||||
# this simple index-diff and all the fsp sub-curve graphics
|
|
||||||
# are diffed on each draw cycle anyway; so updates to the
|
|
||||||
# "curve" length is already automatic.
|
|
||||||
|
|
||||||
# increment the view position by the sample offset.
|
|
||||||
# i_step = shm.index
|
|
||||||
i_step = shm.array[-1]['time']
|
|
||||||
# i_diff = i_step - state['i_last']
|
|
||||||
# state['i_last'] = i_step
|
|
||||||
global _i_last, _i_last_append
|
|
||||||
i_diff = i_step - _i_last
|
|
||||||
# update global state
|
|
||||||
if (
|
|
||||||
# state is None
|
|
||||||
not is_1m
|
|
||||||
and i_diff > 0
|
|
||||||
):
|
|
||||||
_i_last = i_step
|
|
||||||
|
|
||||||
# append_diff = i_step - state['i_last_append']
|
|
||||||
append_diff = i_step - _i_last_append
|
|
||||||
|
|
||||||
# real-time update necessary?
|
|
||||||
main_viz = chart.get_viz(chart.name)
|
|
||||||
_, _, _, r = main_viz.bars_range()
|
|
||||||
liv = r >= shm.index
|
|
||||||
|
|
||||||
# update the "last datum" (aka extending the vizs graphic with
|
|
||||||
# new data) only if the number of unit steps is >= the number of
|
|
||||||
# such unit steps per pixel (aka uppx). Iow, if the zoom level
|
|
||||||
# is such that a datum(s) update to graphics wouldn't span
|
|
||||||
# to a new pixel, we don't update yet.
|
|
||||||
do_append = (
|
|
||||||
append_diff >= uppx
|
|
||||||
and i_diff
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
do_append
|
|
||||||
and not is_1m
|
|
||||||
):
|
|
||||||
_i_last_append = i_step
|
|
||||||
# fqsn = self.flume.symbol.fqsn
|
|
||||||
# print(
|
|
||||||
# f'DOING APPEND => {fqsn}\n'
|
|
||||||
# f'i_step:{i_step}\n'
|
|
||||||
# f'i_diff:{i_diff}\n'
|
|
||||||
# f'last:{_i_last}\n'
|
|
||||||
# f'last_append:{_i_last_append}\n'
|
|
||||||
# f'append_diff:{append_diff}\n'
|
|
||||||
# f'r: {r}\n'
|
|
||||||
# f'liv: {liv}\n'
|
|
||||||
# f'uppx: {uppx}\n'
|
|
||||||
# )
|
|
||||||
|
|
||||||
do_rt_update = uppx < update_uppx
|
|
||||||
|
|
||||||
# TODO: pack this into a struct
|
|
||||||
return (
|
|
||||||
uppx,
|
|
||||||
liv,
|
|
||||||
do_append,
|
|
||||||
i_diff,
|
|
||||||
append_diff,
|
|
||||||
do_rt_update,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def graphics_update_loop(
|
async def graphics_update_loop(
|
||||||
|
|
||||||
|
@ -295,7 +211,15 @@ async def graphics_update_loop(
|
||||||
hist_chart = godwidget.hist_linked.chart
|
hist_chart = godwidget.hist_linked.chart
|
||||||
assert hist_chart
|
assert hist_chart
|
||||||
|
|
||||||
|
# per-viz-set global last index tracking for global chart
|
||||||
|
# view UX incrementing.
|
||||||
|
globalz = {
|
||||||
|
'i_last': 0,
|
||||||
|
'i_last_append': 0,
|
||||||
|
}
|
||||||
|
|
||||||
dss: dict[str, DisplayState] = {}
|
dss: dict[str, DisplayState] = {}
|
||||||
|
|
||||||
for fqsn, flume in feed.flumes.items():
|
for fqsn, flume in feed.flumes.items():
|
||||||
ohlcv = flume.rt_shm
|
ohlcv = flume.rt_shm
|
||||||
hist_ohlcv = flume.hist_shm
|
hist_ohlcv = flume.hist_shm
|
||||||
|
@ -315,7 +239,8 @@ async def graphics_update_loop(
|
||||||
)
|
)
|
||||||
last_price_sticky.show()
|
last_price_sticky.show()
|
||||||
|
|
||||||
slow_pi = hist_chart._vizs[fqsn].plot
|
hist_viz = hist_chart._vizs[fqsn]
|
||||||
|
slow_pi = hist_viz.plot
|
||||||
hist_last_price_sticky = slow_pi.getAxis('right')._stickies[fqsn]
|
hist_last_price_sticky = slow_pi.getAxis('right')._stickies[fqsn]
|
||||||
hist_last_price_sticky.update_from_data(
|
hist_last_price_sticky.update_from_data(
|
||||||
*hist_ohlcv.array[-1][[
|
*hist_ohlcv.array[-1][[
|
||||||
|
@ -389,7 +314,8 @@ async def graphics_update_loop(
|
||||||
'last_mx_vlm': last_mx_vlm,
|
'last_mx_vlm': last_mx_vlm,
|
||||||
'last_mx': last_mx,
|
'last_mx': last_mx,
|
||||||
'last_mn': last_mn,
|
'last_mn': last_mn,
|
||||||
}
|
},
|
||||||
|
'globalz': globalz,
|
||||||
})
|
})
|
||||||
|
|
||||||
if vlm_chart:
|
if vlm_chart:
|
||||||
|
@ -400,15 +326,15 @@ async def graphics_update_loop(
|
||||||
|
|
||||||
fast_chart.default_view()
|
fast_chart.default_view()
|
||||||
|
|
||||||
|
ds.hist_vars.update({
|
||||||
|
'i_last_append': i_last,
|
||||||
|
'i_last': i_last,
|
||||||
|
})
|
||||||
|
|
||||||
# TODO: probably factor this into some kinda `DisplayState`
|
# TODO: probably factor this into some kinda `DisplayState`
|
||||||
# API that can be reused at least in terms of pulling view
|
# API that can be reused at least in terms of pulling view
|
||||||
# params (eg ``.bars_range()``).
|
# params (eg ``.bars_range()``).
|
||||||
async def increment_history_view():
|
async def increment_history_view():
|
||||||
i_last = hist_ohlcv.index
|
|
||||||
state = ds.vars.copy() | {
|
|
||||||
'i_last_append': i_last,
|
|
||||||
'i_last': i_last,
|
|
||||||
}
|
|
||||||
_, hist_step_size_s, _ = flume.get_ds_info()
|
_, hist_step_size_s, _ = flume.get_ds_info()
|
||||||
|
|
||||||
async with flume.index_stream(
|
async with flume.index_stream(
|
||||||
|
@ -433,12 +359,11 @@ async def graphics_update_loop(
|
||||||
i_diff,
|
i_diff,
|
||||||
append_diff,
|
append_diff,
|
||||||
do_rt_update,
|
do_rt_update,
|
||||||
) = ds.incr_info(
|
should_incr,
|
||||||
chart=hist_chart,
|
|
||||||
shm=ds.hist_ohlcv,
|
) = hist_viz.incr_info(
|
||||||
state=state,
|
state=ds,
|
||||||
is_1m=True,
|
is_1m=True,
|
||||||
# update_state=False,
|
|
||||||
)
|
)
|
||||||
# print(
|
# print(
|
||||||
# f'liv: {liv}\n'
|
# f'liv: {liv}\n'
|
||||||
|
@ -559,40 +484,8 @@ def graphics_update_cycle(
|
||||||
i_diff,
|
i_diff,
|
||||||
append_diff,
|
append_diff,
|
||||||
do_rt_update,
|
do_rt_update,
|
||||||
) = ds.incr_info()
|
should_incr,
|
||||||
|
) = main_viz.incr_info(state=ds)
|
||||||
# don't real-time "shift" the curve to the
|
|
||||||
# left unless we get one of the following:
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
do_append
|
|
||||||
and liv
|
|
||||||
)
|
|
||||||
or trigger_all
|
|
||||||
):
|
|
||||||
# print(f'INCREMENTING {fqsn}')
|
|
||||||
chart.increment_view(steps=i_diff)
|
|
||||||
main_viz.plot.vb._set_yrange(
|
|
||||||
# yrange=(mn, mx),
|
|
||||||
)
|
|
||||||
|
|
||||||
# NOTE: since vlm and ohlc charts are axis linked now we don't
|
|
||||||
# need the double increment request?
|
|
||||||
# if vlm_chart:
|
|
||||||
# vlm_chart.increment_view(steps=i_diff)
|
|
||||||
|
|
||||||
profiler('view incremented')
|
|
||||||
|
|
||||||
# frames_by_type: dict[str, dict] = {}
|
|
||||||
# lasts = {}
|
|
||||||
|
|
||||||
# build tick-type "frames" of tick sequences since
|
|
||||||
# likely the tick arrival rate is higher then our
|
|
||||||
# (throttled) quote stream rate.
|
|
||||||
|
|
||||||
# iterate in FIFO order per tick-frame
|
|
||||||
# if sym != fqsn:
|
|
||||||
# continue
|
|
||||||
|
|
||||||
# TODO: we should only run mxmn when we know
|
# TODO: we should only run mxmn when we know
|
||||||
# an update is due via ``do_append`` above.
|
# an update is due via ``do_append`` above.
|
||||||
|
@ -623,11 +516,6 @@ def graphics_update_cycle(
|
||||||
# graphic.
|
# graphic.
|
||||||
clear_types = _tick_groups['clears']
|
clear_types = _tick_groups['clears']
|
||||||
|
|
||||||
# XXX: if we wanted to iterate in "latest" (i.e. most
|
|
||||||
# current) tick first order as an optimization where we only
|
|
||||||
# update from the last tick from each type class.
|
|
||||||
# last_clear_updated: bool = False
|
|
||||||
|
|
||||||
# update ohlc sampled price bars
|
# update ohlc sampled price bars
|
||||||
if (
|
if (
|
||||||
do_rt_update
|
do_rt_update
|
||||||
|
@ -647,6 +535,29 @@ def graphics_update_cycle(
|
||||||
# do_append=do_append,
|
# do_append=do_append,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# don't real-time "shift" the curve to the
|
||||||
|
# left unless we get one of the following:
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
should_incr
|
||||||
|
and do_append
|
||||||
|
and liv
|
||||||
|
)
|
||||||
|
or trigger_all
|
||||||
|
):
|
||||||
|
# print(f'INCREMENTING {fqsn}')
|
||||||
|
chart.increment_view(steps=i_diff)
|
||||||
|
main_viz.plot.vb._set_yrange(
|
||||||
|
# yrange=(mn, mx),
|
||||||
|
)
|
||||||
|
|
||||||
|
# NOTE: since vlm and ohlc charts are axis linked now we don't
|
||||||
|
# need the double increment request?
|
||||||
|
# if vlm_chart:
|
||||||
|
# vlm_chart.increment_view(steps=i_diff)
|
||||||
|
|
||||||
|
profiler('view incremented')
|
||||||
|
|
||||||
# from pprint import pformat
|
# from pprint import pformat
|
||||||
# frame_counts = {
|
# frame_counts = {
|
||||||
# typ: len(frame) for typ, frame in frames_by_type.items()
|
# typ: len(frame) for typ, frame in frames_by_type.items()
|
||||||
|
@ -767,6 +678,8 @@ def graphics_update_cycle(
|
||||||
)
|
)
|
||||||
|
|
||||||
# check if slow chart needs a resize
|
# check if slow chart needs a resize
|
||||||
|
|
||||||
|
hist_viz = hist_chart._vizs[fqsn]
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
hist_liv,
|
hist_liv,
|
||||||
|
@ -774,15 +687,13 @@ def graphics_update_cycle(
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
) = ds.incr_info(
|
_,
|
||||||
chart=hist_chart,
|
) = hist_viz.incr_info(
|
||||||
shm=ds.hist_ohlcv,
|
state=ds,
|
||||||
update_state=False,
|
|
||||||
is_1m=True,
|
is_1m=True,
|
||||||
)
|
)
|
||||||
if hist_liv:
|
if hist_liv:
|
||||||
viz = hist_chart._vizs[fqsn]
|
hist_viz.plot.vb._set_yrange(
|
||||||
viz.plot.vb._set_yrange(
|
|
||||||
# yrange=hist_chart.maxmin(name=fqsn),
|
# yrange=hist_chart.maxmin(name=fqsn),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -816,7 +727,7 @@ def graphics_update_cycle(
|
||||||
):
|
):
|
||||||
viz.draw_last(
|
viz.draw_last(
|
||||||
array_key=curve_name,
|
array_key=curve_name,
|
||||||
only_last_uppx=True,
|
# only_last_uppx=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# volume chart logic..
|
# volume chart logic..
|
||||||
|
@ -1209,7 +1120,7 @@ async def display_symbol_data(
|
||||||
# for zoom-interaction purposes.
|
# for zoom-interaction purposes.
|
||||||
hist_chart.get_viz(fqsn).draw_last(
|
hist_chart.get_viz(fqsn).draw_last(
|
||||||
array_key=fqsn,
|
array_key=fqsn,
|
||||||
only_last_uppx=True,
|
# only_last_uppx=True,
|
||||||
)
|
)
|
||||||
pis.setdefault(fqsn, [None, None])[1] = hist_chart.plotItem
|
pis.setdefault(fqsn, [None, None])[1] = hist_chart.plotItem
|
||||||
|
|
||||||
|
@ -1308,7 +1219,7 @@ async def display_symbol_data(
|
||||||
# for zoom-interaction purposes.
|
# for zoom-interaction purposes.
|
||||||
viz.draw_last(
|
viz.draw_last(
|
||||||
array_key=fqsn,
|
array_key=fqsn,
|
||||||
only_last_uppx=True,
|
# only_last_uppx=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
hist_pi.vb.maxmin = partial(
|
hist_pi.vb.maxmin = partial(
|
||||||
|
|
Loading…
Reference in New Issue