Add first-draft `PlotItemOverlay.group_maxmin()`

Computes the maxmin values for each underlying plot's in-view range as
well as the max up/down swing (in percentage terms) from the plot with
most dispersion and returns a all these values plus a `dict` of plots to
their ranges as part of output.
log_linearized_curve_overlays
Tyler Goodlet 2023-01-15 13:32:22 -05:00
parent eb51033b18
commit 223e9d999c
1 changed files with 93 additions and 4 deletions

View File

@ -22,7 +22,6 @@ from collections import defaultdict
from functools import partial from functools import partial
from typing import ( from typing import (
Callable, Callable,
Optional,
) )
from pyqtgraph.graphicsItems.AxisItem import AxisItem from pyqtgraph.graphicsItems.AxisItem import AxisItem
@ -246,7 +245,7 @@ class ComposedGridLayout:
plot: PlotItem, plot: PlotItem,
name: str, name: str,
) -> Optional[AxisItem]: ) -> AxisItem | None:
''' '''
Retrieve the named axis for overlayed ``plot`` or ``None`` Retrieve the named axis for overlayed ``plot`` or ``None``
if axis for that name is not shown. if axis for that name is not shown.
@ -321,7 +320,7 @@ class PlotItemOverlay:
def add_plotitem( def add_plotitem(
self, self,
plotitem: PlotItem, plotitem: PlotItem,
index: Optional[int] = None, index: int | None = None,
# event/signal names which will be broadcasted to all added # event/signal names which will be broadcasted to all added
# (relayee) ``PlotItem``s (eg. ``ViewBox.mouseDragEvent``). # (relayee) ``PlotItem``s (eg. ``ViewBox.mouseDragEvent``).
@ -376,7 +375,7 @@ class PlotItemOverlay:
# TODO: drop this viewbox specific input and # TODO: drop this viewbox specific input and
# allow a predicate to be passed in by user. # allow a predicate to be passed in by user.
axis: 'Optional[int]' = None, axis: int | None = None,
*, *,
@ -578,3 +577,93 @@ class PlotItemOverlay:
# ''' # '''
# ... # ...
def group_maxmin(
self,
focus_around: str | None = None,
force_min: float | None = None,
) -> tuple[
float, # mn
float, # mx
float, # max range in % terms of highest sigma plot's y-range
PlotItem, # front/selected plot
]:
'''
Overlay "group" maxmin sorting.
Assumes all named flows are in the same co-domain and thus can
be sorted as one set.
Iterates all the named flows and calls the chart api to find
their range values and return.
TODO: really we should probably have a more built-in API for
this?
'''
# TODO:
# - use this in the ``.ui._fsp`` mutli-maxmin stuff
# -
# force 0 to always be in view
group_mx: float = 0
group_mn: float = 0
mx_up_rng: float = 0
mn_down_rng: float = 0
pis2ranges: dict[
PlotItem,
tuple[float, float],
] = {}
for pi in self.overlays:
# TODO: can we remove this from the widget
# and place somewhere more related to UX/Viz?
# name = pi.name
# chartw = pi.chart_widget
viz = pi.viz
# viz = chartw._vizs[name]
out = viz.maxmin()
if out is None:
return None
(
(x_start, x_stop),
read_slc,
(ymn, ymx),
) = out
arr = viz.shm.array
y_start = arr[read_slc.start - 1]
y_stop = arr[read_slc.stop - 1]
if viz.is_ohlc:
y_start = y_start['open']
y_stop = y_stop['close']
else:
y_start = y_start[viz.name]
y_stop = y_stop[viz.name]
# update max for group
up_rng = (ymx - y_start) / y_start
down_rng = (y_stop - ymn) / y_stop
# compute directional (up/down) y-range % swing/dispersion
mx_up_rng = max(mx_up_rng, up_rng)
mn_down_rng = min(mn_down_rng, down_rng)
pis2ranges[pi] = (ymn, ymx)
group_mx = max(group_mx, ymx)
if force_min is None:
group_mn = min(group_mn, ymn)
return (
group_mn if force_min is None else force_min,
group_mx,
mn_down_rng,
mx_up_rng,
pis2ranges,
)