Rename `Flow` -> `Viz`
The type is better described as a "data visualization": https://en.wikipedia.org/wiki/Data_and_information_visualization Add `ChartPlotWidget.get_viz()` to start working towards not accessing the private table directly XD We'll probably end up using the name `Flow` for a type that tracks a collection of composed/cascaded `Flume`s: https://en.wikipedia.org/wiki/Two-port_network#Cascade_connectionepoch_indexing_and_dataviz_layer
							parent
							
								
									9ace053aaf
								
							
						
					
					
						commit
						86d09d9305
					
				|  | @ -302,7 +302,7 @@ class DynamicDateAxis(Axis): | |||
|         # XX: ARGGGGG AG:LKSKDJF:LKJSDFD | ||||
|         chart = self.pi.chart_widget | ||||
| 
 | ||||
|         flow = chart._flows[chart.name] | ||||
|         flow = chart._vizs[chart.name] | ||||
|         shm = flow.shm | ||||
|         bars = shm.array | ||||
|         first = shm._first.value | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ from ._interaction import ChartView | |||
| from ._forms import FieldsForm | ||||
| from .._profile import pg_profile_enabled, ms_slower_then | ||||
| from ._overlay import PlotItemOverlay | ||||
| from ._flows import Flow | ||||
| from ._flows import Viz | ||||
| from ._search import SearchWidget | ||||
| from . import _pg_overrides as pgo | ||||
| from .._profile import Profiler | ||||
|  | @ -711,7 +711,7 @@ class LinkedSplits(QWidget): | |||
|         if style == 'ohlc_bar': | ||||
| 
 | ||||
