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.multichartz
							parent
							
								
									0deee65318
								
							
						
					
					
						commit
						d7b9c4044e
					
				| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue