Attempt to make `.default_view()` time-index ready

As in make the call to `Flume.slice_from_time()` to try and convert any
time index values from the view range to array-indices; all untested
atm.

Also drop some old/unused/moved methods:
- `._set_xlimits()`
- `.bars_range()`
- `.curve_width_pxs()`

and fix some `flow` -> `viz` var naming.
multichartz
Tyler Goodlet 2022-11-29 10:56:17 -05:00
parent 6252469ecc
commit 99311b4f46
1 changed files with 75 additions and 105 deletions

View File

@ -60,7 +60,7 @@ from ._style import (
hcolor, hcolor,
CHART_MARGINS, CHART_MARGINS,
_xaxis_at, _xaxis_at,
_min_points_to_show, # _min_points_to_show,
) )
from ..data.feed import ( from ..data.feed import (
Feed, Feed,
@ -810,6 +810,8 @@ class LinkedSplits(QWidget):
self.chart.sidepane.setMinimumWidth(sp_w) self.chart.sidepane.setMinimumWidth(sp_w)
# TODO: we should really drop using this type and instead just
# write our own wrapper around `PlotItem`..
class ChartPlotWidget(pg.PlotWidget): class ChartPlotWidget(pg.PlotWidget):
''' '''
``GraphicsView`` subtype containing a single ``PlotItem``. ``GraphicsView`` subtype containing a single ``PlotItem``.
@ -921,7 +923,7 @@ class ChartPlotWidget(pg.PlotWidget):
# show background grid # show background grid
self.showGrid(x=False, y=True, alpha=0.3) self.showGrid(x=False, y=True, alpha=0.3)
self.cv.enable_auto_yrange() # self.cv.enable_auto_yrange()
self.pi_overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem) self.pi_overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem)
@ -951,41 +953,10 @@ class ChartPlotWidget(pg.PlotWidget):
def focus(self) -> None: def focus(self) -> None:
self.view.setFocus() self.view.setFocus()
def _set_xlimits(
self,
xfirst: int,
xlast: int
) -> None:
"""Set view limits (what's shown in the main chart "pane")
based on max/min x/y coords.
"""
self.setLimits(
xMin=xfirst,
xMax=xlast,
minXRange=_min_points_to_show,
)
def view_range(self) -> tuple[int, int]: def view_range(self) -> tuple[int, int]:
vr = self.viewRect() vr = self.viewRect()
return int(vr.left()), int(vr.right()) return int(vr.left()), int(vr.right())
def bars_range(self) -> tuple[int, int, int, int]:
'''
Return a range tuple for the bars present in view.
'''
main_flow = self._vizs[self.name]
ifirst, l, lbar, rbar, r, ilast = main_flow.datums_range()
return l, lbar, rbar, r
def curve_width_pxs(
self,
) -> float:
_, lbar, rbar, _ = self.bars_range()
return self.view.mapViewToDevice(
QLineF(lbar, 0, rbar, 0)
).length()
def pre_l1_xs(self) -> tuple[float, float]: def pre_l1_xs(self) -> tuple[float, float]:
''' '''
Return the view x-coord for the value just before Return the view x-coord for the value just before
@ -1038,59 +1009,88 @@ class ChartPlotWidget(pg.PlotWidget):
Set the view box to the "default" startup view of the scene. Set the view box to the "default" startup view of the scene.
''' '''
flow = self._vizs.get(self.name) viz = self.get_viz(self.name)
if not flow: if not viz:
log.warning(f'`Viz` for {self.name} not loaded yet?') log.warning(f'`Viz` for {self.name} not loaded yet?')
return return
arr = flow.shm.array (
index = arr['index'] _,
# times = arr['time'] l,
datum_start,
datum_stop,
r,
_,
) = viz.datums_range()
# these will be epoch time floats array = viz.shm.array
xfirst, xlast = index[0], index[-1] index_field = viz.index_field
l, lbar, rbar, r = self.bars_range()
view = self.view if index_field == 'time':
vr = viz.plot.viewRect()
(
abs_slc,
read_slc,
mask,
) = viz.flume.slice_from_time(
array,
start_t=vr.left(),
stop_t=vr.right(),
)
iv_arr = array[mask]
index = iv_arr['index']
else:
index = array['index']
# these must be array-index-ints (hence the slice from time
# above).
x_start, x_stop = index[0], index[-1]
view: ChartView = viz.plot.vb
if ( if (
rbar < 0 datum_stop < 0
or l < xfirst or l < x_start
or l < 0 or l < 0
or (rbar - lbar) < 6 or (datum_stop - datum_start) < 6
): ):
# TODO: set fixed bars count on screen that approx includes as begin = x_stop - bars_from_y
# many bars as possible before a downsample line is shown.
begin = xlast - bars_from_y
view.setXRange( view.setXRange(
min=begin, min=begin,
max=xlast, max=x_stop,
padding=0, padding=0,
) )
# re-get range # re-get range
l, lbar, rbar, r = self.bars_range() l, datum_start, datum_stop, r = viz.bars_range()
# we get the L1 spread label "length" in view coords # we get the L1 spread label "length" in view coords
# terms now that we've scaled either by user control # terms now that we've scaled either by user control
# or to the default set of bars as per the immediate block # or to the default set of bars as per the immediate block
# above. # above.
debug_msg = (
f'x_stop: {x_stop}\n'
)
if not y_offset: if not y_offset:
marker_pos, l1_len = self.pre_l1_xs() marker_pos, l1_len = self.pre_l1_xs()
end = xlast + l1_len + 1 end = x_stop + l1_len + 1
debug_msg += (
f'marker pos: {marker_pos}\n'
f'l1 len: {l1_len}\n'
)
else: else:
end = xlast + y_offset + 1 end = x_stop + y_offset + 1
begin = end - (r - l) begin = end - (r - l)
# for debugging debug_msg += (
# print( f'end: {end}\n'
# # f'bars range: {brange}\n' f'begin: {begin}\n'
# f'xlast: {xlast}\n' )
# f'marker pos: {marker_pos}\n' print(debug_msg)
# f'l1 len: {l1_len}\n'
# f'begin: {begin}\n'
# f'end: {end}\n'
# )
# remove any custom user yrange setttings # remove any custom user yrange setttings
if self._static_yrange == 'axis': if self._static_yrange == 'axis':
@ -1254,17 +1254,17 @@ class ChartPlotWidget(pg.PlotWidget):
**graphics_kwargs, **graphics_kwargs,
) )
flow = self._vizs[data_key] = Viz( viz = self._vizs[data_key] = Viz(
data_key, data_key,
pi, pi,
shm, shm,
flume, flume,
is_ohlc=is_ohlc, is_ohlc=is_ohlc,
# register curve graphics with this flow # register curve graphics with this viz
graphics=graphics, graphics=graphics,
) )
assert isinstance(flow.shm, ShmArray) assert isinstance(viz.shm, ShmArray)
# TODO: this probably needs its own method? # TODO: this probably needs its own method?
if overlay: if overlay:
@ -1321,7 +1321,7 @@ class ChartPlotWidget(pg.PlotWidget):
# understand. # understand.
pi.addItem(graphics) pi.addItem(graphics)
return flow return viz
def draw_ohlc( def draw_ohlc(
self, self,
@ -1364,35 +1364,6 @@ class ChartPlotWidget(pg.PlotWidget):
**kwargs, **kwargs,
) )
# def _label_h(self, yhigh: float, ylow: float) -> float:
# # compute contents label "height" in view terms
# # to avoid having data "contents" overlap with them
# if self._labels:
# label = self._labels[self.name][0]
# rect = label.itemRect()
# tl, br = rect.topLeft(), rect.bottomRight()
# vb = self.plotItem.vb
# try:
# # on startup labels might not yet be rendered
# top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y())
# # XXX: magic hack, how do we compute exactly?
# label_h = (top - bottom) * 0.42
# except np.linalg.LinAlgError:
# label_h = 0
# else:
# label_h = 0
# # print(f'label height {self.name}: {label_h}')
# if label_h > yhigh - ylow:
# label_h = 0
# print(f"bounds (ylow, yhigh): {(ylow, yhigh)}")
# TODO: pretty sure we can just call the cursor # TODO: pretty sure we can just call the cursor
# directly not? i don't wee why we need special "signal proxies" # directly not? i don't wee why we need special "signal proxies"
# for this lul.. # for this lul..
@ -1429,23 +1400,22 @@ class ChartPlotWidget(pg.PlotWidget):
# TODO: here we should instead look up the ``Viz.shm.array`` # TODO: here we should instead look up the ``Viz.shm.array``
# and read directly from shm to avoid copying to memory first # and read directly from shm to avoid copying to memory first
# and then reading it again here. # and then reading it again here.
flow_key = name or self.name viz_key = name or self.name
viz = self._vizs.get(flow_key) viz = self._vizs.get(viz_key)
if ( if viz is None:
viz is None log.error(f"viz {viz_key} doesn't exist in chart {self.name} !?")
):
log.error(f"viz {flow_key} doesn't exist in chart {self.name} !?")
key = res = 0, 0 key = res = 0, 0
else: else:
( (
first, _,
l, l,
lbar, lbar,
rbar, rbar,
r, r,
last, _,
) = bars_range or viz.datums_range() ) = bars_range or viz.datums_range()
profiler(f'{self.name} got bars range') profiler(f'{self.name} got bars range')
key = round(lbar), round(rbar) key = round(lbar), round(rbar)
@ -1455,7 +1425,7 @@ class ChartPlotWidget(pg.PlotWidget):
res is None res is None
): ):
log.warning( log.warning(
f"{flow_key} no mxmn for bars_range => {key} !?" f"{viz_key} no mxmn for bars_range => {key} !?"
) )
res = 0, 0 res = 0, 0
if not self._on_screen: if not self._on_screen:
@ -1463,11 +1433,11 @@ class ChartPlotWidget(pg.PlotWidget):
self._on_screen = True self._on_screen = True
profiler(f'yrange mxmn: {key} -> {res}') profiler(f'yrange mxmn: {key} -> {res}')
# print(f'{flow_key} yrange mxmn: {key} -> {res}') # print(f'{viz_key} yrange mxmn: {key} -> {res}')
return res return res
def get_viz( def get_viz(
self, self,
key: str, key: str,
) -> Viz: ) -> Viz:
return self._vizs[key] return self._vizs.get(key)