|             # graphics, data_key = cpw.draw_ohlc( | ||||
|             flow = cpw.draw_ohlc( | ||||
|             viz = cpw.draw_ohlc( | ||||
|                 name, | ||||
|                 shm, | ||||
|                 flume=flume, | ||||
|  | @ -727,7 +727,7 @@ class LinkedSplits(QWidget): | |||
|         elif style == 'line': | ||||
|             add_label = True | ||||
|             # graphics, data_key = cpw.draw_curve( | ||||
|             flow = cpw.draw_curve( | ||||
|             viz = cpw.draw_curve( | ||||
|                 name, | ||||
|                 shm, | ||||
|                 flume, | ||||
|  | @ -738,7 +738,7 @@ class LinkedSplits(QWidget): | |||
|         elif style == 'step': | ||||
|             add_label = True | ||||
|             # graphics, data_key = cpw.draw_curve( | ||||
|             flow = cpw.draw_curve( | ||||
|             viz = cpw.draw_curve( | ||||
|                 name, | ||||
|                 shm, | ||||
|                 flume, | ||||
|  | @ -751,8 +751,8 @@ class LinkedSplits(QWidget): | |||
|         else: | ||||
|             raise ValueError(f"Chart style {style} is currently unsupported") | ||||
| 
 | ||||
|         graphics = flow.graphics | ||||
|         data_key = flow.name | ||||
|         graphics = viz.graphics | ||||
|         data_key = viz.name | ||||
| 
 | ||||
|         if _is_main: | ||||
|             assert style == 'ohlc_bar', 'main chart must be OHLC' | ||||
|  | @ -908,7 +908,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         # self.setViewportMargins(0, 0, 0, 0) | ||||
| 
 | ||||
|         # registry of overlay curve names | ||||
|         self._flows: dict[str, Flow] = {} | ||||
|         self._vizs: dict[str, Viz] = {} | ||||
| 
 | ||||
|         self.feed: Feed | None = None | ||||
| 
 | ||||
|  | @ -974,7 +974,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         Return a range tuple for the bars present in view. | ||||
| 
 | ||||
|         ''' | ||||
|         main_flow = self._flows[self.name] | ||||
|         main_flow = self._vizs[self.name] | ||||
|         ifirst, l, lbar, rbar, r, ilast = main_flow.datums_range() | ||||
|         return l, lbar, rbar, r | ||||
| 
 | ||||
|  | @ -1038,9 +1038,9 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         Set the view box to the "default" startup view of the scene. | ||||
| 
 | ||||
|         ''' | ||||
|         flow = self._flows.get(self.name) | ||||
|         flow = self._vizs.get(self.name) | ||||
|         if not flow: | ||||
|             log.warning(f'`Flow` for {self.name} not loaded yet?') | ||||
|             log.warning(f'`Viz` for {self.name} not loaded yet?') | ||||
|             return | ||||
| 
 | ||||
|         arr = flow.shm.array | ||||
|  | @ -1220,7 +1220,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
| 
 | ||||
|         **graphics_kwargs, | ||||
| 
 | ||||
|     ) -> Flow: | ||||
|     ) -> Viz: | ||||
|         ''' | ||||
|         Draw a "curve" (line plot graphics) for the provided data in | ||||
|         the input shm array ``shm``. | ||||
|  | @ -1254,7 +1254,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|                 **graphics_kwargs, | ||||
|             ) | ||||
| 
 | ||||
|         flow = self._flows[data_key] = Flow( | ||||
|         flow = self._vizs[data_key] = Viz( | ||||
|             data_key, | ||||
|             pi, | ||||
|             shm, | ||||
|  | @ -1332,7 +1332,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         array_key: Optional[str] = None, | ||||
|         **draw_curve_kwargs, | ||||
| 
 | ||||
|     ) -> Flow: | ||||
|     ) -> Viz: | ||||
|         ''' | ||||
|         Draw OHLC datums to chart. | ||||
| 
 | ||||
|  | @ -1358,7 +1358,7 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         Update the named internal graphics from ``array``. | ||||
| 
 | ||||
|         ''' | ||||
|         flow = self._flows[array_key or graphics_name] | ||||
|         flow = self._vizs[array_key or graphics_name] | ||||
|         return flow.update_graphics( | ||||
|             array_key=array_key, | ||||
|             **kwargs, | ||||
|  | @ -1426,15 +1426,15 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|             delayed=True, | ||||
|         ) | ||||
| 
 | ||||
|         # TODO: here we should instead look up the ``Flow.shm.array`` | ||||
|         # TODO: here we should instead look up the ``Viz.shm.array`` | ||||
|         # and read directly from shm to avoid copying to memory first | ||||
|         # and then reading it again here. | ||||
|         flow_key = name or self.name | ||||
|         flow = self._flows.get(flow_key) | ||||
|         viz = self._vizs.get(flow_key) | ||||
|         if ( | ||||
|             flow is None | ||||
|             viz is None | ||||
|         ): | ||||
|             log.error(f"flow {flow_key} doesn't exist in chart {self.name} !?") | ||||
|             log.error(f"viz {flow_key} doesn't exist in chart {self.name} !?") | ||||
|             key = res = 0, 0 | ||||
| 
 | ||||
|         else: | ||||
|  | @ -1445,11 +1445,11 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|                 rbar, | ||||
|                 r, | ||||
|                 last, | ||||
|             ) = bars_range or flow.datums_range() | ||||
|             ) = bars_range or viz.datums_range() | ||||
|             profiler(f'{self.name} got bars range') | ||||
| 
 | ||||
|             key = round(lbar), round(rbar) | ||||
|             res = flow.maxmin(*key) | ||||
|             res = viz.maxmin(*key) | ||||
| 
 | ||||
|             if ( | ||||
|                 res is None | ||||
|  | @ -1465,3 +1465,9 @@ class ChartPlotWidget(pg.PlotWidget): | |||
|         profiler(f'yrange mxmn: {key} -> {res}') | ||||
|         # print(f'{flow_key} yrange mxmn: {key} -> {res}') | ||||
|         return res | ||||
| 
 | ||||
|     def get_viz( | ||||
|         self, | ||||
|         key: str, | ||||
|     ) -> Viz: | ||||
|         return self._vizs[key] | ||||
|  |  | |||
|  | @ -274,8 +274,8 @@ class ContentsLabels: | |||
|     ) -> None: | ||||
|         for chart, name, label, update in self._labels: | ||||
| 
 | ||||
|             flow = chart._flows[name] | ||||
|             array = flow.shm.array | ||||
|             viz = chart.get_viz(name) | ||||
|             array = viz.shm.array | ||||
| 
 | ||||
|             if not ( | ||||
|                 index >= 0 | ||||
|  | @ -482,25 +482,32 @@ class Cursor(pg.GraphicsObject): | |||
| 
 | ||||
|     def add_curve_cursor( | ||||
|         self, | ||||
|         plot: ChartPlotWidget,  # noqa | ||||
|         chart: ChartPlotWidget,  # noqa | ||||
|         curve: 'PlotCurveItem',  # noqa | ||||
| 
 | ||||
|     ) -> LineDot: | ||||
|         # if this plot contains curves add line dot "cursors" to denote | ||||
|         # if this chart contains curves add line dot "cursors" to denote | ||||
|         # the current sample under the mouse | ||||
|         main_flow = plot._flows[plot.name] | ||||
|         main_viz = chart.get_viz(chart.name) | ||||
| 
 | ||||
|         # read out last index | ||||
|         i = main_flow.shm.array[-1]['index'] | ||||
|         i = main_viz.shm.array[-1]['index'] | ||||
|         cursor = LineDot( | ||||
|             curve, | ||||
|             index=i, | ||||
|             plot=plot | ||||
|             plot=chart | ||||
|         ) | ||||
|         plot.addItem(cursor) | ||||
|         self.graphics[plot].setdefault('cursors', []).append(cursor) | ||||
|         chart.addItem(cursor) | ||||
|         self.graphics[chart].setdefault('cursors', []).append(cursor) | ||||
|         return cursor | ||||
| 
 | ||||
|     def mouseAction(self, action, plot):  # noqa | ||||
|     def mouseAction( | ||||
|         self, | ||||
|         action: str, | ||||
|         plot: ChartPlotWidget, | ||||
| 
 | ||||
|     ) -> None:  # noqa | ||||
| 
 | ||||
|         log.debug(f"{(action, plot.name)}") | ||||
|         if action == 'Enter': | ||||
|             self.active_plot = plot | ||||
|  |  | |||
|  | @ -78,7 +78,7 @@ from .._profile import Profiler | |||
| log = get_logger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| # TODO: delegate this to each `Flow.maxmin()` which includes | ||||
| # TODO: delegate this to each `Viz.maxmin()` which includes | ||||
| # caching and further we should implement the following stream based | ||||
| # approach, likely with ``numba``: | ||||
| # https://arxiv.org/abs/cs/0610046 | ||||
|  | @ -113,7 +113,7 @@ def chart_maxmin( | |||
| 
 | ||||
|     # TODO: we need to NOT call this to avoid a manual | ||||
|     # np.max/min trigger and especially on the vlm_chart | ||||
|     # flows which aren't shown.. like vlm? | ||||
|     # vizs which aren't shown.. like vlm? | ||||
|     if vlm_chart: | ||||
|         out = vlm_chart.maxmin() | ||||
|         if out: | ||||
|  | @ -220,7 +220,7 @@ class DisplayState(Struct): | |||
|         _, _, _, r = chart.bars_range() | ||||
|         liv = r >= shm.index | ||||
| 
 | ||||
|         # update the "last datum" (aka extending the flow graphic with | ||||
|         # 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 | ||||
|  | @ -301,14 +301,14 @@ async def graphics_update_loop( | |||
|         fqsn = symbol.fqsn | ||||
| 
 | ||||
|         # update last price sticky | ||||
|         fast_pi = fast_chart._flows[fqsn].plot | ||||
|         fast_pi = fast_chart._vizs[fqsn].plot | ||||
|         last_price_sticky = fast_pi.getAxis('right')._stickies[fqsn] | ||||
|         last_price_sticky.update_from_data( | ||||
|             *ohlcv.array[-1][['index', 'close']] | ||||
|         ) | ||||
|         last_price_sticky.show() | ||||
| 
 | ||||
|         slow_pi = hist_chart._flows[fqsn].plot | ||||
|         slow_pi = hist_chart._vizs[fqsn].plot | ||||
|         hist_last_price_sticky = slow_pi.getAxis('right')._stickies[fqsn] | ||||
|         hist_last_price_sticky.update_from_data( | ||||
|             *hist_ohlcv.array[-1][['index', 'close']] | ||||
|  | @ -383,7 +383,7 @@ async def graphics_update_loop( | |||
|         }) | ||||
| 
 | ||||
|         if vlm_chart: | ||||
|             vlm_pi = vlm_chart._flows['volume'].plot | ||||
|             vlm_pi = vlm_chart._vizs['volume'].plot | ||||
|             vlm_sticky = vlm_pi.getAxis('right')._stickies['volume'] | ||||
|             ds.vlm_chart = vlm_chart | ||||
|             ds.vlm_sticky = vlm_sticky | ||||
|  | @ -441,8 +441,8 @@ async def graphics_update_loop( | |||
|                         and liv | ||||
|                     ): | ||||
|                         # hist_chart.increment_view(steps=i_diff) | ||||
|                         flow = hist_chart._flows[fqsn] | ||||
|                         flow.plot.vb._set_yrange( | ||||
|                         viz = hist_chart._vizs[fqsn] | ||||
|                         viz.plot.vb._set_yrange( | ||||
|                             # yrange=hist_chart.maxmin(name=fqsn) | ||||
|                         ) | ||||
|                         # hist_chart.view._set_yrange(yrange=hist_chart.maxmin()) | ||||
|  | @ -518,7 +518,7 @@ def graphics_update_cycle( | |||
|     flume = ds.flume | ||||
|     sym = flume.symbol | ||||
|     fqsn = sym.fqsn | ||||
|     main_flow = chart._flows[fqsn] | ||||
|     main_viz = chart._vizs[fqsn] | ||||
| 
 | ||||
|     profiler = Profiler( | ||||
|         msg=f'Graphics loop cycle for: `{chart.name}`', | ||||
|  | @ -562,7 +562,7 @@ def graphics_update_cycle( | |||
|     ): | ||||
|         # print(f'INCREMENTING {fqsn}') | ||||
|         chart.increment_view(steps=i_diff) | ||||
|         main_flow.plot.vb._set_yrange( | ||||
|         main_viz.plot.vb._set_yrange( | ||||
|             # yrange=(mn, mx), | ||||
|         ) | ||||
| 
 | ||||
|  | @ -629,7 +629,7 @@ def graphics_update_cycle( | |||
|             # chart.name, | ||||
|             # do_append=do_append, | ||||
|         ) | ||||
|         main_flow.draw_last(array_key=fqsn) | ||||
|         main_viz.draw_last(array_key=fqsn) | ||||
| 
 | ||||
|         hist_chart.update_graphics_from_flow( | ||||
|             fqsn, | ||||
|  | @ -748,7 +748,7 @@ def graphics_update_cycle( | |||
|             and not chart._static_yrange == 'axis' | ||||
|         ): | ||||
|             # main_vb = chart.view | ||||
|             main_vb = chart._flows[fqsn].plot.vb | ||||
|             main_vb = chart._vizs[fqsn].plot.vb | ||||
|             if ( | ||||
|                 main_vb._ic is None | ||||
|                 or not main_vb._ic.is_set() | ||||
|  | @ -779,26 +779,26 @@ def graphics_update_cycle( | |||
|             is_1m=True, | ||||
|         ) | ||||
|         if hist_liv: | ||||
|             flow = hist_chart._flows[fqsn] | ||||
|             flow.plot.vb._set_yrange( | ||||
|             viz = hist_chart._vizs[fqsn] | ||||
|             viz.plot.vb._set_yrange( | ||||
|                 # yrange=hist_chart.maxmin(name=fqsn), | ||||
|             ) | ||||
| 
 | ||||
|     # XXX: update this every draw cycle to make L1-always-in-view work. | ||||
|     vars['last_mx'], vars['last_mn'] = mx, mn | ||||
| 
 | ||||
|     # run synchronous update on all linked flows | ||||
|     # TODO: should the "main" (aka source) flow be special? | ||||
|     for curve_name, flow in chart._flows.items(): | ||||
|     # run synchronous update on all linked viz | ||||
|     # TODO: should the "main" (aka source) viz be special? | ||||
|     for curve_name, viz in chart._vizs.items(): | ||||
|         # update any overlayed fsp flows | ||||
|         if ( | ||||
|             # curve_name != chart.data_key | ||||
|             curve_name != fqsn | ||||
|             and not flow.is_ohlc | ||||
|             and not viz.is_ohlc | ||||
|         ): | ||||
|             update_fsp_chart( | ||||
|                 chart, | ||||
|                 flow, | ||||
|                 viz, | ||||
|                 curve_name, | ||||
|                 array_key=curve_name, | ||||
|             ) | ||||
|  | @ -812,7 +812,7 @@ def graphics_update_cycle( | |||
|             # and not do_append | ||||
|             # and not do_rt_update | ||||
|         ): | ||||
|             flow.draw_last( | ||||
|             viz.draw_last( | ||||
|                 array_key=curve_name, | ||||
|                 only_last_uppx=True, | ||||
|             ) | ||||
|  | @ -821,7 +821,7 @@ def graphics_update_cycle( | |||
|     # TODO: can we unify this with the above loop? | ||||
|     if vlm_chart: | ||||
|         # print(f"DOING VLM {fqsn}") | ||||
|         vlm_flows = vlm_chart._flows | ||||
|         vlm_vizs = vlm_chart._vizs | ||||
| 
 | ||||
|         # always update y-label | ||||
|         ds.vlm_sticky.update_from_data( | ||||
|  | @ -866,21 +866,21 @@ def graphics_update_cycle( | |||
|                 vars['last_mx_vlm'] = mx_vlm_in_view | ||||
| 
 | ||||
|         # update all downstream FSPs | ||||
|         for curve_name, flow in vlm_flows.items(): | ||||
|         for curve_name, viz in vlm_vizs.items(): | ||||
| 
 | ||||
|             if ( | ||||
|                 curve_name not in {'volume', fqsn} | ||||
|                 and flow.render | ||||
|                 and viz.render | ||||
|                 and ( | ||||
|                     liv and do_rt_update | ||||
|                     or do_append | ||||
|                 ) | ||||
|                 # and not flow.is_ohlc | ||||
|                 # and not viz.is_ohlc | ||||
|                 # and curve_name != fqsn | ||||
|             ): | ||||
|                 update_fsp_chart( | ||||
|                     vlm_chart, | ||||
|                     flow, | ||||
|                     viz, | ||||
|                     curve_name, | ||||
|                     array_key=curve_name, | ||||
|                     # do_append=uppx < update_uppx, | ||||
|  | @ -889,7 +889,7 @@ def graphics_update_cycle( | |||
|                 # is this even doing anything? | ||||
|                 # (pretty sure it's the real-time | ||||
|                 # resizing from last quote?) | ||||
|                 fvb = flow.plot.vb | ||||
|                 fvb = viz.plot.vb | ||||
|                 fvb._set_yrange( | ||||
|                     name=curve_name, | ||||
|                 ) | ||||
|  | @ -905,9 +905,9 @@ def graphics_update_cycle( | |||
|                 # 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) | ||||
|                 # graphic for all vizs | ||||
|                 # print(f'drawing last {viz.name}') | ||||
|                 viz.draw_last(array_key=curve_name) | ||||
| 
 | ||||
| 
 | ||||
| async def link_views_with_region( | ||||
|  | @ -937,12 +937,12 @@ async def link_views_with_region( | |||
|     hist_pi.addItem(region, ignoreBounds=True) | ||||
|     region.setOpacity(6/16) | ||||
| 
 | ||||
|     flow = rt_chart._flows[flume.symbol.fqsn] | ||||
|     assert flow | ||||
|     viz = rt_chart._vizs[flume.symbol.fqsn] | ||||
|     assert viz | ||||
| 
 | ||||
|     # XXX: no idea why this doesn't work but it's causing | ||||
|     # a weird placement of the region on the way-far-left.. | ||||
|     # region.setClipItem(flow.graphics) | ||||
|     # region.setClipItem(viz.graphics) | ||||
| 
 | ||||
|     # poll for datums load and timestep detection | ||||
|     for _ in range(100): | ||||
|  | @ -1052,11 +1052,11 @@ def multi_maxmin( | |||
| 
 | ||||
| ) -> tuple[float, float]: | ||||
|     ''' | ||||
|     Flows "group" maxmin loop; assumes all named flows | ||||
|     Viz "group" maxmin loop; assumes all named vizs | ||||
|     are in the same co-domain and thus can be sorted | ||||
|     as one set. | ||||
| 
 | ||||
|     Iterates all the named flows and calls the chart | ||||
|     Iterates all the named vizs and calls the chart | ||||
|     api to find their range values and return. | ||||
| 
 | ||||
|     TODO: really we should probably have a more built-in API | ||||
|  | @ -1279,7 +1279,7 @@ async def display_symbol_data( | |||
|                 hist_pi.hideAxis('left') | ||||
|                 hist_pi.hideAxis('bottom') | ||||
| 
 | ||||
|                 flow = hist_chart.draw_curve( | ||||
|                 viz = hist_chart.draw_curve( | ||||
|                     fqsn, | ||||
|                     hist_ohlcv, | ||||
|                     flume, | ||||
|  | @ -1300,8 +1300,8 @@ async def display_symbol_data( | |||
|                 # specially store ref to shm for lookup in display loop | ||||
|                 # since only a placeholder of `None` is entered in | ||||
|                 # ``.draw_curve()``. | ||||
|                 flow = hist_chart._flows[fqsn] | ||||
|                 assert flow.plot is hist_pi | ||||
|                 viz = hist_chart._vizs[fqsn] | ||||
|                 assert viz.plot is hist_pi | ||||
|                 pis.setdefault(fqsn, [None, None])[1] = hist_pi | ||||
| 
 | ||||
|                 rt_pi = rt_chart.overlay_plotitem( | ||||
|  | @ -1312,7 +1312,7 @@ async def display_symbol_data( | |||
|                 rt_pi.hideAxis('left') | ||||
|                 rt_pi.hideAxis('bottom') | ||||
| 
 | ||||
|                 flow = rt_chart.draw_curve( | ||||
|                 viz = rt_chart.draw_curve( | ||||
|                     fqsn, | ||||
|                     ohlcv, | ||||
|                     flume, | ||||
|  | @ -1333,8 +1333,8 @@ async def display_symbol_data( | |||
|                 # specially store ref to shm for lookup in display loop | ||||
|                 # since only a placeholder of `None` is entered in | ||||
|                 # ``.draw_curve()``. | ||||
|                 flow = rt_chart._flows[fqsn] | ||||
|                 assert flow.plot is rt_pi | ||||
|                 viz = rt_chart._vizs[fqsn] | ||||
|                 assert viz.plot is rt_pi | ||||
|                 pis.setdefault(fqsn, [None, None])[0] = rt_pi | ||||
| 
 | ||||
|             rt_chart.setFocus() | ||||
|  |  | |||
|  | @ -377,7 +377,7 @@ class SelectRect(QtWidgets.QGraphicsRectItem): | |||
|         nbars = ixmx - ixmn + 1 | ||||
| 
 | ||||
|         chart = self._chart | ||||
|         data = chart._flows[chart.name].shm.array[ixmn:ixmx] | ||||
|         data = chart.get_viz(chart.name).shm.array[ixmn:ixmx] | ||||
| 
 | ||||
|         if len(data): | ||||
|             std = data['close'].std() | ||||
|  |  | |||
|  | @ -65,7 +65,7 @@ log = get_logger(__name__) | |||
| 
 | ||||
| 
 | ||||
| def render_baritems( | ||||
|     flow: Flow, | ||||
|     viz: Viz, | ||||
|     graphics: BarItems, | ||||
|     read: tuple[ | ||||
|         int, int, np.ndarray, | ||||
|  | @ -89,7 +89,7 @@ def render_baritems( | |||
|     bars = graphics | ||||
| 
 | ||||
|     # if no source data renderer exists create one. | ||||
|     self = flow | ||||
|     self = viz | ||||
|     show_bars: bool = False | ||||
| 
 | ||||
|     r = self._src_r | ||||
|  | @ -98,28 +98,28 @@ def render_baritems( | |||
| 
 | ||||
|         # OHLC bars path renderer | ||||
|         r = self._src_r = Renderer( | ||||
|             flow=self, | ||||
|             viz=self, | ||||
|             fmtr=OHLCBarsFmtr( | ||||
|                 shm=flow.shm, | ||||
|                 flow=flow, | ||||
|                 shm=viz.shm, | ||||
|                 viz=viz, | ||||
|                 _last_read=read, | ||||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|         ds_curve_r = Renderer( | ||||
|             flow=self, | ||||
|             viz=self, | ||||
|             fmtr=OHLCBarsAsCurveFmtr( | ||||
|                 shm=flow.shm, | ||||
|                 flow=flow, | ||||
|                 shm=viz.shm, | ||||
|                 viz=viz, | ||||
|                 _last_read=read, | ||||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|         curve = FlattenedOHLC( | ||||
|             name=f'{flow.name}_ds_ohlc', | ||||
|             name=f'{viz.name}_ds_ohlc', | ||||
|             color=bars._color, | ||||
|         ) | ||||
|         flow.ds_graphics = curve | ||||
|         viz.ds_graphics = curve | ||||
|         curve.hide() | ||||
|         self.plot.addItem(curve) | ||||
| 
 | ||||
|  | @ -142,7 +142,7 @@ def render_baritems( | |||
|     ): | ||||
|         # print('FLIPPING TO BARS') | ||||
|         should_line = False | ||||
|         flow._in_ds = False | ||||
|         viz._in_ds = False | ||||
| 
 | ||||
|     elif ( | ||||
|         not in_line | ||||
|  | @ -150,7 +150,7 @@ def render_baritems( | |||
|     ): | ||||
|         # print('FLIPPING TO LINE') | ||||
|         should_line = True | ||||
|         flow._in_ds = True | ||||
|         viz._in_ds = True | ||||
| 
 | ||||
|     profiler(f'ds logic complete line={should_line}') | ||||
| 
 | ||||
|  | @ -196,9 +196,9 @@ def render_baritems( | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class Flow(msgspec.Struct):  # , frozen=True): | ||||
| class Viz(msgspec.Struct):  # , frozen=True): | ||||
|     ''' | ||||
|     (Financial Signal-)Flow compound type which wraps a real-time | ||||
|     (Data) "Visualization" compound type which wraps a real-time | ||||
|     shm array stream with displayed graphics (curves, charts) | ||||
|     for high level access and control as well as efficient incremental | ||||
|     update. | ||||
|  | @ -216,7 +216,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|     # for tracking y-mn/mx for y-axis auto-ranging | ||||
|     yrange: tuple[float, float] = None | ||||
| 
 | ||||
|     # in some cases a flow may want to change its | ||||
|     # in some cases a viz may want to change its | ||||
|     # graphical "type" or, "form" when downsampling, to | ||||
|     # start this is only ever an interpolation line. | ||||
|     ds_graphics: Optional[Curve] = None | ||||
|  | @ -251,12 +251,6 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|     def shm(self) -> ShmArray: | ||||
|         return self._shm | ||||
| 
 | ||||
|     # TODO: remove this and only allow setting through | ||||
|     # private ``._shm`` attr? | ||||
|     # @shm.setter | ||||
|     # def shm(self, shm: ShmArray) -> ShmArray: | ||||
|     #     self._shm = shm | ||||
| 
 | ||||
|     def maxmin( | ||||
|         self, | ||||
|         lbar: int, | ||||
|  | @ -318,7 +312,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|     def view_range(self) -> tuple[int, int]: | ||||
|         ''' | ||||
|         Return the indexes in view for the associated | ||||
|         plot displaying this flow's data. | ||||
|         plot displaying this viz's data. | ||||
| 
 | ||||
|         ''' | ||||
|         vr = self.plot.viewRect() | ||||
|  | @ -344,7 +338,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|         # TODO: avoid this and have shm passed | ||||
|         # in earlier. | ||||
|         if self.shm is None: | ||||
|             # haven't initialized the flow yet | ||||
|             # haven't initialized the viz yet | ||||
|             return (0, l, 0, 0, r, 0) | ||||
| 
 | ||||
|         array = self.shm.array | ||||
|  | @ -420,7 +414,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
| 
 | ||||
|         ''' | ||||
|         profiler = Profiler( | ||||
|             msg=f'Flow.update_graphics() for {self.name}', | ||||
|             msg=f'Viz.update_graphics() for {self.name}', | ||||
|             disabled=not pg_profile_enabled(), | ||||
|             ms_threshold=4, | ||||
|             # ms_threshold=ms_slower_then, | ||||
|  | @ -475,10 +469,10 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|             if isinstance(graphics, StepCurve): | ||||
| 
 | ||||
|                 r = self._src_r = Renderer( | ||||
|                     flow=self, | ||||
|                     viz=self, | ||||
|                     fmtr=StepCurveFmtr( | ||||
|                         shm=self.shm, | ||||
|                         flow=self, | ||||
|                         viz=self, | ||||
|                         _last_read=read, | ||||
|                     ), | ||||
|                 ) | ||||
|  | @ -493,10 +487,10 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|                 if not r: | ||||
|                     # just using for ``.diff()`` atm.. | ||||
|                     r = self._src_r = Renderer( | ||||
|                         flow=self, | ||||
|                         viz=self, | ||||
|                         fmtr=IncrementalFormatter( | ||||
|                             shm=self.shm, | ||||
|                             flow=self, | ||||
|                             viz=self, | ||||
|                             _last_read=read, | ||||
|                         ), | ||||
|                     ) | ||||
|  | @ -581,7 +575,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
|         path, data, reset = out | ||||
| 
 | ||||
|         # if self.yrange: | ||||
|         #     print(f'flow {self.name} yrange from m4: {self.yrange}') | ||||
|         #     print(f'viz {self.name} yrange from m4: {self.yrange}') | ||||
| 
 | ||||
|         # XXX: SUPER UGGGHHH... without this we get stale cache | ||||
|         # graphics that don't update until you downsampler again.. | ||||
|  | @ -691,7 +685,7 @@ class Flow(msgspec.Struct):  # , frozen=True): | |||
| 
 | ||||
| class Renderer(msgspec.Struct): | ||||
| 
 | ||||
|     flow: Flow | ||||
|     viz: Viz | ||||
|     fmtr: IncrementalFormatter | ||||
| 
 | ||||
|     # output graphics rendering, the main object | ||||
|  | @ -794,7 +788,7 @@ class Renderer(msgspec.Struct): | |||
|         - blah blah blah (from notes) | ||||
| 
 | ||||
|         ''' | ||||
|         # TODO: can the renderer just call ``Flow.read()`` directly? | ||||
|         # TODO: can the renderer just call ``Viz.read()`` directly? | ||||
|         # unpack latest source data read | ||||
|         fmtr = self.fmtr | ||||
| 
 | ||||
|  | @ -858,7 +852,7 @@ class Renderer(msgspec.Struct): | |||
|             path is None | ||||
|             or should_redraw | ||||
|         ): | ||||
|             # print(f"{self.flow.name} -> REDRAWING BRUH") | ||||
|             # print(f"{self.viz.name} -> REDRAWING BRUH") | ||||
|             if new_sample_rate and showing_src_data: | ||||
|                 log.info(f'DEDOWN -> {array_key}') | ||||
|                 self._in_ds = False | ||||
|  | @ -870,8 +864,8 @@ class Renderer(msgspec.Struct): | |||
|                     y_1d, | ||||
|                     uppx, | ||||
|                 ) | ||||
|                 self.flow.yrange = ymn, ymx | ||||
|                 # print(f'{self.flow.name} post ds: ymn, ymx: {ymn},{ymx}') | ||||
|                 self.viz.yrange = ymn, ymx | ||||
|                 # print(f'{self.viz.name} post ds: ymn, ymx: {ymn},{ymx}') | ||||
| 
 | ||||
|                 reset = True | ||||
|                 profiler(f'FULL PATH downsample redraw={should_ds}') | ||||
|  | @ -942,7 +936,7 @@ class Renderer(msgspec.Struct): | |||
|             profiler('generated append qpath') | ||||
| 
 | ||||
|             if use_fpath: | ||||
|                 # print(f'{self.flow.name}: FAST PATH') | ||||
|                 # print(f'{self.viz.name}: FAST PATH') | ||||
|                 # an attempt at trying to make append-updates faster.. | ||||
|                 if fast_path is None: | ||||
|                     fast_path = append_path | ||||
|  |  | |||
|  | @ -289,7 +289,7 @@ async def run_fsp_ui( | |||
|         # first UI update, usually from shm pushed history | ||||
|         update_fsp_chart( | ||||
|             chart, | ||||
|             chart._flows[array_key], | ||||
|             chart.get_viz(array_key), | ||||
|             name, | ||||
|             array_key=array_key, | ||||
|         ) | ||||
|  | @ -357,7 +357,7 @@ async def run_fsp_ui( | |||
|         #         last = time.time() | ||||
| 
 | ||||
| 
 | ||||
| # TODO: maybe this should be our ``Flow`` type since it maps | ||||
| # TODO: maybe this should be our ``Viz`` type since it maps | ||||
| # one flume to the next? The machinery for task/actor mgmt should | ||||
| # be part of the instantiation API? | ||||
| class FspAdmin: | ||||
|  | @ -386,7 +386,7 @@ class FspAdmin: | |||
| 
 | ||||
|         # TODO: make this a `.src_flume` and add | ||||
|         # a `dst_flume`? | ||||
|         # (=> but then wouldn't this be the most basic `Flow`?) | ||||
|         # (=> but then wouldn't this be the most basic `Viz`?) | ||||
|         self.flume = flume | ||||
| 
 | ||||
|     def rr_next_portal(self) -> tractor.Portal: | ||||
|  | @ -694,7 +694,7 @@ async def open_vlm_displays( | |||
| 
 | ||||
|         ) -> tuple[float, float]: | ||||
|             ''' | ||||
|             Flows "group" maxmin loop; assumes all named flows | ||||
|             Viz "group" maxmin loop; assumes all named flows | ||||
|             are in the same co-domain and thus can be sorted | ||||
|             as one set. | ||||
| 
 | ||||
|  | @ -865,7 +865,7 @@ async def open_vlm_displays( | |||
|                     # specially store ref to shm for lookup in display loop | ||||
|                     # since only a placeholder of `None` is entered in | ||||
|                     # ``.draw_curve()``. | ||||
|                     # flow = chart._flows[name] | ||||
|                     # viz = chart._vizs[name] | ||||
|                     assert flow.plot is pi | ||||
| 
 | ||||
|             chart_curves( | ||||
|  | @ -901,7 +901,7 @@ async def open_vlm_displays( | |||
|             # liquidity events (well at least on low OHLC periods - 1s). | ||||
|             vlm_curve.hide() | ||||
|             chart.removeItem(vlm_curve) | ||||
|             vflow = chart._flows['volume'] | ||||
|             vflow = chart._vizs['volume'] | ||||
|             vflow.render = False | ||||
| 
 | ||||
|             # avoid range sorting on volume once disabled | ||||
|  |  | |||
|  | @ -504,7 +504,7 @@ class ChartView(ViewBox): | |||
| 
 | ||||
|         # if ( | ||||
|         #     ev.delta() < 0 | ||||
|         #     and vl >= len(chart._flows[chart.name].shm.array) + 666 | ||||
|         #     and vl >= len(chart._vizs[chart.name].shm.array) + 666 | ||||
|         # ): | ||||
|         #     log.debug("Min zoom bruh...") | ||||
|         #     return | ||||
|  | @ -821,7 +821,7 @@ class ChartView(ViewBox): | |||
|             # XXX: only compute the mxmn range | ||||
|             # if none is provided as input! | ||||
|             if not yrange: | ||||
|                 # flow = chart._flows[name] | ||||
|                 # flow = chart._vizs[name] | ||||
|                 yrange = self._maxmin() | ||||
| 
 | ||||
|                 if yrange is None: | ||||
|  | @ -912,7 +912,7 @@ class ChartView(ViewBox): | |||
|         graphics items which are our children. | ||||
| 
 | ||||
|         ''' | ||||
|         graphics = [f.graphics for f in self._chart._flows.values()] | ||||
|         graphics = [f.graphics for f in self._chart._vizs.values()] | ||||
|         if not graphics: | ||||
|             return 0 | ||||
| 
 | ||||
|  | @ -948,7 +948,7 @@ class ChartView(ViewBox): | |||
|             plots |= linked.subplots | ||||
| 
 | ||||
|         for chart_name, chart in plots.items(): | ||||
|             for name, flow in chart._flows.items(): | ||||
|             for name, flow in chart._vizs.items(): | ||||
| 
 | ||||
|                 if ( | ||||
|                     not flow.render | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ from ._compression import ( | |||
| if TYPE_CHECKING: | ||||
|     from ._flows import ( | ||||
|         Renderer, | ||||
|         Flow, | ||||
|         Viz, | ||||
|     ) | ||||
|     from .._profile import Profiler | ||||
| 
 | ||||
|  | @ -73,7 +73,7 @@ class IncrementalFormatter(msgspec.Struct): | |||
| 
 | ||||
|     ''' | ||||
|     shm: ShmArray | ||||
|     flow: Flow | ||||
|     viz: Viz | ||||
| 
 | ||||
|     # last read from shm (usually due to an update call) | ||||
|     _last_read: tuple[ | ||||
|  | @ -90,7 +90,7 @@ class IncrementalFormatter(msgspec.Struct): | |||
|     def __repr__(self) -> str: | ||||
|         msg = ( | ||||
|             f'{type(self)}: ->\n\n' | ||||
|             f'fqsn={self.flow.name}\n' | ||||
|             f'fqsn={self.viz.name}\n' | ||||
|             f'shm_name={self.shm.token["shm_name"]}\n\n' | ||||
| 
 | ||||
|             f'last_vr={self._last_vr}\n' | ||||
|  | @ -130,7 +130,7 @@ class IncrementalFormatter(msgspec.Struct): | |||
|             last_in_view, | ||||
|         ) = self.last_read | ||||
| 
 | ||||
|         # TODO: can the renderer just call ``Flow.read()`` directly? | ||||
|         # TODO: can the renderer just call ``Viz.read()`` directly? | ||||
|         # unpack latest source data read | ||||
|         ( | ||||
|             xfirst, | ||||
|  | @ -337,7 +337,7 @@ class IncrementalFormatter(msgspec.Struct): | |||
|         if slice_to_inview: | ||||
|             view_changed = self._track_inview_range(view_range) | ||||
|             array = in_view | ||||
|             profiler(f'{self.flow.name} view range slice {view_range}') | ||||
|             profiler(f'{self.viz.name} view range slice {view_range}') | ||||
| 
 | ||||
|         hist = array[:slice_to_head] | ||||
| 
 | ||||
|  | @ -370,9 +370,9 @@ class IncrementalFormatter(msgspec.Struct): | |||
|         #     # assert (len(appended) - 1) == append_len | ||||
|         #     # assert len(appended) == append_len | ||||
|         #     print( | ||||
|         #         f'{self.flow.name} APPEND LEN: {append_len}\n' | ||||
|         #         f'{self.flow.name} APPENDED: {appended}\n' | ||||
|         #         f'{self.flow.name} app_tres: {app_tres}\n' | ||||
|         #         f'{self.viz.name} APPEND LEN: {append_len}\n' | ||||
|         #         f'{self.viz.name} APPENDED: {appended}\n' | ||||
|         #         f'{self.viz.name} app_tres: {app_tres}\n' | ||||
|         #     ) | ||||
| 
 | ||||
|         # update the last "in view data range" | ||||
|  |  | |||
|  | @ -1,3 +0,0 @@ | |||
| """ | ||||
| Super hawt Qt UI components | ||||
| """ | ||||
|  | @ -1,67 +0,0 @@ | |||
| import sys | ||||
| 
 | ||||
| from PySide2.QtCharts import QtCharts | ||||
| from PySide2.QtWidgets import QApplication, QMainWindow | ||||
| from PySide2.QtCore import Qt, QPointF | ||||
| from PySide2 import QtGui | ||||
| import qdarkstyle | ||||
| 
 | ||||
| data = ((1, 7380, 7520, 7380, 7510, 7324), | ||||
|     (2, 7520, 7580, 7410, 7440, 7372), | ||||
|     (3, 7440, 7650, 7310, 7520, 7434), | ||||
|     (4, 7450, 7640, 7450, 7550, 7480), | ||||
|     (5, 7510, 7590, 7460, 7490, 7502), | ||||
|     (6, 7500, 7590, 7480, 7560, 7512), | ||||
|     (7, 7560, 7830, 7540, 7800, 7584)) | ||||
| 
 | ||||
| 
 | ||||
| app = QApplication([]) | ||||
| # set dark stylesheet | ||||
| # import pdb; pdb.set_trace() | ||||
| app.setStyleSheet(qdarkstyle.load_stylesheet_pyside()) | ||||
| 
 | ||||
| series = QtCharts.QCandlestickSeries() | ||||
| series.setDecreasingColor(Qt.darkRed) | ||||
| series.setIncreasingColor(Qt.darkGreen) | ||||
| 
 | ||||
| ma5 = QtCharts.QLineSeries()  # 5-days average data line | ||||
| tm = []  # stores str type data | ||||
| 
 | ||||
| # in a loop,  series and ma5 append corresponding data | ||||
| for num, o, h, l, c, m in data: | ||||
|     candle = QtCharts.QCandlestickSet(o, h, l, c) | ||||
|     series.append(candle) | ||||
|     ma5.append(QPointF(num, m)) | ||||
|     tm.append(str(num)) | ||||
| 
 | ||||
| pen = candle.pen() | ||||
| # import pdb; pdb.set_trace() | ||||
| 
 | ||||
| chart = QtCharts.QChart() | ||||
| 
 | ||||
| # import pdb; pdb.set_trace() | ||||
| series.setBodyOutlineVisible(False) | ||||
| series.setCapsVisible(False) | ||||
| # brush = QtGui.QBrush() | ||||
| # brush.setColor(Qt.green) | ||||
| # series.setBrush(brush) | ||||
| chart.addSeries(series)  # candle | ||||
| chart.addSeries(ma5)  # ma5 line | ||||
| 
 | ||||
| chart.setAnimationOptions(QtCharts.QChart.SeriesAnimations) | ||||
| chart.createDefaultAxes() | ||||
| chart.legend().hide() | ||||
| 
 | ||||
| chart.axisX(series).setCategories(tm) | ||||
| chart.axisX(ma5).setVisible(False) | ||||
| 
 | ||||
| view = QtCharts.QChartView(chart) | ||||
| view.chart().setTheme(QtCharts.QChart.ChartTheme.ChartThemeDark) | ||||
| view.setRubberBand(QtCharts.QChartView.HorizontalRubberBand) | ||||
| # chartview.chart().setTheme(QtCharts.QChart.ChartTheme.ChartThemeBlueCerulean) | ||||
| 
 | ||||
| ui = QMainWindow() | ||||
| # ui.setGeometry(50, 50, 500, 300) | ||||
| ui.setCentralWidget(view) | ||||
| ui.show() | ||||
| sys.exit(app.exec_()) | ||||
		Loading…
	
		Reference in New Issue