Adjust OHLC bar x-offsets to be time span matched

Previously we were drawing with the middle of the bar on each index with
arms to either side: +/- some arm length. Instead this changes so that
each bar is drawn *after* each index/timestamp such that in graphics
coords the bar span more correctly matches the time span in the
x-domain. This makes the linked region between slow and fast chart
directly match (without any transform) for epoch-time indexing such that
the last x-coord in view on the fast chart is no more then the
next time step in (downsampled) slow view.

Deats:
- adjust in `._pathops.path_arrays_from_ohlc()` and take an `bar_w` bar
  width input (normally taken from the data step size).
- change `.ui._ohlc.bar_from_ohlc_row()` and
  `BarItems.draw_last_datum()` to match.
epoch_indexing_and_dataviz_layer
Tyler Goodlet 2022-12-16 12:40:32 -05:00
parent 0d0675ac7e
commit 444768d30f
2 changed files with 31 additions and 14 deletions

View File

@ -93,7 +93,8 @@ def xy_downsample(
def path_arrays_from_ohlc( def path_arrays_from_ohlc(
data: np.ndarray, data: np.ndarray,
start: int64, start: int64,
bar_gap: float64 = 0.43, bar_w: float64,
bar_gap: float64 = 0.16,
use_time_index: bool = True, use_time_index: bool = True,
# XXX: ``numba`` issue: https://github.com/numba/numba/issues/8622 # XXX: ``numba`` issue: https://github.com/numba/numba/issues/8622
@ -119,6 +120,8 @@ def path_arrays_from_ohlc(
) )
y, c = x.copy(), x.copy() y, c = x.copy(), x.copy()
half_w: float = bar_w/2
# TODO: report bug for assert @ # TODO: report bug for assert @
# /home/goodboy/repos/piker/env/lib/python3.8/site-packages/numba/core/typing/builtins.py:991 # /home/goodboy/repos/piker/env/lib/python3.8/site-packages/numba/core/typing/builtins.py:991
for i, q in enumerate(data[start:], start): for i, q in enumerate(data[start:], start):
@ -143,13 +146,14 @@ def path_arrays_from_ohlc(
istop = istart + 6 istop = istart + 6
# x,y detail the 6 points which connect all vertexes of a ohlc bar # x,y detail the 6 points which connect all vertexes of a ohlc bar
mid: float = index + half_w
x[istart:istop] = ( x[istart:istop] = (
index - bar_gap,
index,
index,
index,
index,
index + bar_gap, index + bar_gap,
mid,
mid,
mid,
mid,
index + bar_w - bar_gap,
) )
y[istart:istop] = ( y[istart:istop] = (
open, open,

View File

@ -51,7 +51,8 @@ log = get_logger(__name__)
def bar_from_ohlc_row( def bar_from_ohlc_row(
row: np.ndarray, row: np.ndarray,
# 0.5 is no overlap between arms, 1.0 is full overlap # 0.5 is no overlap between arms, 1.0 is full overlap
bar_gap: float = 0.43 bar_w: float,
bar_gap: float = 0.16
) -> tuple[QLineF]: ) -> tuple[QLineF]:
''' '''
@ -67,9 +68,11 @@ def bar_from_ohlc_row(
# history path faster since it's done in C++: # history path faster since it's done in C++:
# https://doc.qt.io/qt-5/qgraphicslineitem.html # https://doc.qt.io/qt-5/qgraphicslineitem.html
mid: float = (bar_w / 2) + index
# high -> low vertical (body) line # high -> low vertical (body) line
if low != high: if low != high:
hl = QLineF(index, low, index, high) hl = QLineF(mid, low, mid, high)
else: else:
# XXX: if we don't do it renders a weird rectangle? # XXX: if we don't do it renders a weird rectangle?
# see below for filtering this later... # see below for filtering this later...
@ -80,10 +83,13 @@ def bar_from_ohlc_row(
# the index's range according to the view mapping coordinates. # the index's range according to the view mapping coordinates.
# open line # open line
o = QLineF(index - bar_gap, open, index, open) o = QLineF(index + bar_gap, open, mid, open)
# close line # close line
c = QLineF(index, close, index + bar_gap, close) c = QLineF(
mid, close,
index + bar_w - bar_gap, close,
)
return [hl, o, c] return [hl, o, c]
@ -249,10 +255,11 @@ class BarItems(pg.GraphicsObject):
step_size = index[-1] - index[-2] step_size = index[-1] - index[-2]
# generate new lines objects for updatable "current bar" # generate new lines objects for updatable "current bar"
bg: float = 0.16 * step_size
self._last_bar_lines = bar_from_ohlc_row( self._last_bar_lines = bar_from_ohlc_row(
last_row, last_row,
bar_gap=step_size * 0.43 bar_w=step_size,
# fields, bar_gap=bg,
) )
# assert i == graphics.start_index - 1 # assert i == graphics.start_index - 1
@ -268,10 +275,16 @@ class BarItems(pg.GraphicsObject):
if l != h: # noqa if l != h: # noqa
if body is None: if body is None:
body = self._last_bar_lines[0] = QLineF(i, l, i, h) body = self._last_bar_lines[0] = QLineF(
i + bg, l,
i + step_size - bg, h,
)
else: else:
# update body # update body
body.setLine(i, l, i, h) body.setLine(
body.x1(), l,
body.x2(), h,
)
# XXX: pretty sure this is causing an issue where the # XXX: pretty sure this is causing an issue where the
# bar has a large upward move right before the next # bar has a large upward move right before the next