From 08c288c3f94bb45a7d461c2f170aa4e7c771a4f2 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Wed, 14 Dec 2022 17:36:01 -0500 Subject: [PATCH] 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. --- piker/ui/_display.py | 223 +++++++++++++------------------------------ 1 file changed, 65 insertions(+), 158 deletions(-) diff --git a/piker/ui/_display.py b/piker/ui/_display.py index 5d7a90f3..7fd2d6b1 100644 --- a/piker/ui/_display.py +++ b/piker/ui/_display.py @@ -126,10 +126,6 @@ def chart_maxmin( ) -_i_last: int = 0 -_i_last_append: int = 0 - - class DisplayState(Struct): ''' Chart-local real-time graphics state container. @@ -160,105 +156,21 @@ class DisplayState(Struct): 'last_mx': 0, 'last_mn': 0, } + hist_vars: dict[str, Any] = { + '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_sticky: Optional[YAxisLabel] = None 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( @@ -293,7 +205,15 @@ async def graphics_update_loop( hist_chart = godwidget.hist_linked.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] = {} + for fqsn, flume in feed.flumes.items(): ohlcv = flume.rt_shm hist_ohlcv = flume.hist_shm @@ -313,7 +233,8 @@ async def graphics_update_loop( ) 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.update_from_data( *hist_ohlcv.array[-1][[ @@ -387,7 +308,8 @@ async def graphics_update_loop( 'last_mx_vlm': last_mx_vlm, 'last_mx': last_mx, 'last_mn': last_mn, - } + }, + 'globalz': globalz, }) if vlm_chart: @@ -398,15 +320,15 @@ async def graphics_update_loop( 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` # API that can be reused at least in terms of pulling view # params (eg ``.bars_range()``). 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() async with flume.index_stream( @@ -431,12 +353,11 @@ async def graphics_update_loop( i_diff, append_diff, do_rt_update, - ) = ds.incr_info( - chart=hist_chart, - shm=ds.hist_ohlcv, - state=state, + should_incr, + + ) = hist_viz.incr_info( + state=ds, is_1m=True, - # update_state=False, ) # print( # f'liv: {liv}\n' @@ -557,40 +478,8 @@ def graphics_update_cycle( i_diff, append_diff, do_rt_update, - ) = ds.incr_info() - - # 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 + should_incr, + ) = main_viz.incr_info(state=ds) # TODO: we should only run mxmn when we know # an update is due via ``do_append`` above. @@ -621,11 +510,6 @@ def graphics_update_cycle( # graphic. 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 if ( do_rt_update @@ -645,6 +529,29 @@ def graphics_update_cycle( # 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 # frame_counts = { # typ: len(frame) for typ, frame in frames_by_type.items() @@ -765,6 +672,8 @@ def graphics_update_cycle( ) # check if slow chart needs a resize + + hist_viz = hist_chart._vizs[fqsn] ( _, hist_liv, @@ -772,15 +681,13 @@ def graphics_update_cycle( _, _, _, - ) = ds.incr_info( - chart=hist_chart, - shm=ds.hist_ohlcv, - update_state=False, + _, + ) = hist_viz.incr_info( + state=ds, is_1m=True, ) if hist_liv: - viz = hist_chart._vizs[fqsn] - viz.plot.vb._set_yrange( + hist_viz.plot.vb._set_yrange( # yrange=hist_chart.maxmin(name=fqsn), ) @@ -814,7 +721,7 @@ def graphics_update_cycle( ): viz.draw_last( array_key=curve_name, - only_last_uppx=True, + # only_last_uppx=True, ) # volume chart logic.. @@ -1207,7 +1114,7 @@ async def display_symbol_data( # for zoom-interaction purposes. hist_chart.get_viz(fqsn).draw_last( array_key=fqsn, - only_last_uppx=True, + # only_last_uppx=True, ) pis.setdefault(fqsn, [None, None])[1] = hist_chart.plotItem @@ -1306,7 +1213,7 @@ async def display_symbol_data( # for zoom-interaction purposes. viz.draw_last( array_key=fqsn, - only_last_uppx=True, + # only_last_uppx=True, ) hist_pi.vb.maxmin = partial(