Move plotitem overlaying into a `.overlay_plotitem()`
							parent
							
								
									d0693e2967
								
							
						
					
					
						commit
						ca9973e619
					
				| 
						 | 
				
			
			@ -19,8 +19,6 @@ High level chart-widget apis.
 | 
			
		|||
 | 
			
		||||
'''
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
from functools import partial
 | 
			
		||||
from dataclasses import dataclass
 | 
			
		||||
from typing import Optional
 | 
			
		||||
 | 
			
		||||
from PyQt5 import QtCore, QtWidgets
 | 
			
		||||
| 
						 | 
				
			
			@ -383,8 +381,9 @@ class LinkedSplits(QWidget):
 | 
			
		|||
 | 
			
		||||
        style: str = 'bar',
 | 
			
		||||
 | 
			
		||||
    ) -> 'ChartPlotWidget':
 | 
			
		||||
        '''Start up and show main (price) chart and all linked subcharts.
 | 
			
		||||
    ) -> ChartPlotWidget:
 | 
			
		||||
        '''
 | 
			
		||||
        Start up and show main (price) chart and all linked subcharts.
 | 
			
		||||
 | 
			
		||||
        The data input struct array must include OHLC fields.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +536,7 @@ class LinkedSplits(QWidget):
 | 
			
		|||
            )
 | 
			
		||||
            self.cursor.contents_labels.add_label(
 | 
			
		||||
                cpw,
 | 
			
		||||
                'ohlc',
 | 
			
		||||
                name,
 | 
			
		||||
                anchor_at=('top', 'left'),
 | 
			
		||||
                update_func=ContentsLabel.update_from_ohlc,
 | 
			
		||||
            )
 | 
			
		||||
| 
						 | 
				
			
			@ -611,11 +610,11 @@ class LinkedSplits(QWidget):
 | 
			
		|||
 | 
			
		||||
# import pydantic
 | 
			
		||||
 | 
			
		||||
# class ArrayScene(pydantic.BaseModel):
 | 
			
		||||
# class Graphics(pydantic.BaseModel):
 | 
			
		||||
#     '''
 | 
			
		||||
#     Data-AGGRegate: high level API onto multiple (categorized)
 | 
			
		||||
#     ``ShmArray``s with high level processing routines mostly for
 | 
			
		||||
#     graphics summary and display.
 | 
			
		||||
#     ``ShmArray``s with high level processing routines for
 | 
			
		||||
#     graphics computations and display.
 | 
			
		||||
 | 
			
		||||
#     '''
 | 
			
		||||
#     arrays: dict[str, np.ndarray] = {}
 | 
			
		||||
| 
						 | 
				
			
			@ -738,7 +737,7 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
        self.default_view()
 | 
			
		||||
        self.cv.enable_auto_yrange()
 | 
			
		||||
 | 
			
		||||
        self.overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem)
 | 
			
		||||
        self.pi_overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem)
 | 
			
		||||
 | 
			
		||||
    def resume_all_feeds(self):
 | 
			
		||||
        for feed in self._feeds.values():
 | 
			
		||||
| 
						 | 
				
			
			@ -849,7 +848,7 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
 | 
			
		||||
        # adds all bar/candle graphics objects for each data point in
 | 
			
		||||
        # the np array buffer to be drawn on next render cycle
 | 
			
		||||
        self.addItem(graphics)
 | 
			
		||||
        self.plotItem.addItem(graphics)
 | 
			
		||||
 | 
			
		||||
        # draw after to allow self.scene() to work...
 | 
			
		||||
        graphics.draw_from_data(data)
 | 
			
		||||
| 
						 | 
				
			
			@ -860,6 +859,57 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
 | 
			
		||||
        return graphics, data_key
 | 
			
		||||
 | 
			
		||||
    def overlay_plotitem(
 | 
			
		||||
        self,
 | 
			
		||||
        name: str,
 | 
			
		||||
 | 
			
		||||
    ) -> pg.PlotItem:
 | 
			
		||||
        # Custom viewbox impl
 | 
			
		||||
        cv = self.mk_vb(name)
 | 
			
		||||
        cv.chart = self
 | 
			
		||||
 | 
			
		||||
        # xaxis = DynamicDateAxis(
 | 
			
		||||
        #     orientation='bottom',
 | 
			
		||||
        #     linkedsplits=self.linked,
 | 
			
		||||
        # )
 | 
			
		||||
        yaxis = PriceAxis(
 | 
			
		||||
            orientation='right',
 | 
			
		||||
            linkedsplits=self.linked,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        plotitem = pg.PlotItem(
 | 
			
		||||
            parent=self.plotItem,
 | 
			
		||||
            name=name,
 | 
			
		||||
            enableMenu=False,
 | 
			
		||||
            viewBox=cv,
 | 
			
		||||
            axisItems={
 | 
			
		||||
                # 'bottom': xaxis,
 | 
			
		||||
                'right': yaxis,
 | 
			
		||||
            },
 | 
			
		||||
            default_axes=[],
 | 
			
		||||
        )
 | 
			
		||||
        # plotitem.setAxisItems(
 | 
			
		||||
        #     add_to_layout=False,
 | 
			
		||||
        #     axisItems={
 | 
			
		||||
        #         'bottom': xaxis,
 | 
			
		||||
        #         'right': yaxis,
 | 
			
		||||
        #     },
 | 
			
		||||
        # )
 | 
			
		||||
        # plotite.hideAxis('right')
 | 
			
		||||
        # plotite.hideAxis('bottom')
 | 
			
		||||
        # plotitem.addItem(curve)
 | 
			
		||||
        cv.enable_auto_yrange()
 | 
			
		||||
 | 
			
		||||
        # plotitem.enableAutoRange(axis='y')
 | 
			
		||||
        plotitem.hideButtons()
 | 
			
		||||
 | 
			
		||||
        self.pi_overlay.add_plotitem(
 | 
			
		||||
            plotitem,
 | 
			
		||||
            # only link x-axes,
 | 
			
		||||
            link_axes=(0,),
 | 
			
		||||
        )
 | 
			
		||||
        return plotitem
 | 
			
		||||
 | 
			
		||||
    def draw_curve(
 | 
			
		||||
        self,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -868,7 +918,6 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
 | 
			
		||||
        array_key: Optional[str] = None,
 | 
			
		||||
        overlay: bool = False,
 | 
			
		||||
        separate_axes: bool = False,
 | 
			
		||||
        color: Optional[str] = None,
 | 
			
		||||
        add_label: bool = True,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -907,11 +956,11 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
            **pdi_kwargs,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # XXX: see explanation for differenct caching modes:
 | 
			
		||||
        # XXX: see explanation for different caching modes:
 | 
			
		||||
        # https://stackoverflow.com/a/39410081
 | 
			
		||||
        # seems to only be useful if we don't re-generate the entire
 | 
			
		||||
        # QPainterPath every time
 | 
			
		||||
        # curve.curve.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)
 | 
			
		||||
        # curve.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)
 | 
			
		||||
 | 
			
		||||
        # don't ever use this - it's a colossal nightmare of artefacts
 | 
			
		||||
        # and is disastrous for performance.
 | 
			
		||||
| 
						 | 
				
			
			@ -921,83 +970,28 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
        self._graphics[name] = curve
 | 
			
		||||
        self._arrays[data_key] = data
 | 
			
		||||
 | 
			
		||||
        pi = self.plotItem
 | 
			
		||||
 | 
			
		||||
        # TODO: this probably needs its own method?
 | 
			
		||||
        if overlay:
 | 
			
		||||
            # anchor_at = ('bottom', 'left')
 | 
			
		||||
            self._overlays[name] = None
 | 
			
		||||
 | 
			
		||||
            if separate_axes:
 | 
			
		||||
            if isinstance(overlay, pg.PlotItem):
 | 
			
		||||
                if overlay not in self.pi_overlay.overlays:
 | 
			
		||||
                    raise RuntimeError(
 | 
			
		||||
                            f'{overlay} must be from `.plotitem_overlay()`'
 | 
			
		||||
                        )
 | 
			
		||||
                pi = overlay
 | 
			
		||||
 | 
			
		||||
                # Custom viewbox impl
 | 
			
		||||
                cv = self.mk_vb(name)
 | 
			
		||||
 | 
			
		||||
                def maxmin():
 | 
			
		||||
                    return self.maxmin(name=data_key)
 | 
			
		||||
 | 
			
		||||
                # ensure view maxmin is computed from correct array
 | 
			
		||||
                # cv._maxmin = partial(self.maxmin, name=data_key)
 | 
			
		||||
 | 
			
		||||
                cv._maxmin = maxmin
 | 
			
		||||
 | 
			
		||||
                cv.chart = self
 | 
			
		||||
 | 
			
		||||
                # xaxis = DynamicDateAxis(
 | 
			
		||||
                #     orientation='bottom',
 | 
			
		||||
                #     linkedsplits=self.linked,
 | 
			
		||||
                # )
 | 
			
		||||
                yaxis = PriceAxis(
 | 
			
		||||
                    orientation='right',
 | 
			
		||||
                    linkedsplits=self.linked,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                plotitem = pg.PlotItem(
 | 
			
		||||
                    parent=self.plotItem,
 | 
			
		||||
                    name=name,
 | 
			
		||||
                    enableMenu=False,
 | 
			
		||||
                    viewBox=cv,
 | 
			
		||||
                    axisItems={
 | 
			
		||||
                        # 'bottom': xaxis,
 | 
			
		||||
                        'right': yaxis,
 | 
			
		||||
                    },
 | 
			
		||||
                    default_axes=[],
 | 
			
		||||
                )
 | 
			
		||||
                # plotitem.setAxisItems(
 | 
			
		||||
                #     add_to_layout=False,
 | 
			
		||||
                #     axisItems={
 | 
			
		||||
                #         'bottom': xaxis,
 | 
			
		||||
                #         'right': yaxis,
 | 
			
		||||
                #     },
 | 
			
		||||
                # )
 | 
			
		||||
                # plotite.hideAxis('right')
 | 
			
		||||
                # plotite.hideAxis('bottom')
 | 
			
		||||
                plotitem.addItem(curve)
 | 
			
		||||
                cv.enable_auto_yrange()
 | 
			
		||||
 | 
			
		||||
                # config
 | 
			
		||||
                # plotitem.setAutoVisible(y=True)
 | 
			
		||||
                # plotitem.enableAutoRange(axis='y')
 | 
			
		||||
                plotitem.hideButtons()
 | 
			
		||||
 | 
			
		||||
                self.overlay.add_plotitem(
 | 
			
		||||
                    plotitem,
 | 
			
		||||
                    # only link x-axes,
 | 
			
		||||
                    link_axes=(0,),
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            else:
 | 
			
		||||
                # this intnernally calls `PlotItem.addItem()` on the
 | 
			
		||||
                # graphics object
 | 
			
		||||
                self.addItem(curve)
 | 
			
		||||
        else:
 | 
			
		||||
            # this intnernally calls `PlotItem.addItem()` on the
 | 
			
		||||
            # graphics object
 | 
			
		||||
            self.addItem(curve)
 | 
			
		||||
 | 
			
		||||
            # anchor_at = ('top', 'left')
 | 
			
		||||
 | 
			
		||||
            # TODO: something instead of stickies for overlays
 | 
			
		||||
            # (we need something that avoids clutter on x-axis).
 | 
			
		||||
            self._add_sticky(name, bg_color=color)
 | 
			
		||||
 | 
			
		||||
        pi.addItem(curve)
 | 
			
		||||
        return curve, data_key
 | 
			
		||||
 | 
			
		||||
    # TODO: make this a ctx mngr
 | 
			
		||||
| 
						 | 
				
			
			@ -1036,7 +1030,8 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
        **kwargs,
 | 
			
		||||
 | 
			
		||||
    ) -> pg.GraphicsObject:
 | 
			
		||||
        '''Update the named internal graphics from ``array``.
 | 
			
		||||
        '''
 | 
			
		||||
        Update the named internal graphics from ``array``.
 | 
			
		||||
 | 
			
		||||
        '''
 | 
			
		||||
        self._arrays[self.name] = array
 | 
			
		||||
| 
						 | 
				
			
			@ -1053,7 +1048,8 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
        **kwargs,
 | 
			
		||||
 | 
			
		||||
    ) -> pg.GraphicsObject:
 | 
			
		||||
        '''Update the named internal graphics from ``array``.
 | 
			
		||||
        '''
 | 
			
		||||
        Update the named internal graphics from ``array``.
 | 
			
		||||
 | 
			
		||||
        '''
 | 
			
		||||
        assert len(array)
 | 
			
		||||
| 
						 | 
				
			
			@ -1123,7 +1119,7 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
    def get_index(self, time: float) -> int:
 | 
			
		||||
 | 
			
		||||
        # TODO: this should go onto some sort of
 | 
			
		||||
        # data-view strimg thinger..right?
 | 
			
		||||
        # data-view thinger..right?
 | 
			
		||||
        ohlc = self._shm.array
 | 
			
		||||
 | 
			
		||||
        # XXX: not sure why the time is so off here
 | 
			
		||||
| 
						 | 
				
			
			@ -1178,15 +1174,9 @@ class ChartPlotWidget(pg.PlotWidget):
 | 
			
		|||
            yhigh = np.nanmax(bars['high'])
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                view = bars[name or self.data_key]
 | 
			
		||||
            except:
 | 
			
		||||
                breakpoint()
 | 
			
		||||
            # if self.data_key != 'volume':
 | 
			
		||||
            # else:
 | 
			
		||||
            #     view = bars
 | 
			
		||||
            view = bars[name or self.data_key]
 | 
			
		||||
            ylow = np.nanmin(view)
 | 
			
		||||
            yhigh = np.nanmax(view)
 | 
			
		||||
            # print(f'{(ylow, yhigh)}')
 | 
			
		||||
 | 
			
		||||
        # print(f'{(ylow, yhigh)}')
 | 
			
		||||
        return ylow, yhigh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue