diff --git a/piker/ui/_graphics/_ohlc.py b/piker/ui/_graphics/_ohlc.py index 58a139ea..044ce679 100644 --- a/piker/ui/_graphics/_ohlc.py +++ b/piker/ui/_graphics/_ohlc.py @@ -21,7 +21,7 @@ from typing import List, Optional, Tuple import numpy as np import pyqtgraph as pg -from numba import jit, float64, int64 # , optional +from numba import njit, float64, int64 # , optional from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import QLineF, QPointF # from numba import types as ntypes @@ -46,10 +46,20 @@ def _mk_lines_array( ) -def lines_from_ohlc(row: np.ndarray, w: float) -> Tuple[QLineF]: +def lines_from_ohlc( + row: np.ndarray, + w: float +) -> Tuple[QLineF]: + open, high, low, close, index = row[ ['open', 'high', 'low', 'close', 'index']] + # TODO: maybe consider using `QGraphicsLineItem` ?? + # gives us a ``.boundingRect()`` on the objects which may make + # computing the composite bounding rect of the last bars + the + # history path faster since it's done in C++: + # https://doc.qt.io/qt-5/qgraphicslineitem.html + # high -> low vertical (body) line if low != high: hl = QLineF(index, low, index, high) @@ -60,17 +70,18 @@ def lines_from_ohlc(row: np.ndarray, w: float) -> Tuple[QLineF]: # NOTE: place the x-coord start as "middle" of the drawing range such # that the open arm line-graphic is at the left-most-side of - # the index's range according to the view mapping. + # the index's range according to the view mapping coordinates. # open line o = QLineF(index - w, open, index, open) + # close line c = QLineF(index, close, index + w, close) return [hl, o, c] -@jit( +@njit( # TODO: for now need to construct this manually for readonly arrays, see # https://github.com/numba/numba/issues/4511 # ntypes.Tuple((float64[:], float64[:], float64[:]))( @@ -78,7 +89,6 @@ def lines_from_ohlc(row: np.ndarray, w: float) -> Tuple[QLineF]: # int64, # optional(float64), # ), - nopython=True, nogil=True ) def path_arrays_from_ohlc( @@ -177,7 +187,7 @@ class BarItems(pg.GraphicsObject): # XXX: for the mega-lulz increasing width here increases draw latency... # so probably don't do it until we figure that out. - self.bars_pen = pg.mkPen(hcolor(pen_color)) + self.bars_pen = pg.mkPen(hcolor(pen_color), width=1) # NOTE: this prevents redraws on mouse interaction which is # a huge boon for avg interaction latency. @@ -314,15 +324,17 @@ class BarItems(pg.GraphicsObject): ['index', 'open', 'high', 'low', 'close', 'volume'] ] # assert i == self.start_index - 1 - assert i == last_index + # assert i == last_index body, larm, rarm = self._last_bar_lines # XXX: is there a faster way to modify this? rarm.setLine(rarm.x1(), last, rarm.x2(), last) + # writer is responsible for changing open on "first" volume of bar larm.setLine(larm.x1(), o, larm.x2(), o) if l != h: # noqa + if body is None: body = self._last_bar_lines[0] = QLineF(i, l, i, h) else: @@ -383,19 +395,29 @@ class BarItems(pg.GraphicsObject): # apparently this a lot faster says the docs? # https://doc.qt.io/qt-5/qpainterpath.html#controlPointRect hb = self.path.controlPointRect() - hb_size = hb.size() - # print(f'hb_size: {hb_size}') + hb_tl, hb_br = hb.topLeft(), hb.bottomRight() - w = hb_size.width() + 1 - h = hb_size.height() + 1 + # need to include last bar height or BR will be off + mx_y = hb_br.y() + mn_y = hb_tl.y() - br = QtCore.QRectF( + body_line = self._last_bar_lines[0] + if body_line: + mx_y = max(mx_y, max(body_line.y1(), body_line.y2())) + mn_y = min(mn_y, min(body_line.y1(), body_line.y2())) + + return QtCore.QRectF( # top left - QPointF(hb.topLeft()), + QPointF( + hb_tl.x(), + mn_y, + ), + + # bottom right + QPointF( + hb_br.x() + 1, + mx_y, + ) - # total size - QtCore.QSizeF(w, h) ) - # print(f'bounding rect: {br}') - return br