diff --git a/piker/ui/_curve.py b/piker/ui/_curve.py index 091bbad0..5442d347 100644 --- a/piker/ui/_curve.py +++ b/piker/ui/_curve.py @@ -163,22 +163,32 @@ class FlowGraphic(pg.GraphicsObject): return None + # XXX: due to a variety of weird jitter bugs and "smearing" + # artifacts when click-drag panning and viewing history time series, + # we offer this ctx-mngr interface to allow temporarily disabling + # Qt's graphics caching mode; this is now currently used from + # ``ChartView.start/signal_ic()`` methods which also disable the + # rt-display loop when the user is moving around a view. @cm def reset_cache(self) -> None: - self.setCacheMode(QtWidgets.QGraphicsItem.NoCache) try: - log.debug(f'{self._name} -> CACHE DISABLE') + none = QGraphicsItem.NoCache + log.debug( + f'{self._name} -> CACHE DISABLE: {none}' + ) + self.setCacheMode(none) yield finally: - log.debug(f'{self._name} -> CACHE ENABLE') - self.setCacheMode(self.cache_mode) + mode = self.cache_mode + log.debug(f'{self._name} -> CACHE ENABLE {mode}') + self.setCacheMode(mode) class Curve(FlowGraphic): ''' A faster, simpler, append friendly version of ``pyqtgraph.PlotCurveItem`` built for highly customizable real-time - updates. + updates; a graphics object to render a simple "line" plot. This type is a much stripped down version of a ``pyqtgraph`` style "graphics object" in the sense that the internal lower level @@ -385,7 +395,6 @@ class Curve(FlowGraphic): ) -> None: # default line draw last call - # with self.reset_cache(): x = src_data[index_field] y = src_data[array_key] @@ -413,12 +422,20 @@ class Curve(FlowGraphic): # element such that the current datum in view can be shown # (via it's max / min) even when highly zoomed out. class FlattenedOHLC(Curve): + ''' + More or less the exact same as a standard line ``Curve`` above + but meant to handle a traced-and-downsampled OHLC time series. + _ + _| | _ + |_ | |_ | | + _| => |_| | + | | + |_ |_ - # avoids strange dragging/smearing artifacts when panning - # as well as mouse over artefacts when the vlm chart series - # is "shorter" then some overlay.. - # cache_mode: int = QGraphicsItem.NoCache + The main implementation different is that ``.draw_last_datum()`` + expects an underlying OHLC array for the ``src_data`` input. + ''' def draw_last_datum( self, path: QPainterPath, @@ -443,12 +460,19 @@ class FlattenedOHLC(Curve): class StepCurve(Curve): + ''' + A familiar rectangle-with-y-height-per-datum type curve: - # avoids strange dragging/smearing artifacts when panning - # as well as mouse over artefacts when the vlm chart series - # is "shorter" then some overlay.. - # cache_mode: int = QGraphicsItem.NoCache + || + || || + || || |||| + _||_||_||_||||_ where each datum's y-value is drawn as + a nearly full rectangle, each "level" spans some x-step size. + This is most often used for vlm and option OI style curves and/or + the very popular "bar chart". + + ''' def declare_paintables( self, ) -> None: diff --git a/piker/ui/_display.py b/piker/ui/_display.py index 8a4de766..685fcca7 100644 --- a/piker/ui/_display.py +++ b/piker/ui/_display.py @@ -473,7 +473,7 @@ async def graphics_update_loop( fast_chart.pause_all_feeds() continue - ic = fast_chart.view._ic + ic = fast_chart.view._in_interact if ic: fast_chart.pause_all_feeds() print(f'{fqsn} PAUSING DURING INTERACTION') @@ -756,8 +756,8 @@ def graphics_update_cycle( mx = max(mx, lmx) if ( - main_vb._ic is None - or not main_vb._ic.is_set() + main_vb._in_interact is None + or not main_vb._in_interact.is_set() ): # print(f'SETTING Y-mnmx -> {main_viz.name}: {(mn, mx)}') this_vb.interact_graphics_cycle( diff --git a/piker/ui/_interaction.py b/piker/ui/_interaction.py index 6de25aa8..15e5b2ff 100644 --- a/piker/ui/_interaction.py +++ b/piker/ui/_interaction.py @@ -19,7 +19,10 @@ Chart view box primitives ''' from __future__ import annotations -from contextlib import asynccontextmanager +from contextlib import ( + asynccontextmanager, + ExitStack, +) import time from typing import ( Callable, @@ -405,7 +408,8 @@ class ChartView(ViewBox): self.order_mode: bool = False self.setFocusPolicy(QtCore.Qt.StrongFocus) - self._ic = None + self._in_interact: trio.Event | None = None + self._interact_stack: ExitStack = ExitStack() # TODO: probably just assign this whenever a new `PlotItem` is # allocated since they're 1to1 with views.. @@ -420,10 +424,20 @@ class ChartView(ViewBox): to any interested task waiters. ''' - if self._ic is None: + if self._in_interact is None: + chart = self.chart try: - self.chart.pause_all_feeds() - self._ic = trio.Event() + chart.pause_all_feeds() + self._in_interact = trio.Event() + for viz in chart.iter_vizs(): + self._interact_stack.enter_context( + viz.graphics.reset_cache(), + ) + dsg = viz.ds_graphics + if dsg: + self._interact_stack.enter_context( + dsg.reset_cache(), + ) except RuntimeError: pass @@ -437,10 +451,11 @@ class ChartView(ViewBox): to any waiters. ''' - if self._ic: + if self._in_interact: try: - self._ic.set() - self._ic = None + self._in_interact.set() + self._in_interact = None + self._interact_stack.close() self.chart.resume_all_feeds() except RuntimeError: pass @@ -667,9 +682,6 @@ class ChartView(ViewBox): self.start_ic() except RuntimeError: pass - # if self._ic is None: - # self.chart.pause_all_feeds() - # self._ic = trio.Event() if axis == 1: self.chart._static_yrange = 'axis' @@ -693,8 +705,8 @@ class ChartView(ViewBox): if ev.isFinish(): self.signal_ic() - # self._ic.set() - # self._ic = None + # self._in_interact.set() + # self._in_interact = None # self.chart.resume_all_feeds() # # XXX: WHY diff --git a/piker/ui/_ohlc.py b/piker/ui/_ohlc.py index f3eb12b0..33d7bbda 100644 --- a/piker/ui/_ohlc.py +++ b/piker/ui/_ohlc.py @@ -28,7 +28,6 @@ from PyQt5.QtCore import ( QLineF, QRectF, ) -from PyQt5.QtWidgets import QGraphicsItem from PyQt5.QtGui import QPainterPath from ._curve import FlowGraphic @@ -91,10 +90,6 @@ class BarItems(FlowGraphic): "Price range" bars graphics rendered from a OHLC sampled sequence. ''' - # XXX: causes this weird jitter bug when click-drag panning - # where the path curve will awkwardly flicker back and forth? - # cache_mode: int = QGraphicsItem.NoCache - def __init__( self, *args,