Formalize rc `redraw()` msg-endpoint

So now a chart rc client can ask to invoke the new
`Viz.reset_graphics()` by timeframe and fqme Bo This handy when doing
underlying (real time or tsp) edits and you want to make the UI reflect
the changes incrementally.

Impl deatz:
- tweak the msg schema to use a `cmd:  str` which normally maps to
  (something similar to) the UI method name instead of `annot` and now
  offer 3 such "commands": 'redraw', 'remove', 'SelectRect'.
- impl `AnnotCtl.redraw()` which sends the underlying `msg: dict` on the
  correct `tractor.Msgstream` ipc instance.
  - since ipc-stream lookups now happen in multiple client methods impl
    a private `._get_ipc()` to do the error raise on unknown fqmes.
distribute_dis
Tyler Goodlet 2024-01-03 17:33:15 -05:00
parent 9be29a707d
commit d3e7b5cd0e
1 changed files with 54 additions and 30 deletions

View File

@ -50,15 +50,16 @@ from ._display import DisplayState
from ._interaction import ChartView from ._interaction import ChartView
from ._editors import SelectRect from ._editors import SelectRect
from ._chart import ChartPlotWidget from ._chart import ChartPlotWidget
from ._dataviz import Viz
log = get_logger(__name__) log = get_logger(__name__)
# NOTE: this is set by the `._display.graphics_update_loop()` once # NOTE: this is UPDATED by the `._display.graphics_update_loop()`
# all chart widgets / Viz per flume have been initialized allowing # once all chart widgets / Viz per flume have been initialized
# for remote annotation (control) of any chart-actor's mkt feed by # allowing for remote annotation (control) of any chart-actor's mkt
# fqme lookup Bo # feed by fqme lookup Bo
_dss: dict[str, DisplayState] | None = None _dss: dict[str, DisplayState] = {}
# stash each and every client connection so that they can all # stash each and every client connection so that they can all
# be cancelled on shutdown/error. # be cancelled on shutdown/error.
@ -96,7 +97,7 @@ async def serve_rc_annots(
async for msg in annot_req_stream: async for msg in annot_req_stream:
match msg: match msg:
case { case {
'annot': 'SelectRect', 'cmd': 'SelectRect',
'fqme': fqme, 'fqme': fqme,
'timeframe': timeframe, 'timeframe': timeframe,
'meth': str(meth), 'meth': str(meth),
@ -110,14 +111,6 @@ async def serve_rc_annots(
}[timeframe] }[timeframe]
cv: ChartView = chart.cv cv: ChartView = chart.cv
# sanity
if timeframe == 60:
assert (
chart.linked.godwidget.hist_linked.chart.view
is
cv
)
# annot type lookup from cmd # annot type lookup from cmd
rect = SelectRect( rect = SelectRect(
viewbox=cv, viewbox=cv,
@ -143,7 +136,8 @@ async def serve_rc_annots(
await annot_req_stream.send(aid) await annot_req_stream.send(aid)
case { case {
'rm_annot': int(aid), 'cmd': 'remove',
'aid': int(aid),
}: }:
# NOTE: this is normally entered on # NOTE: this is normally entered on
# a client's annotation de-alloc normally # a client's annotation de-alloc normally
@ -156,19 +150,29 @@ async def serve_rc_annots(
await annot_req_stream.send(aid) await annot_req_stream.send(aid)
case { case {
'cmd': 'redraw',
'fqme': fqme, 'fqme': fqme,
'render': int(aid),
'viz_name': str(viz_name),
'timeframe': timeframe, 'timeframe': timeframe,
# TODO: maybe more fields?
# 'render': int(aid),
# 'viz_name': str(viz_name),
}: }:
# NOTE: old match from the 60s display loop task
# | { # | {
# 'backfilling': (str(viz_name), timeframe), # 'backfilling': (str(viz_name), timeframe),
# }: # }:
ds: DisplayState = _dss[viz_name] ds: DisplayState = _dss[fqme]
chart: ChartPlotWidget = { viz: Viz = {
60: ds.hist_chart, 60: ds.hist_viz,
1: ds.chart, 1: ds.viz,
}[timeframe] }[timeframe]
log.warning(
f'Forcing VIZ REDRAW:\n'
f'fqme: {fqme}\n'
f'timeframe: {timeframe}\n'
)
viz.reset_graphics()
case _: case _:
log.error( log.error(
@ -227,6 +231,18 @@ class AnnotCtl(Struct):
# ids to their equivalent IPC msg-streams. # ids to their equivalent IPC msg-streams.
_ipcs: dict[int, MsgStream] = {} _ipcs: dict[int, MsgStream] = {}
def _get_ipc(
self,
fqme: str,
) -> MsgStream:
ipc: MsgStream = self.fqme2ipc.get(fqme)
if ipc is None:
raise SymbolNotFound(
'No chart (actor) seems to have mkt feed loaded?\n'
f'{fqme}'
)
return ipc
async def add_rect( async def add_rect(
self, self,
fqme: str, fqme: str,
@ -246,16 +262,10 @@ class AnnotCtl(Struct):
the instances `id(obj)` from the remote UI actor. the instances `id(obj)` from the remote UI actor.
''' '''
ipc: MsgStream = self.fqme2ipc.get(fqme) ipc: MsgStream = self._get_ipc(fqme)
if ipc is None:
raise SymbolNotFound(
'No chart (actor) seems to have mkt feed loaded?\n'
f'{fqme}'
)
await ipc.send({ await ipc.send({
'fqme': fqme, 'fqme': fqme,
'annot': 'SelectRect', 'cmd': 'SelectRect',
'timeframe': timeframe, 'timeframe': timeframe,
# 'meth': str(meth), # 'meth': str(meth),
'meth': 'set_view_pos' if domain == 'view' else 'set_scene_pos', 'meth': 'set_view_pos' if domain == 'view' else 'set_scene_pos',
@ -288,7 +298,8 @@ class AnnotCtl(Struct):
''' '''
ipc: MsgStream = self._ipcs[aid] ipc: MsgStream = self._ipcs[aid]
await ipc.send({ await ipc.send({
'rm_annot': aid, 'cmd': 'remove',
'aid': aid,
}) })
removed: bool = await ipc.receive() removed: bool = await ipc.receive()
return removed return removed
@ -307,6 +318,19 @@ class AnnotCtl(Struct):
finally: finally:
await self.remove(aid) await self.remove(aid)
async def redraw(
self,
fqme: str,
timeframe: float,
) -> None:
await self._get_ipc(fqme).send({
'cmd': 'redraw',
'fqme': fqme,
# 'render': int(aid),
# 'viz_name': str(viz_name),
'timeframe': timeframe,
})
# TODO: do we even need this? # TODO: do we even need this?
# async def modify( # async def modify(
# self, # self,