Add initial y-axis zoom
parent
f3a0b1e91e
commit
81b10b9dfc
|
@ -384,7 +384,6 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
|
|
||||||
# self.setViewportMargins(0, 0, 0, 0)
|
# self.setViewportMargins(0, 0, 0, 0)
|
||||||
self._ohlc = array # readonly view of ohlc data
|
self._ohlc = array # readonly view of ohlc data
|
||||||
self.default_view()
|
|
||||||
|
|
||||||
self._arrays = {} # readonly view of overlays
|
self._arrays = {} # readonly view of overlays
|
||||||
self._graphics = {} # registry of underlying graphics
|
self._graphics = {} # registry of underlying graphics
|
||||||
|
@ -406,6 +405,8 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
# show background grid
|
# show background grid
|
||||||
self.showGrid(x=True, y=True, alpha=0.5)
|
self.showGrid(x=True, y=True, alpha=0.5)
|
||||||
|
|
||||||
|
self.default_view()
|
||||||
|
|
||||||
# TODO: stick in config
|
# TODO: stick in config
|
||||||
# use cross-hair for cursor?
|
# use cross-hair for cursor?
|
||||||
# self.setCursor(QtCore.Qt.CrossCursor)
|
# self.setCursor(QtCore.Qt.CrossCursor)
|
||||||
|
@ -478,10 +479,13 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
xlast = self._ohlc[index]['index']
|
xlast = self._ohlc[index]['index']
|
||||||
print(xlast)
|
|
||||||
begin = xlast - _bars_to_left_in_follow_mode
|
begin = xlast - _bars_to_left_in_follow_mode
|
||||||
end = xlast + _bars_from_right_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(
|
self.plotItem.vb.setXRange(
|
||||||
min=begin,
|
min=begin,
|
||||||
max=end,
|
max=end,
|
||||||
|
@ -697,7 +701,12 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
data set.
|
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
|
ylow, yhigh = self._static_yrange
|
||||||
|
|
||||||
elif yrange is not None:
|
elif yrange is not None:
|
||||||
|
@ -761,44 +770,46 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
ylow = np.nanmin(bars)
|
ylow = np.nanmin(bars)
|
||||||
yhigh = np.nanmax(bars)
|
yhigh = np.nanmax(bars)
|
||||||
|
|
||||||
# view margins: stay within a % of the "true range"
|
if set_range:
|
||||||
diff = yhigh - ylow
|
# view margins: stay within a % of the "true range"
|
||||||
ylow = ylow - (diff * 0.04)
|
diff = yhigh - ylow
|
||||||
yhigh = yhigh + (diff * 0.04)
|
ylow = ylow - (diff * 0.04)
|
||||||
|
yhigh = yhigh + (diff * 0.04)
|
||||||
|
|
||||||
# # compute contents label "height" in view terms
|
self.setLimits(
|
||||||
# # to avoid having data "contents" overlap with them
|
yMin=ylow,
|
||||||
# if self._labels:
|
yMax=yhigh,
|
||||||
# label = self._labels[self.name][0]
|
)
|
||||||
|
self.setYRange(ylow, yhigh)
|
||||||
|
|
||||||
# rect = label.itemRect()
|
# def _label_h(self, yhigh: float, ylow: float) -> float:
|
||||||
# tl, br = rect.topLeft(), rect.bottomRight()
|
# # compute contents label "height" in view terms
|
||||||
# vb = self.plotItem.vb
|
# # to avoid having data "contents" overlap with them
|
||||||
|
# if self._labels:
|
||||||
|
# label = self._labels[self.name][0]
|
||||||
|
|
||||||
# try:
|
# rect = label.itemRect()
|
||||||
# # on startup labels might not yet be rendered
|
# tl, br = rect.topLeft(), rect.bottomRight()
|
||||||
# top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y())
|
# vb = self.plotItem.vb
|
||||||
|
|
||||||
# # XXX: magic hack, how do we compute exactly?
|
# try:
|
||||||
# label_h = (top - bottom) * 0.42
|
# # on startup labels might not yet be rendered
|
||||||
|
# top, bottom = (vb.mapToView(tl).y(), vb.mapToView(br).y())
|
||||||
|
|
||||||
# except np.linalg.LinAlgError:
|
# # XXX: magic hack, how do we compute exactly?
|
||||||
# label_h = 0
|
# label_h = (top - bottom) * 0.42
|
||||||
# else:
|
|
||||||
# label_h = 0
|
|
||||||
|
|
||||||
# # print(f'label height {self.name}: {label_h}')
|
# except np.linalg.LinAlgError:
|
||||||
|
# label_h = 0
|
||||||
|
# else:
|
||||||
|
# label_h = 0
|
||||||
|
|
||||||
# if label_h > yhigh - ylow:
|
# # print(f'label height {self.name}: {label_h}')
|
||||||
# label_h = 0
|
|
||||||
# print(f"bounds (ylow, yhigh): {(ylow, yhigh)}")
|
|
||||||
label_h = 0
|
|
||||||
|
|
||||||
self.setLimits(
|
# if label_h > yhigh - ylow:
|
||||||
yMin=ylow,
|
# label_h = 0
|
||||||
yMax=yhigh + label_h,
|
|
||||||
)
|
# print(f"bounds (ylow, yhigh): {(ylow, yhigh)}")
|
||||||
self.setYRange(ylow, yhigh + label_h)
|
|
||||||
|
|
||||||
def enterEvent(self, ev): # noqa
|
def enterEvent(self, ev): # noqa
|
||||||
# pg.PlotWidget.enterEvent(self, ev)
|
# pg.PlotWidget.enterEvent(self, ev)
|
||||||
|
@ -1137,7 +1148,7 @@ async def spawn_fsps(
|
||||||
"""Start an fsp subactor async.
|
"""Start an fsp subactor async.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
print(f'FSP NAME: {fsp_name}')
|
# print(f'FSP NAME: {fsp_name}')
|
||||||
portal = await n.run_in_actor(
|
portal = await n.run_in_actor(
|
||||||
|
|
||||||
# subactor entrypoint
|
# subactor entrypoint
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
"""
|
"""
|
||||||
UX interaction customs.
|
UX interaction customs.
|
||||||
"""
|
"""
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph import ViewBox, Point, QtCore, QtGui
|
from pyqtgraph import ViewBox, Point, QtCore, QtGui
|
||||||
from pyqtgraph import functions as fn
|
from pyqtgraph import functions as fn
|
||||||
|
@ -144,7 +146,7 @@ class SelectRect(QtGui.QGraphicsRectItem):
|
||||||
x1, x2 = start_pos.x(), end_pos.x()
|
x1, x2 = start_pos.x(), end_pos.x()
|
||||||
|
|
||||||
# TODO: heh, could probably use a max-min streamin algo here too
|
# 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)
|
ymx, xmx = max(y1, y2), max(x1, x2)
|
||||||
|
|
||||||
pchng = (y2 - y1) / y1 * 100
|
pchng = (y2 - y1) / y1 * 100
|
||||||
|
@ -277,7 +279,11 @@ class ChartView(ViewBox):
|
||||||
ev.accept()
|
ev.accept()
|
||||||
self.sigRangeChangedManually.emit(mask)
|
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.
|
# if axis is specified, event will only affect that axis.
|
||||||
ev.accept() # we accept all buttons
|
ev.accept() # we accept all buttons
|
||||||
|
|
||||||
|
@ -295,6 +301,18 @@ class ChartView(ViewBox):
|
||||||
# Scale or translate based on mouse button
|
# Scale or translate based on mouse button
|
||||||
if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
|
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:
|
if self.state['mouseMode'] == ViewBox.RectMode:
|
||||||
|
|
||||||
down_pos = ev.buttonDownPos()
|
down_pos = ev.buttonDownPos()
|
||||||
|
@ -333,6 +351,7 @@ class ChartView(ViewBox):
|
||||||
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
|
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
|
||||||
|
|
||||||
elif ev.button() & QtCore.Qt.RightButton:
|
elif ev.button() & QtCore.Qt.RightButton:
|
||||||
|
|
||||||
# print "vb.rightDrag"
|
# print "vb.rightDrag"
|
||||||
if self.state['aspectLocked'] is not False:
|
if self.state['aspectLocked'] is not False:
|
||||||
mask[0] = 0
|
mask[0] = 0
|
||||||
|
|
Loading…
Reference in New Issue