From 520905a65305e0d7c05b08e88da990527d45400d Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Sat, 21 Jan 2023 17:31:31 -0500 Subject: [PATCH] Clean up cross-curve intersect point indexing When there are `N`-curves we need to consider the smallest x-data-support subset when figuring out for each major-minor pair such that the "shorter" series is always returns aligned to the longer one. This makes the var naming more explicit with `major/minor_i_start` as well as clarifies more stringently a bunch of other variables and explicitly uses the `minor_y_intersect` y value in the scaling transform calcs. Also fixes some debug prints. --- piker/ui/_interaction.py | 105 ++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/piker/ui/_interaction.py b/piker/ui/_interaction.py index 08530bb0..ab5542c3 100644 --- a/piker/ui/_interaction.py +++ b/piker/ui/_interaction.py @@ -930,17 +930,20 @@ class ChartView(ViewBox): for chart_name, chart in plots.items(): - # Viz "group" maxmins table; presumes that some path - # graphics (and thus their backing data sets) - # are in the same co-domain and thus can be sorted - # as one set per plot. - mxmns_by_pi: dict[ + # Common `PlotItem` maxmin table; presumes that some path + # graphics (and thus their backing data sets) are in the + # same co-domain and view box (since the were added + # a separate graphics objects to a common plot) and thus can + # be sorted as one set per plot. + mxmns_by_common_pi: dict[ pg.PlotItem, tuple[float, float], ] = {} - # collect certain flows into groups and do a common calc to + # collect certain flows have grapics objects **in seperate + # plots/viewboxes** into groups and do a common calc to # determine auto-ranging input for `._set_yrange()`. + # this is primarly used for our so called "log-linearized mxmn_groups: dict[ set[Viz], set[Viz, tuple[float, float]], @@ -967,15 +970,15 @@ class ChartView(ViewBox): ) = out pi = viz.plot - mxmn = mxmns_by_pi.get(pi) + mxmn = mxmns_by_common_pi.get(pi) if mxmn: - yrange = mxmns_by_pi[pi] = ( + yrange = mxmns_by_common_pi[pi] = ( min(yrange[0], mxmn[0]), max(yrange[1], mxmn[1]), ) else: - mxmns_by_pi[pi] = yrange + mxmns_by_common_pi[pi] = yrange if viz.is_ohlc: # print(f'adding {viz.name} to overlay') @@ -1019,7 +1022,7 @@ class ChartView(ViewBox): np.ndarray, # in-view array ], ] = {} - max_start: float = 0 + max_istart: float = 0 major_viz: Viz = None for viz_name, out in mxmn_groups.items(): @@ -1029,15 +1032,13 @@ class ChartView(ViewBox): (ymn, ymx), ) = out - x_start = ixrng[0] - max_start = max(x_start, max_start) - # determine start datum in view viz = chart._vizs[viz_name] arr = viz.shm.array in_view = arr[read_slc] row_start = arr[read_slc.start - 1] - # row_stop = arr[read_slc.stop - 1] + + max_istart = max(in_view[0]['index'], max_istart) if viz.is_ohlc: y_med = np.median(in_view['close']) @@ -1045,11 +1046,12 @@ class ChartView(ViewBox): else: y_med = np.median(in_view[viz.name]) y_start = row_start[viz.name] - # y_stop = row_stop[viz.name] - print( - f'{viz.name} -> (x_start: {x_start}, y_start: {y_start}\n' - ) + # x_start = ixrng[0] + # print( + # f'{viz.name} ->\n' + # f'(x_start: {x_start}, y_start: {y_start}\n' + # ) start_datums[viz.plot.vb] = ( viz, y_start, @@ -1080,17 +1082,14 @@ class ChartView(ViewBox): mn_down_rng = min(mn_down_rng, down_rng) print( - '####################\n' f'{viz.name}@{chart_name} group mxmn calc\n' - '--------------------\nn' + '--------------------\n' f'y_start: {y_start}\n' f'ymn: {ymn}\n' f'ymx: {ymx}\n' f'mx_disp: {mx_disp}\n' - '####################\n' f'up %: {up_rng * 100}\n' f'down %: {down_rng * 100}\n' - '####################\n' f'mx up %: {mx_up_rng * 100}\n' f'mn down %: {mn_down_rng * 100}\n' ) @@ -1128,28 +1127,39 @@ class ChartView(ViewBox): # that the intersecting y-value is used as the # reference point for scaling minor curve's # y-range based on the major curves y-range. - abs_ifirst = minor_in_view[0]['index'] - mshm = major_viz.shm - abs_i_start = max( - abs_ifirst, - mshm.array['index'][0], - ) + # get intersection point y-values for both curves + # abs_i_start = max_istart + + mshm = major_viz.shm + minor_i_start = minor_in_view[0]['index'] + major_i_start = mshm.array['index'][0], + abs_i_start = max( + minor_i_start, + major_i_start, + ) + y_maj_intersect = mshm._array[abs_i_start][key] - y_min_intersect = minor_in_view[abs_i_start - abs_ifirst] + y_minor_intersect = viz.shm._array[abs_i_start][key] # TODO: probably write this as a compile cpython or # numba func. + # if abs_i_start > major_i_start: + # compute directional (up/down) y-range # % swing/dispersion starting at the reference index # determined by the above indexing arithmetic. y_ref = y_maj_intersect - assert y_ref + if not y_ref: + breakpoint() + r_up = (major_mx - y_ref) / y_ref r_down = (major_mn - y_ref) / y_ref - ymn = y_start * (1 + r_down) - ymx = y_start * (1 + r_up) + + minor_y_start = y_minor_intersect + ymn = minor_y_start * (1 + r_down) + ymx = minor_y_start * (1 + r_up) # XXX: handle out of view cases where minor curve # now is outside the range of the major curve. in @@ -1159,42 +1169,47 @@ class ChartView(ViewBox): # is side (up/down) specific. new_maj_mxmn: None | tuple[float, float] = None if y_max > ymx: - y_ref = y_min_intersect[key] + y_ref = y_minor_intersect r_up_minor = (y_max - y_ref) / y_ref new_maj_ymx = y_maj_intersect * (1 + r_up_minor) new_maj_mxmn = (major_mn, new_maj_ymx) - ymx = y_max - print( f'{view.name} OUT OF RANGE:\n' - f'MAJOR is {major_viz.name}\n' + '--------------------\n' f'y_max:{y_max} > ymx:{ymx}\n' + f'RESCALE MAJOR {major_viz.name}:\n' + f'{new_maj_mxmn}\n' ) + ymx = y_max if y_min < ymn: - y_ref = y_min_intersect[key] + y_ref = y_minor_intersect r_down_minor = (y_min - y_ref) / y_ref new_maj_ymn = y_maj_intersect * (1 + r_down_minor) new_maj_mxmn = ( new_maj_ymn, - new_maj_ymx[1] if new_maj_mxmn else major_mx + new_maj_mxmn[1] if new_maj_mxmn else major_mx + ) + print( + f'{view.name} OUT OF RANGE:\n' + '--------------------\n' + f'y_min:{y_min} < ymn:{ymn}\n' + f'RESCALE MAJOR {major_viz.name}:\n' + f'{new_maj_mxmn}\n' ) ymn = y_min - print( - f'{view.name} OUT OF RANGE:\n' - f'MAJOR is {major_viz.name}\n' - f'y_min:{y_min} < ymn:{ymn}\n' - ) - if new_maj_mxmn: + major_mx, major_mn = new_maj_mxmn major_viz.plot.vb._set_yrange( yrange=new_maj_mxmn, + # range_margin=None, ) print( f'{view.name} APPLY group mxmn\n' - f'y_start: {y_start}\n' + '--------------------\n' + f'minor_y_start: {minor_y_start}\n' f'mn_down_rng: {mn_down_rng * 100}\n' f'mx_up_rng: {mx_up_rng * 100}\n' f'scaled ymn: {ymn}\n'