From eda7b7f3c78cb7904d61434166d96a411dc3c353 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Wed, 30 Nov 2022 18:54:42 -0500 Subject: [PATCH] Move qpath-ops routines back to separate mod --- piker/data/_formatters.py | 138 +-------------------------------- piker/data/_pathops.py | 155 ++++++++++++++++++++++++++++++++++++++ piker/ui/_render.py | 2 +- 3 files changed, 159 insertions(+), 136 deletions(-) create mode 100644 piker/data/_pathops.py diff --git a/piker/data/_formatters.py b/piker/data/_formatters.py index 00719555..913831b6 100644 --- a/piker/data/_formatters.py +++ b/piker/data/_formatters.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . """ -Super fast ``QPainterPath`` generation related operator routines. +Pre-(path)-graphics formatted x/y nd/1d rendering subsystem. """ from __future__ import annotations @@ -26,20 +26,12 @@ from typing import ( import msgspec import numpy as np from numpy.lib import recfunctions as rfn -from numba import ( - # types, - njit, - float64, - int64, - # optional, -) from ._sharedmem import ( ShmArray, ) -# from ._source import numba_ohlc_dtype -from ._compression import ( - ds_m4, +from ._pathops import ( + path_arrays_from_ohlc, ) if TYPE_CHECKING: @@ -49,129 +41,6 @@ if TYPE_CHECKING: from .._profile import Profiler -def xy_downsample( - x, - y, - uppx, - - x_spacer: float = 0.5, - -) -> tuple[ - np.ndarray, - np.ndarray, - float, - float, -]: - ''' - Downsample 1D (flat ``numpy.ndarray``) arrays using M4 given an input - ``uppx`` (units-per-pixel) and add space between discreet datums. - - ''' - # downsample whenever more then 1 pixels per datum can be shown. - # always refresh data bounds until we get diffing - # working properly, see above.. - bins, x, y, ymn, ymx = ds_m4( - x, - y, - uppx, - ) - - # flatten output to 1d arrays suitable for path-graphics generation. - x = np.broadcast_to(x[:, None], y.shape) - x = (x + np.array( - [-x_spacer, 0, 0, x_spacer] - )).flatten() - y = y.flatten() - - return x, y, ymn, ymx - - -@njit( - # NOTE: need to construct this manually for readonly - # arrays, see https://github.com/numba/numba/issues/4511 - # ( - # types.Array( - # numba_ohlc_dtype, - # 1, - # 'C', - # readonly=True, - # ), - # int64, - # types.unicode_type, - # optional(float64), - # ), - nogil=True -) -def path_arrays_from_ohlc( - data: np.ndarray, - start: int64, - bar_gap: float64 = 0.43, - # index_field: str, - -) -> tuple[ - np.ndarray, - np.ndarray, - np.ndarray, -]: - ''' - Generate an array of lines objects from input ohlc data. - - ''' - size = int(data.shape[0] * 6) - - # XXX: see this for why the dtype might have to be defined outside - # the routine. - # https://github.com/numba/numba/issues/4098#issuecomment-493914533 - x = np.zeros( - shape=size, - dtype=float64, - ) - y, c = x.copy(), x.copy() - - # 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): - - # TODO: ask numba why this doesn't work.. - # open, high, low, close, index = q[ - # ['open', 'high', 'low', 'close', 'index']] - - open = q['open'] - high = q['high'] - low = q['low'] - close = q['close'] - # index = float64(q[index_field]) - index = float64(q['index']) - - istart = i * 6 - istop = istart + 6 - - # x,y detail the 6 points which connect all vertexes of a ohlc bar - x[istart:istop] = ( - index - bar_gap, - index, - index, - index, - index, - index + bar_gap, - ) - y[istart:istop] = ( - open, - open, - low, - high, - close, - close, - ) - - # specifies that the first edge is never connected to the - # prior bars last edge thus providing a small "gap"/"space" - # between bars determined by ``bar_gap``. - c[istart:istop] = (1, 1, 1, 1, 1, 0) - - return x, y, c - - class IncrementalFormatter(msgspec.Struct): ''' Incrementally updating, pre-path-graphics tracking, formatter. @@ -652,7 +521,6 @@ class OHLCBarsFmtr(IncrementalFormatter): new_y_nd.shape, ) + np.array([-0.5, 0, 0, 0.5]) - # TODO: can we drop this frame and just use the above? def format_xy_nd_to_1d( self, diff --git a/piker/data/_pathops.py b/piker/data/_pathops.py new file mode 100644 index 00000000..b2026f17 --- /dev/null +++ b/piker/data/_pathops.py @@ -0,0 +1,155 @@ +# piker: trading gear for hackers +# Copyright (C) 2018-present Tyler Goodlet (in stewardship of piker0) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +""" +Super fast ``QPainterPath`` generation related operator routines. + +""" +import numpy as np +from numba import ( + # types, + njit, + float64, + int64, + # optional, +) + +# from ._source import numba_ohlc_dtype +from ._compression import ( + ds_m4, +) + + +def xy_downsample( + x, + y, + uppx, + + x_spacer: float = 0.5, + +) -> tuple[ + np.ndarray, + np.ndarray, + float, + float, +]: + ''' + Downsample 1D (flat ``numpy.ndarray``) arrays using M4 given an input + ``uppx`` (units-per-pixel) and add space between discreet datums. + + ''' + # downsample whenever more then 1 pixels per datum can be shown. + # always refresh data bounds until we get diffing + # working properly, see above.. + bins, x, y, ymn, ymx = ds_m4( + x, + y, + uppx, + ) + + # flatten output to 1d arrays suitable for path-graphics generation. + x = np.broadcast_to(x[:, None], y.shape) + x = (x + np.array( + [-x_spacer, 0, 0, x_spacer] + )).flatten() + y = y.flatten() + + return x, y, ymn, ymx + + +@njit( + # NOTE: need to construct this manually for readonly + # arrays, see https://github.com/numba/numba/issues/4511 + # ( + # types.Array( + # numba_ohlc_dtype, + # 1, + # 'C', + # readonly=True, + # ), + # int64, + # types.unicode_type, + # optional(float64), + # ), + nogil=True +) +def path_arrays_from_ohlc( + data: np.ndarray, + start: int64, + bar_gap: float64 = 0.43, + # index_field: str, + +) -> tuple[ + np.ndarray, + np.ndarray, + np.ndarray, +]: + ''' + Generate an array of lines objects from input ohlc data. + + ''' + size = int(data.shape[0] * 6) + + # XXX: see this for why the dtype might have to be defined outside + # the routine. + # https://github.com/numba/numba/issues/4098#issuecomment-493914533 + x = np.zeros( + shape=size, + dtype=float64, + ) + y, c = x.copy(), x.copy() + + # 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): + + # TODO: ask numba why this doesn't work.. + # open, high, low, close, index = q[ + # ['open', 'high', 'low', 'close', 'index']] + + open = q['open'] + high = q['high'] + low = q['low'] + close = q['close'] + # index = float64(q[index_field]) + index = float64(q['index']) + + istart = i * 6 + istop = istart + 6 + + # x,y detail the 6 points which connect all vertexes of a ohlc bar + x[istart:istop] = ( + index - bar_gap, + index, + index, + index, + index, + index + bar_gap, + ) + y[istart:istop] = ( + open, + open, + low, + high, + close, + close, + ) + + # specifies that the first edge is never connected to the + # prior bars last edge thus providing a small "gap"/"space" + # between bars determined by ``bar_gap``. + c[istart:istop] = (1, 1, 1, 1, 1, 0) + + return x, y, c diff --git a/piker/ui/_render.py b/piker/ui/_render.py index 96c7e069..1caa8365 100644 --- a/piker/ui/_render.py +++ b/piker/ui/_render.py @@ -42,8 +42,8 @@ from ..data._formatters import ( OHLCBarsFmtr, # Plain OHLC renderer OHLCBarsAsCurveFmtr, # OHLC converted to line StepCurveFmtr, # "step" curve (like for vlm) - xy_downsample, ) +from ..data._pathops import xy_downsample from .._profile import ( pg_profile_enabled, # ms_slower_then,