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.epoch_indexing_and_dataviz_layer
parent
fc17187ff4
commit
459cbfdbad
|
@ -286,10 +286,14 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
) -> float:
|
) -> float:
|
||||||
if self._index_step is None:
|
if self._index_step is None:
|
||||||
index = self.shm.array[self.index_field]
|
index = self.shm.array[self.index_field]
|
||||||
self._index_step = max(
|
isample = index[:16]
|
||||||
np.diff(index[-16:]).max(),
|
mxdiff = np.diff(isample).max()
|
||||||
1,
|
self._index_step = max(mxdiff, 1)
|
||||||
)
|
if (
|
||||||
|
mxdiff < 1
|
||||||
|
or 1 < mxdiff < 60
|
||||||
|
):
|
||||||
|
breakpoint()
|
||||||
|
|
||||||
return self._index_step
|
return self._index_step
|
||||||
|
|
||||||
|
@ -298,6 +302,8 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
lbar: int,
|
lbar: int,
|
||||||
rbar: int,
|
rbar: int,
|
||||||
|
|
||||||
|
use_caching: bool = True,
|
||||||
|
|
||||||
) -> Optional[tuple[float, float]]:
|
) -> Optional[tuple[float, float]]:
|
||||||
'''
|
'''
|
||||||
Compute the cached max and min y-range values for a given
|
Compute the cached max and min y-range values for a given
|
||||||
|
@ -308,8 +314,10 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
# TODO: hash the slice instead maybe?
|
# TODO: hash the slice instead maybe?
|
||||||
# https://stackoverflow.com/a/29980872
|
# https://stackoverflow.com/a/29980872
|
||||||
rkey = (round(lbar), round(rbar))
|
rkey = (round(lbar), round(rbar))
|
||||||
|
|
||||||
|
do_print: bool = False
|
||||||
|
if use_caching:
|
||||||
cached_result = self._mxmns.get(rkey)
|
cached_result = self._mxmns.get(rkey)
|
||||||
do_print = False # (self.index_step() == 60)
|
|
||||||
if cached_result:
|
if cached_result:
|
||||||
if do_print:
|
if do_print:
|
||||||
print(
|
print(
|
||||||
|
@ -332,14 +340,15 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
stop_t=rbar,
|
stop_t=rbar,
|
||||||
step=self.index_step(),
|
step=self.index_step(),
|
||||||
)
|
)
|
||||||
slice_view = arr[read_slc]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ifirst = arr[0]['index']
|
ifirst = arr[0]['index']
|
||||||
slice_view = arr[
|
read_slc = slice(
|
||||||
lbar - ifirst:
|
lbar - ifirst,
|
||||||
(rbar - ifirst) + 1
|
(rbar - ifirst) + 1
|
||||||
]
|
)
|
||||||
|
|
||||||
|
slice_view = arr[read_slc]
|
||||||
|
|
||||||
if not slice_view.size:
|
if not slice_view.size:
|
||||||
log.warning(f'{self.name} no maxmin in view?')
|
log.warning(f'{self.name} no maxmin in view?')
|
||||||
|
@ -366,14 +375,13 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
mxmn = ylow, yhigh
|
mxmn = ylow, yhigh
|
||||||
if (
|
if (
|
||||||
do_print
|
do_print
|
||||||
# and self.index_step() > 1
|
|
||||||
):
|
):
|
||||||
s = 3
|
s = 3
|
||||||
print(
|
print(
|
||||||
f'{self.name} MANUAL ohlc={self.is_ohlc} maxmin:\n'
|
f'{self.name} MANUAL ohlc={self.is_ohlc} maxmin:\n'
|
||||||
f'{rkey} -> {mxmn}\n'
|
f'{rkey} -> {mxmn}\n'
|
||||||
f'read_slc: {read_slc}\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'first {s}:\n{slice_view[:s]}\n'
|
||||||
f'last {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
|
return graphics
|
||||||
|
|
||||||
should_redraw: bool = False
|
should_redraw: bool = False
|
||||||
ds_allowed: bool = True
|
ds_allowed: bool = True # guard for m4 activation
|
||||||
|
|
||||||
# TODO: probably specialize ``Renderer`` types instead of
|
# TODO: probably specialize ``Renderer`` types instead of
|
||||||
# these logic checks?
|
# these logic checks?
|
||||||
|
@ -624,7 +632,7 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
graphics,
|
graphics,
|
||||||
r,
|
r,
|
||||||
should_redraw,
|
should_redraw,
|
||||||
in_line,
|
ds_allowed, # in line mode?
|
||||||
) = render_baritems(
|
) = render_baritems(
|
||||||
self,
|
self,
|
||||||
graphics,
|
graphics,
|
||||||
|
@ -632,7 +640,6 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
profiler,
|
profiler,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
ds_allowed = in_line
|
|
||||||
|
|
||||||
elif not r:
|
elif not r:
|
||||||
if isinstance(graphics, StepCurve):
|
if isinstance(graphics, StepCurve):
|
||||||
|
@ -807,7 +814,7 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
# XXX: pretty sure we don't need this?
|
# XXX: pretty sure we don't need this?
|
||||||
# if isinstance(g, Curve):
|
# if isinstance(g, Curve):
|
||||||
# with dsg.reset_cache():
|
# with dsg.reset_cache():
|
||||||
uppx = self._last_uppx
|
uppx = round(self._last_uppx)
|
||||||
y = y[-uppx:]
|
y = y[-uppx:]
|
||||||
ymn, ymx = y.min(), y.max()
|
ymn, ymx = y.min(), y.max()
|
||||||
# print(f'drawing uppx={uppx} mxmn line: {ymn}, {ymx}')
|
# 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}')
|
# print(f'updating NOT DS curve {self.name}')
|
||||||
g.update()
|
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(
|
def default_view(
|
||||||
self,
|
self,
|
||||||
bars_from_y: int = int(616 * 3/8),
|
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
|
# l->r distance in scene units, no larger then data span
|
||||||
data_diff = last_datum - first_datum
|
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
|
# orient by offset from the y-axis including
|
||||||
# space to compensate for the L1 labels.
|
# space to compensate for the L1 labels.
|
||||||
if not y_offset:
|
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:
|
else:
|
||||||
offset = (y_offset * step) + uppx*step
|
offset = (y_offset * step) + uppx*step
|
||||||
|
|
||||||
# align right side of view to the rightmost datum + the selected
|
# align right side of view to the rightmost datum + the selected
|
||||||
# offset from above.
|
# 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:
|
# no data is in view so check for the only 2 sane cases:
|
||||||
# - entire view is LEFT of data
|
# - entire view is LEFT of data
|
||||||
|
@ -1054,3 +1062,22 @@ class Viz(msgspec.Struct): # , frozen=True):
|
||||||
do_rt_update,
|
do_rt_update,
|
||||||
should_tread,
|
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