diff --git a/piker/ui/_curve.py b/piker/ui/_curve.py index 548eaac5..def90be8 100644 --- a/piker/ui/_curve.py +++ b/piker/ui/_curve.py @@ -28,10 +28,7 @@ from PyQt5.QtWidgets import QGraphicsItem from PyQt5.QtCore import ( Qt, QLineF, - QSizeF, QRectF, - # QRect, - QPointF, ) from PyQt5.QtGui import ( QPainter, @@ -89,9 +86,9 @@ class Curve(pg.GraphicsObject): ''' # sub-type customization methods - sub_br: Optional[Callable] = None - sub_paint: Optional[Callable] = None declare_paintables: Optional[Callable] = None + sub_paint: Optional[Callable] = None + # sub_br: Optional[Callable] = None def __init__( self, @@ -140,9 +137,7 @@ class Curve(pg.GraphicsObject): # self.last_step_pen = pg.mkPen(hcolor(color), width=2) self.last_step_pen = pg.mkPen(pen, width=2) - # self._last_line: Optional[QLineF] = None self._last_line = QLineF() - self._last_w: float = 1 # flat-top style histogram-like discrete curve # self._step_mode: bool = step_mode @@ -231,8 +226,8 @@ class Curve(pg.GraphicsObject): self.path.clear() if self.fast_path: - # self.fast_path.clear() - self.fast_path = None + self.fast_path.clear() + # self.fast_path = None @cm def reset_cache(self) -> None: @@ -252,77 +247,81 @@ class Curve(pg.GraphicsObject): self.boundingRect = self._path_br return self._path_br() + # Qt docs: https://doc.qt.io/qt-5/qgraphicsitem.html#boundingRect def _path_br(self): ''' Post init ``.boundingRect()```. ''' - # hb = self.path.boundingRect() - hb = self.path.controlPointRect() - hb_size = hb.size() - - fp = self.fast_path - if fp: - fhb = fp.controlPointRect() - hb_size = fhb.size() + hb_size - - # print(f'hb_size: {hb_size}') - - # if self._last_step_rect: - # hb_size += self._last_step_rect.size() - - # if self._line: - # br = self._last_step_rect.bottomRight() - - # tl = QPointF( - # # self._vr[0], - # # hb.topLeft().y(), - # # 0, - # # hb_size.height() + 1 - # ) - - # br = self._last_step_rect.bottomRight() - - w = hb_size.width() - h = hb_size.height() - - sbr = self.sub_br - if sbr: - w, h = self.sub_br(w, h) - else: - # assume plain line graphic and use - # default unit step in each direction. - - # only on a plane line do we include - # and extra index step's worth of width - # since in the step case the end of the curve - # actually terminates earlier so we don't need - # this for the last step. - w += self._last_w - # ll = self._last_line - h += 1 # ll.y2() - ll.y1() - - # br = QPointF( - # self._vr[-1], - # # tl.x() + w, - # tl.y() + h, - # ) - - br = QRectF( - - # top left - # hb.topLeft() - # tl, - QPointF(hb.topLeft()), - - # br, - # total size - # QSizeF(hb_size) - # hb_size, - QSizeF(w, h) + profiler = Profiler( + msg=f'Curve.boundingRect(): `{self._name}`', + disabled=not pg_profile_enabled(), + ms_threshold=ms_slower_then, + ) + pr = self.path.controlPointRect() + hb_tl, hb_br = ( + pr.topLeft(), + pr.bottomRight(), + ) + mn_y = hb_tl.y() + mx_y = hb_br.y() + most_left = hb_tl.x() + most_right = hb_br.x() + profiler('calc path vertices') + + # TODO: if/when we get fast path appends working in the + # `Renderer`, then we might need to actually use this.. + # fp = self.fast_path + # if fp: + # fhb = fp.controlPointRect() + # # hb_size = fhb.size() + hb_size + # br = pr.united(fhb) + + # XXX: *was* a way to allow sub-types to extend the + # boundingrect calc, but in the one use case for a step curve + # doesn't seem like we need it as long as the last line segment + # is drawn as it is? + + # sbr = self.sub_br + # if sbr: + # # w, h = self.sub_br(w, h) + # sub_br = sbr() + # br = br.united(sub_br) + + # assume plain line graphic and use + # default unit step in each direction. + ll = self._last_line + y1, y2 = ll.y1(), ll.y2() + x1, x2 = ll.x1(), ll.x2() + + ymn = min(y1, y2, mn_y) + ymx = max(y1, y2, mx_y) + most_left = min(x1, x2, most_left) + most_right = max(x1, x2, most_right) + + profiler('calc last line vertices') + # ll_br = QRectF( + # x1, + # ymn, + # # NOTE: a legacy snippet, not sure if it still applies? + # # only on a plane line do we include + # # and extra index step's worth of width + # # since in the step case the end of the curve + # # actually terminates earlier so we don't need + # # this for the last step. + # x2 - x1 + 1, + # ymx, + # ) + # br = br.united(ll_br) + # profiler('calc united rects') + # return br + + return QRectF( + most_left, + ymn, + most_right - most_left + 1, + ymx, ) - # print(f'bounding rect: {br}') - return br def paint( self, @@ -359,6 +358,7 @@ class Curve(pg.GraphicsObject): fp = self.fast_path if fp: + # print("DRAWING PATH") p.drawPath(fp) profiler('.drawPath(fast_path)') @@ -450,17 +450,20 @@ class StepCurve(Curve): y = src_data[array_key] x_last = x[-1] + x_2last = x[-2] y_last = y[-1] + step_size = x_last - x_2last + half_step = step_size / 2 # lol, commenting this makes step curves # all "black" for me :eyeroll:.. self._last_line = QLineF( - x_last - w, 0, - x_last + w, 0, + x_2last, 0, + x_last, 0, ) self._last_step_rect = QRectF( - x_last - w, 0, - x_last + w, y_last, + x_last - half_step, 0, + step_size, y_last, ) return x, y @@ -475,11 +478,8 @@ class StepCurve(Curve): p.fillRect(self._last_step_rect, self._brush) profiler('.fillRect()') - def sub_br( - self, - path_w: float, - path_h: float, - - ) -> (float, float): - # passthrough - return path_w, path_h + # def sub_br( + # self, + # parent_br: QRectF | None = None, + # ) -> QRectF: + # return self._last_step_rect diff --git a/piker/ui/_ohlc.py b/piker/ui/_ohlc.py index 048861d0..88240b21 100644 --- a/piker/ui/_ohlc.py +++ b/piker/ui/_ohlc.py @@ -25,8 +25,15 @@ from typing import ( import numpy as np import pyqtgraph as pg -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtCore import QLineF, QPointF +from PyQt5 import ( + QtGui, + QtWidgets, +) +from PyQt5.QtCore import ( + QLineF, + QRectF, +) + from PyQt5.QtGui import QPainterPath from .._profile import pg_profile_enabled, ms_slower_then @@ -114,8 +121,13 @@ class BarItems(pg.GraphicsObject): # we expect the downsample curve report this. return 0 + # Qt docs: https://doc.qt.io/qt-5/qgraphicsitem.html#boundingRect def boundingRect(self): - # Qt docs: https://doc.qt.io/qt-5/qgraphicsitem.html#boundingRect + profiler = Profiler( + msg=f'BarItems.boundingRect(): `{self._name}`', + disabled=not pg_profile_enabled(), + ms_threshold=ms_slower_then, + ) # TODO: Can we do rect caching to make this faster # like `pg.PlotCurveItem` does? In theory it's just @@ -135,32 +147,53 @@ class BarItems(pg.GraphicsObject): hb.topLeft(), hb.bottomRight(), ) + mn_y = hb_tl.y() + mx_y = hb_br.y() + most_left = hb_tl.x() + most_right = hb_br.x() + profiler('calc path vertices') # need to include last bar height or BR will be off - mx_y = hb_br.y() - mn_y = hb_tl.y() - - last_lines = self._last_bar_lines + # OHLC line segments: [hl, o, c] + last_lines: tuple[QLineF] | None = self._last_bar_lines if last_lines: - 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())) + ( + hl, + o, + c, + ) = last_lines + most_right = c.x2() + 1 + ymx = ymn = c.y2() - return QtCore.QRectF( + if hl: + y1, y2 = hl.y1(), hl.y2() + ymn = min(y1, y2) + ymx = max(y1, y2) + mx_y = max(ymx, mx_y) + mn_y = min(ymn, mn_y) - # top left - QPointF( - hb_tl.x(), - mn_y, - ), - - # bottom right - QPointF( - hb_br.x() + 1, - mx_y, - ) + profiler('calc last bar vertices') + # TODO: see if this br uniting works faster? + # last_bar_rect = QRectF( + # o.x1(), + # ymn, + # c.x2() - o.x1() + 1, + # ymx, + # ) + # tot_br = hb.united(last_bar_rect) + # print( + # f'last datum bar br: {last_bar_rect}\n' + # f'path br: {hb}\n' + # f'sum br: {tot_br}\n' + # ) + # profiler('calc united rects') + # return tot_br + return QRectF( + most_left, + mn_y, + most_right - most_left + 1, + mx_y - mn_y, ) def paint( @@ -213,11 +246,15 @@ class BarItems(pg.GraphicsObject): # relevant fields ohlc = src_data[fields] - last_row = ohlc[-1:] + # last_row = ohlc[-1:] # individual values last_row = i, o, h, l, last = ohlc[-1] + # times = src_data['time'] + # if times[-1] - times[-2]: + # breakpoint() + # generate new lines objects for updatable "current bar" self._last_bar_lines = bar_from_ohlc_row(last_row) @@ -248,4 +285,5 @@ class BarItems(pg.GraphicsObject): # date / from some previous sample. It's weird though # because i've seen it do this to bars i - 3 back? + # return ohlc['time'], ohlc['close'] return ohlc['index'], ohlc['close']