From 81b10b9dfc1ae9eed57f0223e1b36f39787bdcf0 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Wed, 30 Dec 2020 12:55:02 -0500 Subject: [PATCH] Add initial y-axis zoom --- piker/ui/_chart.py | 79 +++++++++++++++++++++++----------------- piker/ui/_interaction.py | 23 +++++++++++- 2 files changed, 66 insertions(+), 36 deletions(-) diff --git a/piker/ui/_chart.py b/piker/ui/_chart.py index 92eed5d2..6cc8ecb1 100644 --- a/piker/ui/_chart.py +++ b/piker/ui/_chart.py @@ -384,7 +384,6 @@ class ChartPlotWidget(pg.PlotWidget): # self.setViewportMargins(0, 0, 0, 0) self._ohlc = array # readonly view of ohlc data - self.default_view() self._arrays = {} # readonly view of overlays self._graphics = {} # registry of underlying graphics @@ -406,6 +405,8 @@ class ChartPlotWidget(pg.PlotWidget): # show background grid self.showGrid(x=True, y=True, alpha=0.5) + self.default_view() + # TODO: stick in config # use cross-hair for cursor? # self.setCursor(QtCore.Qt.CrossCursor) @@ -478,10 +479,13 @@ class ChartPlotWidget(pg.PlotWidget): """ xlast = self._ohlc[index]['index'] - print(xlast) begin = xlast - _bars_to_left_in_follow_mode end = xlast + _bars_from_right_in_follow_mode + # remove any custom user yrange setttings + if self._static_yrange == 'axis': + self._static_yrange = None + self.plotItem.vb.setXRange( min=begin, max=end, @@ -697,7 +701,12 @@ class ChartPlotWidget(pg.PlotWidget): data set. """ - if self._static_yrange is not None: + set_range = True + + if self._static_yrange == 'axis': + set_range = False + + elif self._static_yrange is not None: ylow, yhigh = self._static_yrange elif yrange is not None: @@ -761,44 +770,46 @@ class ChartPlotWidget(pg.PlotWidget): ylow = np.nanmin(bars) yhigh = np.nanmax(bars) - # view margins: stay within a % of the "true range" - diff = yhigh - ylow - ylow = ylow - (diff * 0.04) - yhigh = yhigh + (diff * 0.04) + if set_range: + # view margins: stay within a % of the "true range" + diff = yhigh - ylow + ylow = ylow - (diff * 0.04) + yhigh = yhigh + (diff * 0.04) - # # compute contents label "height" in view terms - # # to avoid having data "contents" overlap with them - # if self._labels: - # label = self._labels[self.name][0] + self.setLimits( + yMin=ylow, + yMax=yhigh, + ) + self.setYRange(ylow, yhigh) - # rect = label.itemRect() - # tl, br = rect.topLeft(), rect.bottomRight() - # vb = self.plotItem.vb + # def _label_h(self, yhigh: float, ylow: float) -> float: + # # compute contents label "height" in view terms + # # to avoid having data "contents" overlap with them + # if self._labels: + # label = self._labels[self.name][0] - # try: - # # on startup labels might not yet be rendered - # top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y()) + # rect = label.itemRect() + # tl, br = rect.topLeft(), rect.bottomRight() + # vb = self.plotItem.vb - # # XXX: magic hack, how do we compute exactly? - # label_h = (top - bottom) * 0.42 + # try: + # # on startup labels might not yet be rendered + # top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y()) - # except np.linalg.LinAlgError: - # label_h = 0 - # else: - # label_h = 0 + # # XXX: magic hack, how do we compute exactly? + # label_h = (top - bottom) * 0.42 - # # print(f'label height {self.name}: {label_h}') + # except np.linalg.LinAlgError: + # label_h = 0 + # else: + # label_h = 0 - # if label_h > yhigh - ylow: - # label_h = 0 - # print(f"bounds (ylow, yhigh): {(ylow, yhigh)}") - label_h = 0 + # # print(f'label height {self.name}: {label_h}') - self.setLimits( - yMin=ylow, - yMax=yhigh + label_h, - ) - self.setYRange(ylow, yhigh + label_h) + # if label_h > yhigh - ylow: + # label_h = 0 + + # print(f"bounds (ylow, yhigh): {(ylow, yhigh)}") def enterEvent(self, ev): # noqa # pg.PlotWidget.enterEvent(self, ev) @@ -1137,7 +1148,7 @@ async def spawn_fsps( """Start an fsp subactor async. """ - print(f'FSP NAME: {fsp_name}') + # print(f'FSP NAME: {fsp_name}') portal = await n.run_in_actor( # subactor entrypoint diff --git a/piker/ui/_interaction.py b/piker/ui/_interaction.py index 464fd80e..f501238f 100644 --- a/piker/ui/_interaction.py +++ b/piker/ui/_interaction.py @@ -17,6 +17,8 @@ """ UX interaction customs. """ +from typing import Optional + import pyqtgraph as pg from pyqtgraph import ViewBox, Point, QtCore, QtGui from pyqtgraph import functions as fn @@ -144,7 +146,7 @@ class SelectRect(QtGui.QGraphicsRectItem): x1, x2 = start_pos.x(), end_pos.x() # TODO: heh, could probably use a max-min streamin algo here too - ymn, xmn = min(y1, y2), min(x1, x2) + _, xmn = min(y1, y2), min(x1, x2) ymx, xmx = max(y1, y2), max(x1, x2) pchng = (y2 - y1) / y1 * 100 @@ -277,7 +279,11 @@ class ChartView(ViewBox): ev.accept() self.sigRangeChangedManually.emit(mask) - def mouseDragEvent(self, ev, axis=None): + def mouseDragEvent( + self, + ev, + axis: Optional[int] = None, + ) -> None: # if axis is specified, event will only affect that axis. ev.accept() # we accept all buttons @@ -295,6 +301,18 @@ class ChartView(ViewBox): # Scale or translate based on mouse button if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton): + # zoom only y-axis when click-n-drag on it + if axis == 1: + # set a static y range special value on chart widget to + # prevent sizing to data in view. + self._chart._static_yrange = 'axis' + + scale_y = 1.3 ** (dif.y() * -1 / 20) + self.setLimits(yMin=None, yMax=None) + + # print(scale_y) + self.scaleBy((0, scale_y)) + if self.state['mouseMode'] == ViewBox.RectMode: down_pos = ev.buttonDownPos() @@ -333,6 +351,7 @@ class ChartView(ViewBox): self.sigRangeChangedManually.emit(self.state['mouseEnabled']) elif ev.button() & QtCore.Qt.RightButton: + # print "vb.rightDrag" if self.state['aspectLocked'] is not False: mask[0] = 0