No-overlays, y-ranging optimizations
When the caller passes `do_overlay_scaling=False` we skip the given chart's `Viz` iteration loop, and set the yrange immediately, then continue to the next chart (if `do_linked_charts` is set) instead of a `continue` short circuit within the viz sub-loop. Deats: - add a `_maybe_calc_yrange()` helper which makes the `yranges` provided-or-not case logic more terse (factored). - add a `do_linked_charts=False` short circuit. - drop the legacy commented swing % calcs stuff. - use the `ChartView._viz` when `do_overlay_scaling=False` thus presuming that we want to handle the viz mapped to *this* view box. - add a `._yrange` "last set yrange" tracking var which keeps record of the last ymn/ymx value set in `._set_yrange()` BEFORE doing range margins; this will be used for incremental update in the display loop.storage_cli
							parent
							
								
									858429cfcd
								
							
						
					
					
						commit
						d19b663013
					
				| 
						 | 
					@ -445,6 +445,7 @@ class ChartView(ViewBox):
 | 
				
			||||||
        # TODO: probably just assign this whenever a new `PlotItem` is
 | 
					        # TODO: probably just assign this whenever a new `PlotItem` is
 | 
				
			||||||
        # allocated since they're 1to1 with views..
 | 
					        # allocated since they're 1to1 with views..
 | 
				
			||||||
        self._viz: Viz | None = None
 | 
					        self._viz: Viz | None = None
 | 
				
			||||||
 | 
					        self._yrange: tuple[float, float] | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def start_ic(
 | 
					    def start_ic(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
| 
						 | 
					@ -483,7 +484,7 @@ class ChartView(ViewBox):
 | 
				
			||||||
    async def open_async_input_handler(
 | 
					    async def open_async_input_handler(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ) -> 'ChartView':
 | 
					    ) -> ChartView:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async with (
 | 
					        async with (
 | 
				
			||||||
            _event.open_handlers(
 | 
					            _event.open_handlers(
 | 
				
			||||||
| 
						 | 
					@ -785,7 +786,7 @@ class ChartView(ViewBox):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # NOTE: this value pairs (more or less) with L1 label text
 | 
					        # NOTE: this value pairs (more or less) with L1 label text
 | 
				
			||||||
        # height offset from from the bid/ask lines.
 | 
					        # height offset from from the bid/ask lines.
 | 
				
			||||||
        range_margin: float | None = 0.09,
 | 
					        range_margin: float | None = 0.1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bars_range: Optional[tuple[int, int, int, int]] = None,
 | 
					        bars_range: Optional[tuple[int, int, int, int]] = None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -858,6 +859,11 @@ class ChartView(ViewBox):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ylow, yhigh = yrange
 | 
					            ylow, yhigh = yrange
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # always stash last range for diffing by
 | 
				
			||||||
 | 
					        # incremental update calculations BEFORE adding
 | 
				
			||||||
 | 
					        # margin.
 | 
				
			||||||
 | 
					        self._yrange = ylow, yhigh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # view margins: stay within a % of the "true range"
 | 
					        # view margins: stay within a % of the "true range"
 | 
				
			||||||
        if range_margin is not None:
 | 
					        if range_margin is not None:
 | 
				
			||||||
            diff = yhigh - ylow
 | 
					            diff = yhigh - ylow
 | 
				
			||||||
| 
						 | 
					@ -870,10 +876,6 @@ class ChartView(ViewBox):
 | 
				
			||||||
                yhigh * (1 + range_margin),
 | 
					                yhigh * (1 + range_margin),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # XXX: this often needs to be unset
 | 
					 | 
				
			||||||
        # to get different view modes to operate
 | 
					 | 
				
			||||||
        # correctly!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # print(
 | 
					        # print(
 | 
				
			||||||
        #     f'set limits {self.name}:\n'
 | 
					        #     f'set limits {self.name}:\n'
 | 
				
			||||||
        #     f'ylow: {ylow}\n'
 | 
					        #     f'ylow: {ylow}\n'
 | 
				
			||||||
| 
						 | 
					@ -975,7 +977,6 @@ class ChartView(ViewBox):
 | 
				
			||||||
            # ms_threshold=4,
 | 
					            # ms_threshold=4,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        chart = self._chart
 | 
					 | 
				
			||||||
        linked = self.linked
 | 
					        linked = self.linked
 | 
				
			||||||
        if (
 | 
					        if (
 | 
				
			||||||
            do_linked_charts
 | 
					            do_linked_charts
 | 
				
			||||||
| 
						 | 
					@ -983,7 +984,9 @@ class ChartView(ViewBox):
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            plots = {linked.chart.name: linked.chart}
 | 
					            plots = {linked.chart.name: linked.chart}
 | 
				
			||||||
            plots |= linked.subplots
 | 
					            plots |= linked.subplots
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
 | 
					            chart = self._chart
 | 
				
			||||||
            plots = {chart.name: chart}
 | 
					            plots = {chart.name: chart}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: a faster single-loop-iterator way of doing this?
 | 
					        # TODO: a faster single-loop-iterator way of doing this?
 | 
				
			||||||
| 
						 | 
					@ -1031,42 +1034,45 @@ class ChartView(ViewBox):
 | 
				
			||||||
            ] = {}
 | 
					            ] = {}
 | 
				
			||||||
            major_in_view: np.ndarray = None
 | 
					            major_in_view: np.ndarray = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # ONLY auto-yrange the viz mapped to THIS view box
 | 
				
			||||||
 | 
					            if not do_overlay_scaling:
 | 
				
			||||||
 | 
					                viz = self._viz
 | 
				
			||||||
 | 
					                if debug_print:
 | 
				
			||||||
 | 
					                    print(f'ONLY ranging THIS viz: {viz.name}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                out = _maybe_calc_yrange(
 | 
				
			||||||
 | 
					                    viz,
 | 
				
			||||||
 | 
					                    yranges,
 | 
				
			||||||
 | 
					                    profiler,
 | 
				
			||||||
 | 
					                    chart_name,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                if out is None:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                read_slc, yrange = out
 | 
				
			||||||
 | 
					                viz.plot.vb._set_yrange(yrange=yrange)
 | 
				
			||||||
 | 
					                profiler(f'{viz.name}@{chart_name} single curve yrange')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # don't iterate overlays, just move to next chart
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for name, viz in chart._vizs.items():
 | 
					            for name, viz in chart._vizs.items():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if debug_print:
 | 
					                if debug_print:
 | 
				
			||||||
                    print(
 | 
					                    print(
 | 
				
			||||||
                        f'UX GRAPHICS CYCLE: {viz.name}@{chart_name}'
 | 
					                        f'UX GRAPHICS CYCLE: {viz.name}@{chart_name}'
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if not viz.render:
 | 
					                out = _maybe_calc_yrange(
 | 
				
			||||||
                    # print(f'skipping {flow.name}')
 | 
					                    viz,
 | 
				
			||||||
 | 
					                    yranges,
 | 
				
			||||||
 | 
					                    profiler,
 | 
				
			||||||
 | 
					                    chart_name,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                if out is None:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # pass in no array which will read and render from the last
 | 
					                read_slc, yrange = out
 | 
				
			||||||
                # passed array (normally provided by the display loop.)
 | 
					 | 
				
			||||||
                in_view, i_read_range, _ = viz.update_graphics()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not in_view:
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                profiler(f'{viz.name}@{chart_name} `Viz.update_graphics()`')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                yrange = yranges.get(viz) if yranges else None
 | 
					 | 
				
			||||||
                if yrange is not None:
 | 
					 | 
				
			||||||
                    # print(f'INPUT {viz.name} yrange: {yrange}')
 | 
					 | 
				
			||||||
                    read_slc = slice(*i_read_range)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    out = viz.maxmin(i_read_range=i_read_range)
 | 
					 | 
				
			||||||
                    if out is None:
 | 
					 | 
				
			||||||
                        log.warning(f'No yrange provided for {name}!?')
 | 
					 | 
				
			||||||
                        return
 | 
					 | 
				
			||||||
                    (
 | 
					 | 
				
			||||||
                        _,  # ixrng,
 | 
					 | 
				
			||||||
                        read_slc,
 | 
					 | 
				
			||||||
                        yrange
 | 
					 | 
				
			||||||
                    ) = out
 | 
					 | 
				
			||||||
                    profiler(f'{viz.name}@{chart_name} `Viz.maxmin()`')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                pi = viz.plot
 | 
					                pi = viz.plot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # handle multiple graphics-objs per viewbox cases
 | 
					                # handle multiple graphics-objs per viewbox cases
 | 
				
			||||||
| 
						 | 
					@ -1091,9 +1097,6 @@ class ChartView(ViewBox):
 | 
				
			||||||
                    ymn, ymx = yrange
 | 
					                    ymn, ymx = yrange
 | 
				
			||||||
                    # print(f'adding {viz.name} to overlay')
 | 
					                    # print(f'adding {viz.name} to overlay')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if not do_overlay_scaling:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    # determine start datum in view
 | 
					                    # determine start datum in view
 | 
				
			||||||
                    arr = viz.shm.array
 | 
					                    arr = viz.shm.array
 | 
				
			||||||
                    in_view = arr[read_slc]
 | 
					                    in_view = arr[read_slc]
 | 
				
			||||||
| 
						 | 
					@ -1132,24 +1135,6 @@ class ChartView(ViewBox):
 | 
				
			||||||
                        major_in_view = in_view
 | 
					                        major_in_view = in_view
 | 
				
			||||||
                        profiler(f'{viz.name}@{chart_name} set new major')
 | 
					                        profiler(f'{viz.name}@{chart_name} set new major')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    # compute directional (up/down) y-range % swing/dispersion
 | 
					 | 
				
			||||||
                    # y_ref = y_med
 | 
					 | 
				
			||||||
                    # up_rng = (ymx - y_ref) / y_ref
 | 
					 | 
				
			||||||
                    # down_rng = (ymn - y_ref) / y_ref
 | 
					 | 
				
			||||||
                    # mx_up_rng = max(mx_up_rng, up_rng)
 | 
					 | 
				
			||||||
                    # mn_down_rng = min(mn_down_rng, down_rng)
 | 
					 | 
				
			||||||
                    # print(
 | 
					 | 
				
			||||||
                    #     f'{viz.name}@{chart_name} group mxmn calc\n'
 | 
					 | 
				
			||||||
                    #     '--------------------\n'
 | 
					 | 
				
			||||||
                    #     f'y_start: {y_start}\n'
 | 
					 | 
				
			||||||
                    #     f'ymn: {ymn}\n'
 | 
					 | 
				
			||||||
                    #     f'ymx: {ymx}\n'
 | 
					 | 
				
			||||||
                    #     f'mx_disp: {mx_disp}\n'
 | 
					 | 
				
			||||||
                    #     f'up %: {up_rng * 100}\n'
 | 
					 | 
				
			||||||
                    #     f'down %: {down_rng * 100}\n'
 | 
					 | 
				
			||||||
                    #     f'mx up %: {mx_up_rng * 100}\n'
 | 
					 | 
				
			||||||
                    #     f'mn down %: {mn_down_rng * 100}\n'
 | 
					 | 
				
			||||||
                    # )
 | 
					 | 
				
			||||||
                    profiler(f'{viz.name}@{chart_name} MINOR curve scale')
 | 
					                    profiler(f'{viz.name}@{chart_name} MINOR curve scale')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # non-overlay group case
 | 
					                # non-overlay group case
 | 
				
			||||||
| 
						 | 
					@ -1165,21 +1150,32 @@ class ChartView(ViewBox):
 | 
				
			||||||
            # thus a single viz/overlay) then we ONLY set the lone
 | 
					            # thus a single viz/overlay) then we ONLY set the lone
 | 
				
			||||||
            # chart's (viz) yrange and short circuit to the next chart
 | 
					            # chart's (viz) yrange and short circuit to the next chart
 | 
				
			||||||
            # in the linked charts sequence.
 | 
					            # in the linked charts sequence.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (
 | 
					            if (
 | 
				
			||||||
                not do_overlay_scaling
 | 
					                len(overlay_table) < 2
 | 
				
			||||||
                or len(overlay_table) < 2
 | 
					 | 
				
			||||||
                or not overlay_table
 | 
					                or not overlay_table
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                if debug_print:
 | 
					                if debug_print:
 | 
				
			||||||
                    print(f'ONLY ranging major: {viz.name}')
 | 
					                    print(f'ONLY ranging major: {viz.name}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # we're either in `do_overlay_scaling=False` mode
 | 
				
			||||||
 | 
					                # or there is only one curve so we need to pick
 | 
				
			||||||
 | 
					                # that "only curve".
 | 
				
			||||||
                if not major_viz:
 | 
					                if not major_viz:
 | 
				
			||||||
                    major_viz = viz
 | 
					                    major_viz = viz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if yranges is not None:
 | 
				
			||||||
 | 
					                    yrange = yranges.get(major_viz) or yrange
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                assert yrange
 | 
				
			||||||
 | 
					                print(f'ONLY ranging major: {viz.name}')
 | 
				
			||||||
                major_viz.plot.vb._set_yrange(
 | 
					                major_viz.plot.vb._set_yrange(
 | 
				
			||||||
                    yrange=yrange,
 | 
					                    yrange=yrange,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                profiler(f'{viz.name}@{chart_name} single curve yrange')
 | 
					                profiler(f'{viz.name}@{chart_name} single curve yrange')
 | 
				
			||||||
 | 
					                if not do_linked_charts:
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            profiler(f'<{chart_name}>.interact_graphics_cycle({name})')
 | 
					            profiler(f'<{chart_name}>.interact_graphics_cycle({name})')
 | 
				
			||||||
| 
						 | 
					@ -1192,7 +1188,6 @@ class ChartView(ViewBox):
 | 
				
			||||||
                    y_start,
 | 
					                    y_start,
 | 
				
			||||||
                    y_min,
 | 
					                    y_min,
 | 
				
			||||||
                    y_max,
 | 
					                    y_max,
 | 
				
			||||||
                    # y_med,
 | 
					 | 
				
			||||||
                    read_slc,
 | 
					                    read_slc,
 | 
				
			||||||
                    minor_in_view,
 | 
					                    minor_in_view,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
| 
						 | 
					@ -1400,3 +1395,49 @@ class ChartView(ViewBox):
 | 
				
			||||||
            #     breakpoint()
 | 
					            #     breakpoint()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        profiler.finish()
 | 
					        profiler.finish()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _maybe_calc_yrange(
 | 
				
			||||||
 | 
					    viz: Viz,
 | 
				
			||||||
 | 
					    yranges: dict[Viz, tuple[float, float]],
 | 
				
			||||||
 | 
					    profiler: Profiler,
 | 
				
			||||||
 | 
					    chart_name: str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					) -> tuple[slice, tuple[float, float]] | None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not viz.render:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					        # # print(f'skipping {flow.name}')
 | 
				
			||||||
 | 
					        # continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # pass in no array which will read and render from the last
 | 
				
			||||||
 | 
					    # passed array (normally provided by the display loop.)
 | 
				
			||||||
 | 
					    in_view, i_read_range, _ = viz.update_graphics()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not in_view:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					        # continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    profiler(f'{viz.name}@{chart_name} `Viz.update_graphics()`')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # check if explicit yranges were passed in by the caller
 | 
				
			||||||
 | 
					    yrange = yranges.get(viz) if yranges else None
 | 
				
			||||||
 | 
					    if yrange is not None:
 | 
				
			||||||
 | 
					        read_slc = slice(*i_read_range)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        out = viz.maxmin(i_read_range=i_read_range)
 | 
				
			||||||
 | 
					        if out is None:
 | 
				
			||||||
 | 
					            log.warning(f'No yrange provided for {viz.name}!?')
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            _,  # ixrng,
 | 
				
			||||||
 | 
					            read_slc,
 | 
				
			||||||
 | 
					            yrange
 | 
				
			||||||
 | 
					        ) = out
 | 
				
			||||||
 | 
					        profiler(f'{viz.name}@{chart_name} `Viz.maxmin()`')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        read_slc,
 | 
				
			||||||
 | 
					        yrange,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue