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.multichartz
							parent
							
								
									e280e487c8
								
							
						
					
					
						commit
						b1de6dfd0e
					
				| 
						 | 
				
			
			@ -22,7 +22,6 @@ from collections import defaultdict
 | 
			
		|||
from functools import partial
 | 
			
		||||
from typing import (
 | 
			
		||||
    Callable,
 | 
			
		||||
    Optional,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from pyqtgraph.graphicsItems.AxisItem import AxisItem
 | 
			
		||||
| 
						 | 
				
			
			@ -246,7 +245,7 @@ class ComposedGridLayout:
 | 
			
		|||
        plot: PlotItem,
 | 
			
		||||
        name: str,
 | 
			
		||||
 | 
			
		||||
    ) -> Optional[AxisItem]:
 | 
			
		||||
    ) -> AxisItem | None:
 | 
			
		||||
        '''
 | 
			
		||||
        Retrieve the named axis for overlayed ``plot`` or ``None``
 | 
			
		||||
        if axis for that name is not shown.
 | 
			
		||||
| 
						 | 
				
			
			@ -321,7 +320,7 @@ class PlotItemOverlay:
 | 
			
		|||
    def add_plotitem(
 | 
			
		||||
        self,
 | 
			
		||||
        plotitem: PlotItem,
 | 
			
		||||
        index: Optional[int] = None,
 | 
			
		||||
        index: int | None = None,
 | 
			
		||||
 | 
			
		||||
        # event/signal names which will be broadcasted to all added
 | 
			
		||||
        # (relayee) ``PlotItem``s (eg. ``ViewBox.mouseDragEvent``).
 | 
			
		||||
| 
						 | 
				
			
			@ -376,7 +375,7 @@ class PlotItemOverlay:
 | 
			
		|||
 | 
			
		||||
                        # TODO: drop this viewbox specific input and
 | 
			
		||||
                        # 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,
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue