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): | ||||
|     ''' | ||||
|     Chart-local real-time graphics state container. | ||||
|  | @ -154,113 +150,33 @@ class DisplayState(Struct): | |||
|     hist_last_price_sticky: YAxisLabel | ||||
| 
 | ||||
|     # misc state tracking | ||||
|     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, | ||||
|     }) | ||||
|     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, | ||||
|         } | ||||
|     ) | ||||
|     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_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( | ||||
| 
 | ||||
|  | @ -295,7 +211,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 | ||||
|  | @ -315,7 +239,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][[ | ||||
|  | @ -389,7 +314,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: | ||||
|  | @ -400,15 +326,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( | ||||
|  | @ -433,12 +359,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' | ||||
|  | @ -559,40 +484,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. | ||||
|  | @ -623,11 +516,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 | ||||
|  | @ -647,6 +535,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() | ||||
|  | @ -767,6 +678,8 @@ def graphics_update_cycle( | |||
|                 ) | ||||
| 
 | ||||
|         # check if slow chart needs a resize | ||||
| 
 | ||||
|         hist_viz = hist_chart._vizs[fqsn] | ||||
|         ( | ||||
|             _, | ||||
|             hist_liv, | ||||
|  | @ -774,15 +687,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), | ||||
|             ) | ||||
| 
 | ||||
|  | @ -816,7 +727,7 @@ def graphics_update_cycle( | |||
|         ): | ||||
|             viz.draw_last( | ||||
|                 array_key=curve_name, | ||||
|                 only_last_uppx=True, | ||||
|                 # only_last_uppx=True, | ||||
|             ) | ||||
| 
 | ||||
|     # volume chart logic.. | ||||
|  | @ -1209,7 +1120,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 | ||||
| 
 | ||||
|  | @ -1308,7 +1219,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( | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue