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 XD
multichartz
Tyler Goodlet 2023-01-19 14:41:17 -05:00
parent 5b68efdf31
commit f0e6c5827f
1 changed files with 80 additions and 5 deletions

View File

@ -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()