Make `ChartPlotWidget.default_view()` pin to L1
Instead of using a guess about how many x-indexes to reset the last datum in-view to, calculate and shift the latest index such that it's just before any L1 spread labels on the y-axis. This makes the view placement "widget aware" and gives a much more cross-display UX. Summary: - add `ChartPlotWidget.pre_l1_x()` which returns a `tuple` of x view-coord points for the absolute x-pos and length of any L1 line/labels - make `.default_view()` only shift to see the xlast just outside the l1 but keep whatever view range xfirst as the first datum in view - drop `LevelLine.right_point()` since this is now just a `.pre_l1_x()` call and can be retrieved from the line's internal chart ref - drop `._style.bars_from/to_..` vars since we aren't using hard coded offsets any morem4_corrections
parent
e95896722f
commit
6bf4cdaa24
|
@ -25,7 +25,6 @@ from PyQt5.QtCore import QPointF
|
||||||
from PyQt5.QtWidgets import QGraphicsPathItem
|
from PyQt5.QtWidgets import QGraphicsPathItem
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._axes import PriceAxis
|
|
||||||
from ._chart import ChartPlotWidget
|
from ._chart import ChartPlotWidget
|
||||||
from ._label import Label
|
from ._label import Label
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ from PyQt5 import QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import (
|
from PyQt5.QtCore import (
|
||||||
Qt,
|
Qt,
|
||||||
QLineF,
|
QLineF,
|
||||||
QPointF,
|
# QPointF,
|
||||||
)
|
)
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QFrame,
|
QFrame,
|
||||||
|
@ -56,8 +56,6 @@ from ._style import (
|
||||||
CHART_MARGINS,
|
CHART_MARGINS,
|
||||||
_xaxis_at,
|
_xaxis_at,
|
||||||
_min_points_to_show,
|
_min_points_to_show,
|
||||||
_bars_from_right_in_follow_mode,
|
|
||||||
_bars_to_left_in_follow_mode,
|
|
||||||
)
|
)
|
||||||
from ..data.feed import Feed
|
from ..data.feed import Feed
|
||||||
from ..data._source import Symbol
|
from ..data._source import Symbol
|
||||||
|
@ -846,29 +844,62 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
QLineF(lbar, 0, rbar, 0)
|
QLineF(lbar, 0, rbar, 0)
|
||||||
).length()
|
).length()
|
||||||
|
|
||||||
def default_view(
|
def pre_l1_x(
|
||||||
self,
|
self,
|
||||||
index: int = -1,
|
view_coords: bool = False,
|
||||||
|
|
||||||
) -> None:
|
) -> tuple[float, float]:
|
||||||
|
'''
|
||||||
|
Return the scene x-coord for the value just before
|
||||||
|
the L1 labels on the y-axis as well as the length
|
||||||
|
of that L1 label from the y-axis.
|
||||||
|
|
||||||
|
'''
|
||||||
|
l1_len = self._max_l1_line_len
|
||||||
|
ryaxis = self.getAxis('right')
|
||||||
|
ryaxis_x = ryaxis.pos().x()
|
||||||
|
up_to_l1_sc = ryaxis_x - l1_len
|
||||||
|
if not view_coords:
|
||||||
|
return up_to_l1_sc, l1_len
|
||||||
|
else:
|
||||||
|
view = self.view
|
||||||
|
line = view.mapToView(
|
||||||
|
QLineF(up_to_l1_sc, 0, ryaxis_x, 0)
|
||||||
|
)
|
||||||
|
return line.x1(), line.length()
|
||||||
|
|
||||||
|
def default_view(self) -> None:
|
||||||
'''
|
'''
|
||||||
Set the view box to the "default" startup view of the scene.
|
Set the view box to the "default" startup view of the scene.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
xlast = self._arrays[self.name][index]['index']
|
index = self._arrays[self.name]['index']
|
||||||
except IndexError:
|
except IndexError:
|
||||||
log.warning(f'array for {self.name} not loaded yet?')
|
log.warning(f'array for {self.name} not loaded yet?')
|
||||||
return
|
return
|
||||||
|
|
||||||
begin = xlast - 1000
|
xfirst, xlast = index[0], index[-1]
|
||||||
end = xlast + _bars_from_right_in_follow_mode
|
view = self.view
|
||||||
|
vr = view.viewRange()
|
||||||
|
marker_pos, l1_len = self.pre_l1_x(view_coords=True)
|
||||||
|
end = xlast + l1_len
|
||||||
|
xl = vr[0][0]
|
||||||
|
begin = max(xl, xfirst)
|
||||||
|
|
||||||
|
# print(
|
||||||
|
# f'view range: {vr}\n'
|
||||||
|
# f'xlast: {xlast}\n'
|
||||||
|
# f'marker pos: {marker_pos}\n'
|
||||||
|
# f'l1 len: {l1_len}\n'
|
||||||
|
# f'begin: {begin}\n'
|
||||||
|
# f'end: {end}\n'
|
||||||
|
# )
|
||||||
|
|
||||||
# remove any custom user yrange setttings
|
# remove any custom user yrange setttings
|
||||||
if self._static_yrange == 'axis':
|
if self._static_yrange == 'axis':
|
||||||
self._static_yrange = None
|
self._static_yrange = None
|
||||||
|
|
||||||
view = self.view
|
|
||||||
view.setXRange(
|
view.setXRange(
|
||||||
min=begin,
|
min=begin,
|
||||||
max=end,
|
max=end,
|
||||||
|
@ -1228,7 +1259,6 @@ class ChartPlotWidget(pg.PlotWidget):
|
||||||
ifirst = array[0]['index']
|
ifirst = array[0]['index']
|
||||||
# slice data by offset from the first index
|
# slice data by offset from the first index
|
||||||
# available in the passed datum set.
|
# available in the passed datum set.
|
||||||
start = lbar - ifirst
|
|
||||||
return array[lbar - ifirst:(rbar - ifirst) + 1]
|
return array[lbar - ifirst:(rbar - ifirst) + 1]
|
||||||
|
|
||||||
def maxmin(
|
def maxmin(
|
||||||
|
|
|
@ -20,7 +20,7 @@ Lines for orders, alerts, L2.
|
||||||
"""
|
"""
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from math import floor
|
from math import floor
|
||||||
from typing import Tuple, Optional, List, Callable
|
from typing import Optional, Callable
|
||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph import Point, functions as fn
|
from pyqtgraph import Point, functions as fn
|
||||||
|
@ -32,7 +32,6 @@ from ._anchors import (
|
||||||
marker_right_points,
|
marker_right_points,
|
||||||
vbr_left,
|
vbr_left,
|
||||||
right_axis,
|
right_axis,
|
||||||
# pp_tight_and_right, # wanna keep it straight in the long run
|
|
||||||
gpath_pin,
|
gpath_pin,
|
||||||
)
|
)
|
||||||
from ..calc import humanize
|
from ..calc import humanize
|
||||||
|
@ -104,8 +103,8 @@ class LevelLine(pg.InfiniteLine):
|
||||||
|
|
||||||
# list of labels anchored at one of the 2 line endpoints
|
# list of labels anchored at one of the 2 line endpoints
|
||||||
# inside the viewbox
|
# inside the viewbox
|
||||||
self._labels: List[Label] = []
|
self._labels: list[Label] = []
|
||||||
self._markers: List[(int, Label)] = []
|
self._markers: list[(int, Label)] = []
|
||||||
|
|
||||||
# whenever this line is moved trigger label updates
|
# whenever this line is moved trigger label updates
|
||||||
self.sigPositionChanged.connect(self.on_pos_change)
|
self.sigPositionChanged.connect(self.on_pos_change)
|
||||||
|
@ -124,7 +123,7 @@ class LevelLine(pg.InfiniteLine):
|
||||||
self._y_incr_mult = 1 / chart.linked.symbol.tick_size
|
self._y_incr_mult = 1 / chart.linked.symbol.tick_size
|
||||||
self._right_end_sc: float = 0
|
self._right_end_sc: float = 0
|
||||||
|
|
||||||
def txt_offsets(self) -> Tuple[int, int]:
|
def txt_offsets(self) -> tuple[int, int]:
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -315,17 +314,6 @@ class LevelLine(pg.InfiniteLine):
|
||||||
# TODO: enter labels edit mode
|
# TODO: enter labels edit mode
|
||||||
print(f'double click {ev}')
|
print(f'double click {ev}')
|
||||||
|
|
||||||
def right_point(
|
|
||||||
self,
|
|
||||||
) -> float:
|
|
||||||
|
|
||||||
chart = self._chart
|
|
||||||
l1_len = chart._max_l1_line_len
|
|
||||||
ryaxis = chart.getAxis('right')
|
|
||||||
up_to_l1_sc = ryaxis.pos().x() - l1_len
|
|
||||||
|
|
||||||
return up_to_l1_sc
|
|
||||||
|
|
||||||
def paint(
|
def paint(
|
||||||
self,
|
self,
|
||||||
|
|
||||||
|
@ -422,23 +410,23 @@ class LevelLine(pg.InfiniteLine):
|
||||||
|
|
||||||
) -> QtWidgets.QGraphicsPathItem:
|
) -> QtWidgets.QGraphicsPathItem:
|
||||||
|
|
||||||
|
self._marker = path
|
||||||
|
self._marker.setPen(self.currentPen)
|
||||||
|
self._marker.setBrush(fn.mkBrush(self.currentPen.color()))
|
||||||
# add path to scene
|
# add path to scene
|
||||||
self.getViewBox().scene().addItem(path)
|
self.getViewBox().scene().addItem(path)
|
||||||
|
|
||||||
self._marker = path
|
# place to just-left of L1 labels
|
||||||
|
rsc = self._chart.pre_l1_x()[0]
|
||||||
rsc = self.right_point()
|
|
||||||
|
|
||||||
self._marker.setPen(self.currentPen)
|
|
||||||
self._marker.setBrush(fn.mkBrush(self.currentPen.color()))
|
|
||||||
path.setPos(QPointF(rsc, self.scene_y()))
|
path.setPos(QPointF(rsc, self.scene_y()))
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def hoverEvent(self, ev):
|
def hoverEvent(self, ev):
|
||||||
"""Mouse hover callback.
|
'''
|
||||||
|
Mouse hover callback.
|
||||||
|
|
||||||
"""
|
'''
|
||||||
cur = self._chart.linked.cursor
|
cur = self._chart.linked.cursor
|
||||||
|
|
||||||
# hovered
|
# hovered
|
||||||
|
@ -614,7 +602,8 @@ def order_line(
|
||||||
**line_kwargs,
|
**line_kwargs,
|
||||||
|
|
||||||
) -> LevelLine:
|
) -> LevelLine:
|
||||||
'''Convenience routine to add a line graphic representing an order
|
'''
|
||||||
|
Convenience routine to add a line graphic representing an order
|
||||||
execution submitted to the EMS via the chart's "order mode".
|
execution submitted to the EMS via the chart's "order mode".
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -689,7 +678,6 @@ def order_line(
|
||||||
|
|
||||||
return f'{account}: '
|
return f'{account}: '
|
||||||
|
|
||||||
|
|
||||||
label.fields = {
|
label.fields = {
|
||||||
'size': size,
|
'size': size,
|
||||||
'size_digits': 0,
|
'size_digits': 0,
|
||||||
|
|
|
@ -14,9 +14,10 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""
|
'''
|
||||||
Qt UI styling.
|
Qt UI styling.
|
||||||
"""
|
|
||||||
|
'''
|
||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -202,8 +203,6 @@ _xaxis_at = 'bottom'
|
||||||
# charting config
|
# charting config
|
||||||
CHART_MARGINS = (0, 0, 2, 2)
|
CHART_MARGINS = (0, 0, 2, 2)
|
||||||
_min_points_to_show = 6
|
_min_points_to_show = 6
|
||||||
_bars_to_left_in_follow_mode = int(61*6)
|
|
||||||
_bars_from_right_in_follow_mode = round(0.16 * _bars_to_left_in_follow_mode)
|
|
||||||
_tina_mode = False
|
_tina_mode = False
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue