Factor all per graphic `.draw_last()` methods into closures

incremental_update_paths
Tyler Goodlet 2022-05-31 13:57:10 -04:00
parent 8f1faf97ee
commit 57acc3bd29
3 changed files with 133 additions and 97 deletions

View File

@ -160,23 +160,6 @@ class FastAppendCurve(pg.GraphicsObject):
QLineF(lbar, 0, rbar, 0) QLineF(lbar, 0, rbar, 0)
).length() ).length()
def draw_last(
self,
x: np.ndarray,
y: np.ndarray,
) -> None:
x_last = x[-1]
y_last = y[-1]
# draw the "current" step graphic segment so it lines up with
# the "middle" of the current (OHLC) sample.
self._last_line = QLineF(
x[-2], y[-2],
x_last, y_last
)
# self._last_w = x_last - x[-2]
# XXX: lol brutal, the internals of `CurvePoint` (inherited by # XXX: lol brutal, the internals of `CurvePoint` (inherited by
# our `LineDot`) required ``.getData()`` to work.. # our `LineDot`) required ``.getData()`` to work..
def getData(self): def getData(self):

View File

@ -23,7 +23,6 @@ incremental update.
''' '''
from __future__ import annotations from __future__ import annotations
from functools import partial
from typing import ( from typing import (
Optional, Optional,
Callable, Callable,
@ -58,6 +57,7 @@ from ._pathops import (
) )
from ._ohlc import ( from ._ohlc import (
BarItems, BarItems,
bar_from_ohlc_row,
) )
from ._curve import ( from ._curve import (
FastAppendCurve, FastAppendCurve,
@ -245,18 +245,73 @@ def render_baritems(
bars.update() bars.update()
draw_last = False draw_last = False
lasts = self.shm.array[-2:]
last = lasts[-1]
if should_line: if should_line:
def draw_last():
def draw_last_flattened_ohlc_line(
graphics: pg.GraphicsObject,
path: QPainterPath,
src_data: np.ndarray,
render_data: np.ndarray,
reset: bool,
) -> None:
lasts = src_data[-2:]
x, y = lasts['index'], lasts['close'] x, y = lasts['index'], lasts['close']
curve.draw_last(x, y)
# draw the "current" step graphic segment so it
# lines up with the "middle" of the current
# (OHLC) sample.
graphics._last_line = QLineF(
x[-2], y[-2],
x[-1], y[-1]
)
draw_last = draw_last_flattened_ohlc_line
else: else:
draw_last = partial( def draw_last_ohlc_bar(
bars.draw_last, graphics: pg.GraphicsObject,
last, path: QPainterPath,
) src_data: np.ndarray,
render_data: np.ndarray,
reset: bool,
) -> None:
last = src_data[-1]
# generate new lines objects for updatable "current bar"
graphics._last_bar_lines = bar_from_ohlc_row(last, graphics.w)
# last bar update
i, o, h, l, last, v = last[
['index', 'open', 'high', 'low', 'close', 'volume']
]
# assert i == graphics.start_index - 1
# assert i == last_index
body, larm, rarm = graphics._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 = graphics._last_bar_lines[0] = QLineF(i, l, i, h)
else:
# update body
body.setLine(i, l, i, h)
# XXX: pretty sure this is causing an issue where the
# bar has a large upward move right before the next
# sample and the body is getting set to None since the
# next bar is flat but the shm array index update wasn't
# read by the time this code runs. Iow we're doing this
# removal of the body for a bar index that is now out of
# date / from some previous sample. It's weird though
# because i've seen it do this to bars i - 3 back?
draw_last = draw_last_ohlc_bar
return ( return (
graphics, graphics,
@ -355,6 +410,12 @@ class Flow(msgspec.Struct): # , frozen=True):
graphics: pg.GraphicsObject graphics: pg.GraphicsObject
_shm: ShmArray _shm: ShmArray
draw_last_datum: Optional[
Callable[
[np.ndarray, str],
tuple[np.ndarray]
]
] = None
is_ohlc: bool = False is_ohlc: bool = False
render: bool = True # toggle for display loop render: bool = True # toggle for display loop
@ -543,7 +604,7 @@ class Flow(msgspec.Struct): # , frozen=True):
) )
# shm read and slice to view # shm read and slice to view
read = ( read = (
xfirst, xlast, array, xfirst, xlast, src_array,
ivl, ivr, in_view, ivl, ivr, in_view,
) = self.read() ) = self.read()
@ -618,14 +679,6 @@ class Flow(msgspec.Struct): # , frozen=True):
# corrent yet for step curves.. remove this to see it. # corrent yet for step curves.. remove this to see it.
should_redraw = True should_redraw = True
# TODO: remove this and instead place all step curve
# updating into pre-path data render callbacks.
# full input data
x = array['index']
y = array[array_key]
x_last = x[-1]
y_last = y[-1]
draw_last = True draw_last = True
# downsampling incremental state checking # downsampling incremental state checking
@ -698,34 +751,74 @@ class Flow(msgspec.Struct): # , frozen=True):
graphics.fast_path = r.fast_path graphics.fast_path = r.fast_path
if draw_last and not bars: if draw_last and not bars:
# default line draw last call
if not step_mode: if not step_mode:
with graphics.reset_cache():
x = data['index'] def draw_last_line(
y = data[array_key] graphics: pg.GraphicsObject,
graphics.draw_last(x, y) path: QPainterPath,
src_data: np.ndarray,
render_data: np.ndarray,
reset: bool,
) -> None:
# default line draw last call
with graphics.reset_cache():
x = render_data['index']
y = render_data[array_key]
x_last = x[-1]
y_last = y[-1]
# draw the "current" step graphic segment so it
# lines up with the "middle" of the current
# (OHLC) sample.
graphics._last_line = QLineF(
x[-2], y[-2],
x_last, y_last
)
draw_last_line(graphics, path, src_array, data, reset)
else: else:
w = 0.5
# lol, commenting this makes step curves
# all "black" for me :eyeroll:..
graphics._last_line = QLineF(
x_last - w, 0,
x_last + w, 0,
)
graphics._last_step_rect = QRectF(
x_last - w, 0,
x_last + w, y_last,
)
# TODO: does this actuallly help us in any way (prolly should def draw_last_step(
# look at the source / ask ogi). I think it avoid artifacts on graphics: pg.GraphicsObject,
# wheel-scroll downsampling curve updates? path: QPainterPath,
graphics.update() src_data: np.ndarray,
profiler('.prepareGeometryChange()') render_data: np.ndarray,
reset: bool,
) -> None:
w = 0.5
# TODO: remove this and instead place all step curve
# updating into pre-path data render callbacks.
# full input data
x = src_array['index']
y = src_array[array_key]
x_last = x[-1]
y_last = y[-1]
# lol, commenting this makes step curves
# all "black" for me :eyeroll:..
graphics._last_line = QLineF(
x_last - w, 0,
x_last + w, 0,
)
graphics._last_step_rect = QRectF(
x_last - w, 0,
x_last + w, y_last,
)
draw_last_step(graphics, path, src_array, data, reset)
# TODO: does this actuallly help us in any way (prolly should
# look at the source / ask ogi). I think it avoid artifacts on
# wheel-scroll downsampling curve updates?
graphics.update()
profiler('.prepareGeometryChange()')
elif bars and draw_last: elif bars and draw_last:
draw_last() draw_last(graphics, path, src_array, data, reset)
graphics.update() graphics.update()
profiler('.update()') profiler('.update()')

View File

@ -32,8 +32,6 @@ from .._profile import pg_profile_enabled, ms_slower_then
from ._style import hcolor from ._style import hcolor
from ..log import get_logger from ..log import get_logger
from ._curve import FastAppendCurve from ._curve import FastAppendCurve
from ._compression import ohlc_flatten
from ._pathops import gen_ohlc_qpath
if TYPE_CHECKING: if TYPE_CHECKING:
from ._chart import LinkedSplits from ._chart import LinkedSplits
@ -148,44 +146,6 @@ class BarItems(pg.GraphicsObject):
else: else:
return 0 return 0
def draw_last(
self,
last: np.ndarray,
) -> None:
# generate new lines objects for updatable "current bar"
self._last_bar_lines = bar_from_ohlc_row(last, self.w)
# last bar update
i, o, h, l, last, v = last[
['index', 'open', 'high', 'low', 'close', 'volume']
]
# assert i == self.start_index - 1
# 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:
# update body
body.setLine(i, l, i, h)
# XXX: pretty sure this is causing an issue where the bar has
# a large upward move right before the next sample and the body
# is getting set to None since the next bar is flat but the shm
# array index update wasn't read by the time this code runs. Iow
# we're doing this removal of the body for a bar index that is
# now out of date / from some previous sample. It's weird
# though because i've seen it do this to bars i - 3 back?
def boundingRect(self): def boundingRect(self):
# Qt docs: https://doc.qt.io/qt-5/qgraphicsitem.html#boundingRect # Qt docs: https://doc.qt.io/qt-5/qgraphicsitem.html#boundingRect