From 679602166390eb81cdf9f7713941722031cd611b Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Wed, 28 Dec 2022 01:30:34 -0500 Subject: [PATCH] Further fixes `Viz.default_view()` and `.index_step()` Use proper uppx scaling when either of scaling the data to the x-domain index-range or when the uppx is < 1 (now that we support it) such that both the fast and slow chart always appropriately scale and offset to the y-axis with the last datum graphic just adjacent to the order line arrow markers. Further this fixes the `.index_step()` calc to use the "earliest" 16 values to compute the expected sample step diff since the last set often contained gaps due to start up race conditions and generated unexpected/incorrect output. Further this drops the `.curve_width_pxs()` method and replaces it with `.px_width()`, taken from the graphics object API and instead returns the pixel account for the whole view width instead of the x-domain-data-range within the view. --- piker/ui/_dataviz.py | 105 +++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/piker/ui/_dataviz.py b/piker/ui/_dataviz.py index 88d4eada..07ead769 100644 --- a/piker/ui/_dataviz.py +++ b/piker/ui/_dataviz.py @@ -286,10 +286,14 @@ class Viz(msgspec.Struct): # , frozen=True): ) -> float: if self._index_step is None: index = self.shm.array[self.index_field] - self._index_step = max( - np.diff(index[-16:]).max(), - 1, - ) + isample = index[:16] + mxdiff = np.diff(isample).max() + self._index_step = max(mxdiff, 1) + if ( + mxdiff < 1 + or 1 < mxdiff < 60 + ): + breakpoint() return self._index_step @@ -298,6 +302,8 @@ class Viz(msgspec.Struct): # , frozen=True): lbar: int, rbar: int, + use_caching: bool = True, + ) -> Optional[tuple[float, float]]: ''' Compute the cached max and min y-range values for a given @@ -308,15 +314,17 @@ class Viz(msgspec.Struct): # , frozen=True): # TODO: hash the slice instead maybe? # https://stackoverflow.com/a/29980872 rkey = (round(lbar), round(rbar)) - cached_result = self._mxmns.get(rkey) - do_print = False # (self.index_step() == 60) - if cached_result: - if do_print: - print( - f'{self.name} CACHED maxmin\n' - f'{rkey} -> {cached_result}' - ) - return cached_result + + do_print: bool = False + if use_caching: + cached_result = self._mxmns.get(rkey) + if cached_result: + if do_print: + print( + f'{self.name} CACHED maxmin\n' + f'{rkey} -> {cached_result}' + ) + return cached_result shm = self.shm if shm is None: @@ -332,14 +340,15 @@ class Viz(msgspec.Struct): # , frozen=True): stop_t=rbar, step=self.index_step(), ) - slice_view = arr[read_slc] else: ifirst = arr[0]['index'] - slice_view = arr[ - lbar - ifirst: + read_slc = slice( + lbar - ifirst, (rbar - ifirst) + 1 - ] + ) + + slice_view = arr[read_slc] if not slice_view.size: log.warning(f'{self.name} no maxmin in view?') @@ -366,14 +375,13 @@ class Viz(msgspec.Struct): # , frozen=True): mxmn = ylow, yhigh if ( do_print - # and self.index_step() > 1 ): s = 3 print( f'{self.name} MANUAL ohlc={self.is_ohlc} maxmin:\n' f'{rkey} -> {mxmn}\n' f'read_slc: {read_slc}\n' - f'abs_slc: {slice_view["index"]}\n' + # f'abs_slc: {slice_view["index"]}\n' f'first {s}:\n{slice_view[:s]}\n' f'last {s}:\n{slice_view[-s:]}\n' ) @@ -610,7 +618,7 @@ class Viz(msgspec.Struct): # , frozen=True): return graphics should_redraw: bool = False - ds_allowed: bool = True + ds_allowed: bool = True # guard for m4 activation # TODO: probably specialize ``Renderer`` types instead of # these logic checks? @@ -624,7 +632,7 @@ class Viz(msgspec.Struct): # , frozen=True): graphics, r, should_redraw, - in_line, + ds_allowed, # in line mode? ) = render_baritems( self, graphics, @@ -632,7 +640,6 @@ class Viz(msgspec.Struct): # , frozen=True): profiler, **kwargs, ) - ds_allowed = in_line elif not r: if isinstance(graphics, StepCurve): @@ -807,7 +814,7 @@ class Viz(msgspec.Struct): # , frozen=True): # XXX: pretty sure we don't need this? # if isinstance(g, Curve): # with dsg.reset_cache(): - uppx = self._last_uppx + uppx = round(self._last_uppx) y = y[-uppx:] ymn, ymx = y.min(), y.max() # print(f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}') @@ -829,19 +836,6 @@ class Viz(msgspec.Struct): # , frozen=True): # print(f'updating NOT DS curve {self.name}') g.update() - def curve_width_pxs(self) -> float: - ''' - Return the width of the current datums in view in pixel units. - - ''' - _, lbar, rbar, _ = self.bars_range() - return self.view.mapViewToDevice( - QLineF( - lbar, 0, - rbar, 0 - ) - ).length() - def default_view( self, bars_from_y: int = int(616 * 3/8), @@ -900,19 +894,33 @@ class Viz(msgspec.Struct): # , frozen=True): # l->r distance in scene units, no larger then data span data_diff = last_datum - first_datum - rl_diff = min(vr - vl, data_diff) + rl_diff = vr - vl + rescale_to_data: bool = False + # new_uppx: float = 1 + + if rl_diff > data_diff: + rescale_to_data = True + rl_diff = data_diff + new_uppx: float = data_diff / self.px_width() # orient by offset from the y-axis including # space to compensate for the L1 labels. if not y_offset: - _, offset = chartw.pre_l1_xs() + _, l1_offset = chartw.pre_l1_xs() + + offset = l1_offset + + if ( + rescale_to_data + ): + offset = (offset / uppx) * new_uppx else: offset = (y_offset * step) + uppx*step # align right side of view to the rightmost datum + the selected # offset from above. - r_reset = last_datum + offset + r_reset = (self.graphics.x_last() or last_datum) + offset # no data is in view so check for the only 2 sane cases: # - entire view is LEFT of data @@ -1054,3 +1062,22 @@ class Viz(msgspec.Struct): # , frozen=True): do_rt_update, should_tread, ) + + def px_width(self) -> float: + ''' + Return the width of the view box containing + this graphic in pixel units. + + ''' + vb = self.plot.vb + if not vb: + return 0 + + vl, vr = self.view_range() + + return vb.mapViewToDevice( + QLineF( + vl, 0, + vr, 0, + ) + ).length()