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
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._axes import PriceAxis
|
||||
from ._chart import ChartPlotWidget
|
||||
from ._label import Label
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ from PyQt5 import QtCore, QtWidgets
|
|||
from PyQt5.QtCore import (
|
||||
Qt,
|
||||
QLineF,
|
||||
QPointF,
|
||||
# QPointF,
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
QFrame,
|
||||
|
@ -56,8 +56,6 @@ from ._style import (
|
|||
CHART_MARGINS,
|
||||
_xaxis_at,
|
||||
_min_points_to_show,
|
||||
_bars_from_right_in_follow_mode,
|
||||
_bars_to_left_in_follow_mode,
|
||||
)
|
||||
from ..data.feed import Feed
|
||||
from ..data._source import Symbol
|
||||
|
@ -846,29 +844,62 @@ class ChartPlotWidget(pg.PlotWidget):
|
|||
QLineF(lbar, 0, rbar, 0)
|
||||
).length()
|
||||
|
||||
def default_view(
|
||||
def pre_l1_x(
|
||||
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.
|
||||
|
||||
'''
|
||||
try:
|
||||
xlast = self._arrays[self.name][index]['index']
|
||||
index = self._arrays[self.name]['index']
|
||||
except IndexError:
|
||||
log.warning(f'array for {self.name} not loaded yet?')
|
||||
return
|
||||
|
||||
begin = xlast - 1000
|
||||
end = xlast + _bars_from_right_in_follow_mode
|
||||
xfirst, xlast = index[0], index[-1]
|
||||
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
|
||||
if self._static_yrange == 'axis':
|
||||
self._static_yrange = None
|
||||
|
||||
view = self.view
|
||||
view.setXRange(
|
||||
min=begin,
|
||||
max=end,
|
||||
|
@ -1228,7 +1259,6 @@ class ChartPlotWidget(pg.PlotWidget):
|
|||
ifirst = array[0]['index']
|
||||
# slice data by offset from the first index
|
||||
# available in the passed datum set.
|
||||
start = lbar - ifirst
|
||||
return array[lbar - ifirst:(rbar - ifirst) + 1]
|
||||
|
||||
def maxmin(
|
||||
|
|
|
@ -20,7 +20,7 @@ Lines for orders, alerts, L2.
|
|||
"""
|
||||
from functools import partial
|
||||
from math import floor
|
||||
from typing import Tuple, Optional, List, Callable
|
||||
from typing import Optional, Callable
|
||||
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph import Point, functions as fn
|
||||
|
@ -32,7 +32,6 @@ from ._anchors import (
|
|||
marker_right_points,
|
||||
vbr_left,
|
||||
right_axis,
|
||||
# pp_tight_and_right, # wanna keep it straight in the long run
|
||||
gpath_pin,
|
||||
)
|
||||
from ..calc import humanize
|
||||
|
@ -104,8 +103,8 @@ class LevelLine(pg.InfiniteLine):
|
|||
|
||||
# list of labels anchored at one of the 2 line endpoints
|
||||
# inside the viewbox
|
||||
self._labels: List[Label] = []
|
||||
self._markers: List[(int, Label)] = []
|
||||
self._labels: list[Label] = []
|
||||
self._markers: list[(int, Label)] = []
|
||||
|
||||
# whenever this line is moved trigger label updates
|
||||
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._right_end_sc: float = 0
|
||||
|
||||
def txt_offsets(self) -> Tuple[int, int]:
|
||||
def txt_offsets(self) -> tuple[int, int]:
|
||||
return 0, 0
|
||||
|
||||
@property
|
||||
|
@ -315,17 +314,6 @@ class LevelLine(pg.InfiniteLine):
|
|||
# TODO: enter labels edit mode
|
||||
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(
|
||||
self,
|
||||
|
||||
|
@ -422,23 +410,23 @@ class LevelLine(pg.InfiniteLine):
|
|||
|
||||
) -> QtWidgets.QGraphicsPathItem:
|
||||
|
||||
self._marker = path
|
||||
self._marker.setPen(self.currentPen)
|
||||
self._marker.setBrush(fn.mkBrush(self.currentPen.color()))
|
||||
# add path to scene
|
||||
self.getViewBox().scene().addItem(path)
|
||||
|
||||
self._marker = path
|
||||
|
||||
rsc = self.right_point()
|
||||
|
||||
self._marker.setPen(self.currentPen)
|
||||
self._marker.setBrush(fn.mkBrush(self.currentPen.color()))
|
||||
# place to just-left of L1 labels
|
||||
rsc = self._chart.pre_l1_x()[0]
|
||||
path.setPos(QPointF(rsc, self.scene_y()))
|
||||
|
||||
return path
|
||||
|
||||
def hoverEvent(self, ev):
|
||||
"""Mouse hover callback.
|
||||
'''
|
||||
Mouse hover callback.
|
||||
|
||||
"""
|
||||
'''
|
||||
cur = self._chart.linked.cursor
|
||||
|
||||
# hovered
|
||||
|
@ -614,7 +602,8 @@ def order_line(
|
|||
**line_kwargs,
|
||||
|
||||
) -> 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".
|
||||
|
||||
'''
|
||||
|
@ -689,7 +678,6 @@ def order_line(
|
|||
|
||||
return f'{account}: '
|
||||
|
||||
|
||||
label.fields = {
|
||||
'size': size,
|
||||
'size_digits': 0,
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
# 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/>.
|
||||
|
||||
"""
|
||||
'''
|
||||
Qt UI styling.
|
||||
"""
|
||||
|
||||
'''
|
||||
from typing import Optional, Dict
|
||||
import math
|
||||
|
||||
|
@ -202,8 +203,6 @@ _xaxis_at = 'bottom'
|
|||
# charting config
|
||||
CHART_MARGINS = (0, 0, 2, 2)
|
||||
_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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue