First draft, group y-minmax transform algo
On overlaid ohlc vizs we compute the largest max/min spread and apply that maxmimum "up and down swing" proportion to each `Viz`'s viewbox in the group. We obviously still need to clip to the shortest x-range so that it doesn't look exactly the same as before XDmultichartz
							parent
							
								
									5b68efdf31
								
							
						
					
					
						commit
						f0e6c5827f
					
				| 
						 | 
					@ -46,6 +46,7 @@ from . import _event
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from ._chart import ChartPlotWidget
 | 
					    from ._chart import ChartPlotWidget
 | 
				
			||||||
    from ._dataviz import Viz
 | 
					    from ._dataviz import Viz
 | 
				
			||||||
 | 
					    # from ._overlay import PlotItemOverlay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
log = get_logger(__name__)
 | 
					log = get_logger(__name__)
 | 
				
			||||||
| 
						 | 
					@ -931,11 +932,18 @@ class ChartView(ViewBox):
 | 
				
			||||||
            # graphics (and thus their backing data sets)
 | 
					            # graphics (and thus their backing data sets)
 | 
				
			||||||
            # are in the same co-domain and thus can be sorted
 | 
					            # are in the same co-domain and thus can be sorted
 | 
				
			||||||
            # as one set per plot.
 | 
					            # as one set per plot.
 | 
				
			||||||
            mxmns: dict[
 | 
					            mxmns_by_pi: dict[
 | 
				
			||||||
                pg.PlotItem,
 | 
					                pg.PlotItem,
 | 
				
			||||||
                tuple[float, float],
 | 
					                tuple[float, float],
 | 
				
			||||||
            ] = {}
 | 
					            ] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # collect certain flows into groups and do a common calc to
 | 
				
			||||||
 | 
					            # determine auto-ranging input for `._set_yrange()`.
 | 
				
			||||||
 | 
					            mxmn_groups: dict[
 | 
				
			||||||
 | 
					                set[Viz],
 | 
				
			||||||
 | 
					                set[Viz, tuple[float, float]],
 | 
				
			||||||
 | 
					            ] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for name, viz in chart._vizs.items():
 | 
					            for name, viz in chart._vizs.items():
 | 
				
			||||||
                if not viz.render:
 | 
					                if not viz.render:
 | 
				
			||||||
                    # print(f'skipping {flow.name}')
 | 
					                    # print(f'skipping {flow.name}')
 | 
				
			||||||
| 
						 | 
					@ -957,15 +965,19 @@ class ChartView(ViewBox):
 | 
				
			||||||
                ) = out
 | 
					                ) = out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                pi = viz.plot
 | 
					                pi = viz.plot
 | 
				
			||||||
                mxmn = mxmns.get(pi)
 | 
					                mxmn = mxmns_by_pi.get(pi)
 | 
				
			||||||
                if mxmn:
 | 
					                if mxmn:
 | 
				
			||||||
                    yrange = mxmns[pi] = (
 | 
					                    yrange = mxmns_by_pi[pi] = (
 | 
				
			||||||
                        min(yrange[0], mxmn[0]),
 | 
					                        min(yrange[0], mxmn[0]),
 | 
				
			||||||
                        max(yrange[1], mxmn[1]),
 | 
					                        max(yrange[1], mxmn[1]),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    mxmns[viz.plot] = yrange
 | 
					                    mxmns_by_pi[pi] = yrange
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if viz.is_ohlc:
 | 
				
			||||||
 | 
					                    # print(f'adding {viz.name} to overlay')
 | 
				
			||||||
 | 
					                    mxmn_groups[viz.name] = out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                pi.vb._set_yrange(yrange=yrange)
 | 
					                pi.vb._set_yrange(yrange=yrange)
 | 
				
			||||||
                profiler(
 | 
					                profiler(
 | 
				
			||||||
| 
						 | 
					@ -991,5 +1003,68 @@ class ChartView(ViewBox):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            profiler(f'autoscaled overlays {chart_name}')
 | 
					            profiler(f'autoscaled overlays {chart_name}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        profiler(f'<{chart_name}>.update_graphics_from_flow({name})')
 | 
					            profiler(f'<{chart_name}>.interact_graphics_cycle({name})')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # proportional group auto-scaling per overlay set.
 | 
				
			||||||
 | 
					            # -> loop through overlays on each multi-chart widget
 | 
				
			||||||
 | 
					            #    and scale all y-ranges based on autoscale config.
 | 
				
			||||||
 | 
					            group_mx: float = 0
 | 
				
			||||||
 | 
					            group_mn: float = 0
 | 
				
			||||||
 | 
					            mx_up_rng: float = 0
 | 
				
			||||||
 | 
					            mn_down_rng: float = 0
 | 
				
			||||||
 | 
					            start_datums: dict[ViewBox, float] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for viz_name, out in mxmn_groups.items():
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    ixrng,
 | 
				
			||||||
 | 
					                    read_slc,
 | 
				
			||||||
 | 
					                    (ymn, ymx),
 | 
				
			||||||
 | 
					                ) = out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # determine start datum in view
 | 
				
			||||||
 | 
					                viz = chart._vizs[viz_name]
 | 
				
			||||||
 | 
					                arr = viz.shm.array
 | 
				
			||||||
 | 
					                row_start = arr[read_slc.start - 1]
 | 
				
			||||||
 | 
					                # row_stop = arr[read_slc.stop - 1]
 | 
				
			||||||
 | 
					                if viz.is_ohlc:
 | 
				
			||||||
 | 
					                    y_start = row_start['open']
 | 
				
			||||||
 | 
					                    # y_stop = row_stop['close']
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    y_start = row_start[viz.name]
 | 
				
			||||||
 | 
					                    # y_stop = row_stop[viz.name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                start_datums[viz.plot.vb] = (viz, y_start)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # update max for group
 | 
				
			||||||
 | 
					                up_rng = (ymx - y_start) / y_start
 | 
				
			||||||
 | 
					                down_rng = (ymn - y_start) / y_start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # compute directional (up/down) y-range % swing/dispersion
 | 
				
			||||||
 | 
					                mx_up_rng = max(mx_up_rng, up_rng)
 | 
				
			||||||
 | 
					                mn_down_rng = min(mn_down_rng, down_rng)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # pis2ranges[pi] = (ymn, ymx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                group_mx = max(group_mx, ymx)
 | 
				
			||||||
 | 
					                group_mn = min(group_mn, ymn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                print(
 | 
				
			||||||
 | 
					                    f'{viz.name}@{chart_name} group mxmn calc\n'
 | 
				
			||||||
 | 
					                    f'ymn: {ymn}\n'
 | 
				
			||||||
 | 
					                    f'ymx: {ymx}\n'
 | 
				
			||||||
 | 
					                    f'down %: {mx_up_rng * 100}\n'
 | 
				
			||||||
 | 
					                    f'up %: {mn_down_rng * 100}\n'
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for view, (viz, ystart) in start_datums.items():
 | 
				
			||||||
 | 
					                ymn = ystart * (1 + mn_down_rng)
 | 
				
			||||||
 | 
					                ymx = ystart * (1 + mx_up_rng)
 | 
				
			||||||
 | 
					                print(
 | 
				
			||||||
 | 
					                    f'{view.name} APPLY group mxmn\n'
 | 
				
			||||||
 | 
					                    f'ystart: {ystart}\n'
 | 
				
			||||||
 | 
					                    f'ymn: {ymn}\n'
 | 
				
			||||||
 | 
					                    f'ymx: {ymx}\n'
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                view._set_yrange(yrange=(ymn, ymx))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        profiler.finish()
 | 
					        profiler.finish()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue