From 444768d30f72c2893f107a85aaab0c1b970d5374 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 16 Dec 2022 12:40:32 -0500 Subject: [PATCH] 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. --- piker/data/_pathops.py | 16 ++++++++++------ piker/ui/_ohlc.py | 29 +++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/piker/data/_pathops.py b/piker/data/_pathops.py index 3dee38b2..aa6d628d 100644 --- a/piker/data/_pathops.py +++ b/piker/data/_pathops.py @@ -93,7 +93,8 @@ def xy_downsample( def path_arrays_from_ohlc( data: np.ndarray, start: int64, - bar_gap: float64 = 0.43, + bar_w: float64, + bar_gap: float64 = 0.16, use_time_index: bool = True, # 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() + half_w: float = bar_w/2 + # TODO: report bug for assert @ # /home/goodboy/repos/piker/env/lib/python3.8/site-packages/numba/core/typing/builtins.py:991 for i, q in enumerate(data[start:], start): @@ -143,13 +146,14 @@ def path_arrays_from_ohlc( istop = istart + 6 # x,y detail the 6 points which connect all vertexes of a ohlc bar + mid: float = index + half_w x[istart:istop] = ( - index - bar_gap, - index, - index, - index, - index, index + bar_gap, + mid, + mid, + mid, + mid, + index + bar_w - bar_gap, ) y[istart:istop] = ( open, diff --git a/piker/ui/_ohlc.py b/piker/ui/_ohlc.py index d935bd5c..f717b1a5 100644 --- a/piker/ui/_ohlc.py +++ b/piker/ui/_ohlc.py @@ -51,7 +51,8 @@ log = get_logger(__name__) def bar_from_ohlc_row( row: np.ndarray, # 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]: ''' @@ -67,9 +68,11 @@ def bar_from_ohlc_row( # history path faster since it's done in C++: # https://doc.qt.io/qt-5/qgraphicslineitem.html + mid: float = (bar_w / 2) + index + # high -> low vertical (body) line if low != high: - hl = QLineF(index, low, index, high) + hl = QLineF(mid, low, mid, high) else: # XXX: if we don't do it renders a weird rectangle? # 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. # open line - o = QLineF(index - bar_gap, open, index, open) + o = QLineF(index + bar_gap, open, mid, open) # close line - c = QLineF(index, close, index + bar_gap, close) + c = QLineF( + mid, close, + index + bar_w - bar_gap, close, + ) return [hl, o, c] @@ -249,10 +255,11 @@ class BarItems(pg.GraphicsObject): step_size = index[-1] - index[-2] # generate new lines objects for updatable "current bar" + bg: float = 0.16 * step_size self._last_bar_lines = bar_from_ohlc_row( last_row, - bar_gap=step_size * 0.43 - # fields, + bar_w=step_size, + bar_gap=bg, ) # assert i == graphics.start_index - 1 @@ -268,10 +275,16 @@ class BarItems(pg.GraphicsObject): if l != h: # noqa 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: # 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 # bar has a large upward move right before the next