Add optional uppx log scaling to m4 sampler

We were previously ad-hoc scaling up the px count/width to get more
detail at lower uppx values. Add a log scaling sigmoid that range scales
between 1 < px_width < 16.

Add in a flag to use the mxmn OH tracer in `ohlc_flatten()` if desired.
m4_corrections
Tyler Goodlet 2022-03-23 12:29:57 -04:00
parent 69cb8156a2
commit 9726ed1a42
1 changed files with 33 additions and 32 deletions

View File

@ -20,6 +20,7 @@ limits on the display device.
''' '''
import math import math
from typing import Optional
import numpy as np import numpy as np
from numpy.lib import recfunctions as rfn from numpy.lib import recfunctions as rfn
@ -34,11 +35,7 @@ from ..log import get_logger
log = get_logger(__name__) log = get_logger(__name__)
def hl2mxmn( def hl2mxmn(ohlc: np.ndarray) -> np.ndarray:
ohlc: np.ndarray,
# downsample_by: int = 0,
) -> np.ndarray:
''' '''
Convert a OHLC struct-array containing 'high'/'low' columns Convert a OHLC struct-array containing 'high'/'low' columns
to a "joined" max/min 1-d array. to a "joined" max/min 1-d array.
@ -50,12 +47,6 @@ def hl2mxmn(
'high', 'high',
]] ]]
# XXX: don't really need this any more since we implemented
# the "tracer" routine, `numba`-style..
# create a "max and min" sequence from ohlc datums
# hl2d = structured_to_unstructured(hls)
# hl1d = hl2d.flatten()
mxmn = np.empty(2*hls.size, dtype=np.float64) mxmn = np.empty(2*hls.size, dtype=np.float64)
x = np.empty(2*hls.size, dtype=np.float64) x = np.empty(2*hls.size, dtype=np.float64)
trace_hl(hls, mxmn, x, index[0]) trace_hl(hls, mxmn, x, index[0])
@ -63,18 +54,6 @@ def hl2mxmn(
return mxmn, x return mxmn, x
# if downsample_by < 2:
# return mxmn, x
# dsx, dsy = downsample(
# y=mxmn,
# x=x,
# bins=downsample_by,
# )
# log.info(f'downsampling by {downsample_by}')
# print(f'downsampling by {downsample_by}')
# return dsy, dsx
@jit( @jit(
# TODO: the type annots.. # TODO: the type annots..
@ -176,6 +155,7 @@ def downsample(
def ohlc_flatten( def ohlc_flatten(
ohlc: np.ndarray, ohlc: np.ndarray,
use_mxmn: bool = False,
) -> tuple[np.ndarray, np.ndarray]: ) -> tuple[np.ndarray, np.ndarray]:
''' '''
@ -186,15 +166,18 @@ def ohlc_flatten(
''' '''
index = ohlc['index'] index = ohlc['index']
flat = rfn.structured_to_unstructured( if use_mxmn:
ohlc[['open', 'high', 'low', 'close']] flat, x = hl2mxmn(ohlc)
).flatten() else:
flat = rfn.structured_to_unstructured(
ohlc[['open', 'high', 'low', 'close']]
).flatten()
x = np.linspace( x = np.linspace(
start=index[0] - 0.5, start=index[0] - 0.5,
stop=index[-1] + 0.5, stop=index[-1] + 0.5,
num=4*len(ohlc), num=len(flat),
) )
return x, flat return x, flat
@ -202,16 +185,33 @@ def ohlc_to_m4_line(
ohlc: np.ndarray, ohlc: np.ndarray,
px_width: int, px_width: int,
uppx: Optional[float] = None,
) -> tuple[np.ndarray, np.ndarray]: ) -> tuple[np.ndarray, np.ndarray]:
''' '''
Convert an OHLC struct-array to a m4 downsampled 1-d array. Convert an OHLC struct-array to a m4 downsampled 1-d array.
''' '''
xpts, flat = ohlc_flatten(ohlc) xpts, flat = ohlc_flatten(ohlc)
if uppx:
# optionally log-scale down the "supposed pxs on screen"
# as the units-per-px (uppx) get's large.
scaler = round(
max(
# NOTE: found that a 16x px width brought greater
# detail, likely due to dpi scaling?
# px_width=px_width * 16,
32 / (1 + math.log(uppx, 2)),
1
)
)
px_width *= scaler
bins, x, y = ds_m4( bins, x, y = ds_m4(
xpts, xpts,
flat, flat,
px_width=px_width * 16, px_width=px_width,
) )
x = np.broadcast_to(x[:, None], y.shape) x = np.broadcast_to(x[:, None], y.shape)
x = (x + np.array([-0.43, 0, 0, 0.43])).flatten() x = (x + np.array([-0.43, 0, 0, 0.43])).flatten()
@ -313,6 +313,7 @@ def ds_m4(
@jit( @jit(
nopython=True, nopython=True,
nogil=True,
) )
def _m4( def _m4(