Merge pull request #157 from pikers/lo_dpi

Hip shot: try making low dpi "just work"
readme_bumpz
goodboy 2021-04-01 09:31:10 -04:00 committed by GitHub
commit 4a590edcc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 111 additions and 89 deletions

View File

@ -18,8 +18,8 @@
Chart axes graphics and behavior. Chart axes graphics and behavior.
""" """
from typing import List, Tuple, Optional from typing import List, Tuple, Optional
from math import floor
import pandas as pd import pandas as pd
import pyqtgraph as pg import pyqtgraph as pg
@ -51,13 +51,24 @@ class Axis(pg.AxisItem):
self.linked_charts = linked_charts self.linked_charts = linked_charts
self._min_tick = min_tick self._min_tick = min_tick
self._dpi_font = _font
self.setTickFont(_font.font) self.setTickFont(_font.font)
font_size = self._dpi_font.font.pixelSize()
if self.orientation in ('bottom',):
text_offset = floor(0.25 * font_size)
elif self.orientation in ('left', 'right'):
text_offset = floor(font_size / 2)
self.setStyle(**{ self.setStyle(**{
'textFillLimits': [(0, 0.5)], 'textFillLimits': [(0, 0.5)],
'tickFont': _font.font, 'tickFont': self._dpi_font.font,
# offset of text *away from* axis line in px # offset of text *away from* axis line in px
'tickTextOffset': 6, # use approx. half the font pixel size (height)
'tickTextOffset': text_offset,
}) })
self.setTickFont(_font.font) self.setTickFont(_font.font)
@ -79,17 +90,6 @@ class Axis(pg.AxisItem):
class PriceAxis(Axis): class PriceAxis(Axis):
def __init__(
self,
*args,
**kwargs,
) -> None:
super().__init__(*args, **kwargs)
self.setStyle(**{
# offset of text *away from* axis line in px
'tickTextOffset': 9,
})
def size_to_values(self) -> None: def size_to_values(self) -> None:
self.setWidth(self.typical_br.width()) self.setWidth(self.typical_br.width())
@ -170,10 +170,10 @@ class AxisLabel(pg.GraphicsObject):
parent: pg.GraphicsItem, parent: pg.GraphicsItem,
digits: int = 2, digits: int = 2,
font_size_inches: Optional[float] = None,
bg_color: str = 'bracket', bg_color: str = 'bracket',
fg_color: str = 'black', fg_color: str = 'black',
opacity: int = 1, # XXX: seriously don't set this to 0 opacity: int = 1, # XXX: seriously don't set this to 0
font_size: str = 'default',
use_arrow: bool = True, use_arrow: bool = True,
@ -195,7 +195,7 @@ class AxisLabel(pg.GraphicsObject):
self._txt_br: QtCore.QRect = None self._txt_br: QtCore.QRect = None
self._dpifont = DpiAwareFont(size_in_inches=font_size_inches) self._dpifont = DpiAwareFont(font_size=font_size)
self._dpifont.configure_to_dpi() self._dpifont.configure_to_dpi()
self.bg_color = pg.mkColor(hcolor(bg_color)) self.bg_color = pg.mkColor(hcolor(bg_color))
@ -457,7 +457,7 @@ class YAxisLabel(AxisLabel):
path = QtGui.QPainterPath() path = QtGui.QPainterPath()
h = self.rect.height() h = self.rect.height()
path.moveTo(0, 0) path.moveTo(0, 0)
path.lineTo(-x_offset - 4, h/2.) path.lineTo(-x_offset - h/4, h/2.)
path.lineTo(0, h) path.lineTo(0, h)
path.closeSubpath() path.closeSubpath()
self.path = path self.path = path

View File

@ -18,6 +18,7 @@
Mouse interaction graphics Mouse interaction graphics
""" """
import math
from typing import Optional, Tuple, Set, Dict from typing import Optional, Tuple, Set, Dict
import inspect import inspect
@ -113,10 +114,6 @@ class LineDot(pg.CurvePoint):
return False return False
# TODO: likely will need to tweak this based on dpi...
_y_margin = 5
# TODO: change this into our own ``Label`` # TODO: change this into our own ``Label``
class ContentsLabel(pg.LabelItem): class ContentsLabel(pg.LabelItem):
"""Label anchored to a ``ViewBox`` typically for displaying """Label anchored to a ``ViewBox`` typically for displaying
@ -132,11 +129,11 @@ class ContentsLabel(pg.LabelItem):
# XXX: fyi naming here is confusing / opposite to coords # XXX: fyi naming here is confusing / opposite to coords
_corner_margins = { _corner_margins = {
('top', 'left'): (-4, -_y_margin), ('top', 'left'): (-2, lambda font_size: -font_size*0.25),
('top', 'right'): (4, -_y_margin), ('top', 'right'): (2, lambda font_size: -font_size*0.25),
('bottom', 'left'): (-4, lambda font_size: font_size + 2*_y_margin), ('bottom', 'left'): (-2, lambda font_size: font_size),
('bottom', 'right'): (4, lambda font_size: font_size + 2*_y_margin), ('bottom', 'right'): (2, lambda font_size: font_size),
} }
def __init__( def __init__(
@ -147,11 +144,21 @@ class ContentsLabel(pg.LabelItem):
font_size: Optional[int] = None, font_size: Optional[int] = None,
) -> None: ) -> None:
font_size = font_size or _font.font.pixelSize() font_size = font_size or _font.font.pixelSize()
super().__init__( super().__init__(
justify=justify_text, justify=justify_text,
size=f'{str(font_size)}px' size=f'{str(font_size)}px'
) )
if _font._physical_dpi >= 97:
# ad-hoc scale it based on boundingRect
# TODO: need proper fix for this?
typical_br = _font._qfm.boundingRect('Qyp')
anchor_font_size = math.ceil(typical_br.height() * 1.25)
else:
anchor_font_size = font_size
# anchor to viewbox # anchor to viewbox
self.setParentItem(chart._vb) self.setParentItem(chart._vb)
chart.scene().addItem(self) chart.scene().addItem(self)
@ -163,7 +170,9 @@ class ContentsLabel(pg.LabelItem):
ydim = margins[1] ydim = margins[1]
if inspect.isfunction(margins[1]): if inspect.isfunction(margins[1]):
margins = margins[0], ydim(font_size) margins = margins[0], ydim(anchor_font_size)
print(f'margins: {margins}')
self.anchor(itemPos=index, parentPos=index, offset=margins) self.anchor(itemPos=index, parentPos=index, offset=margins)
@ -385,13 +394,12 @@ class Cursor(pg.GraphicsObject):
if self._y_label_update: if self._y_label_update:
self.graphics[self.active_plot]['yl'].update_label( self.graphics[self.active_plot]['yl'].update_label(
abs_pos=plot.mapFromView(QPointF(ix, iy + line_offset)), abs_pos=plot.mapFromView(QPointF(ix, iy)),
value=iy value=iy
) )
# only update horizontal xhair line if label is enabled # only update horizontal xhair line if label is enabled
self.graphics[plot]['hl'].setY(iy + line_offset) self.graphics[plot]['hl'].setY(iy)
# update all trackers # update all trackers
for item in self._trackers: for item in self._trackers:

View File

@ -18,6 +18,7 @@
Lines for orders, alerts, L2. Lines for orders, alerts, L2.
""" """
from math import floor
from typing import Tuple, Optional, List from typing import Tuple, Optional, List
import pyqtgraph as pg import pyqtgraph as pg
@ -27,10 +28,7 @@ from PyQt5.QtCore import QPointF
from .._annotate import mk_marker, qgo_draw_markers from .._annotate import mk_marker, qgo_draw_markers
from .._label import Label, vbr_left, right_axis from .._label import Label, vbr_left, right_axis
from .._style import ( from .._style import hcolor, _font
hcolor,
_down_2_font_inches_we_like,
)
# TODO: probably worth investigating if we can # TODO: probably worth investigating if we can
@ -157,7 +155,6 @@ class LevelLine(pg.InfiniteLine):
side_of_axis: str = 'left', side_of_axis: str = 'left',
x_offset: float = 0, x_offset: float = 0,
font_size_inches: float = _down_2_font_inches_we_like,
color: str = None, color: str = None,
bg_color: str = None, bg_color: str = None,
avoid_book: bool = True, avoid_book: bool = True,
@ -535,9 +532,6 @@ def level_line(
level: float, level: float,
color: str = 'default', color: str = 'default',
# size 4 font on 4k screen scaled down, so small-ish.
font_size_inches: float = _down_2_font_inches_we_like,
# whether or not the line placed in view should highlight # whether or not the line placed in view should highlight
# when moused over (aka "hovered") # when moused over (aka "hovered")
hl_on_hover: bool = True, hl_on_hover: bool = True,
@ -635,11 +629,17 @@ def order_line(
) )
if show_markers: if show_markers:
font_size = _font.font.pixelSize()
# scale marker size with dpi-aware font size
arrow_size = floor(1.375 * font_size)
alert_size = arrow_size * 0.666
# add arrow marker on end of line nearest y-axis # add arrow marker on end of line nearest y-axis
marker_style, marker_size = { marker_style, marker_size = {
'buy': ('|<', 20), 'buy': ('|<', arrow_size),
'sell': ('>|', 20), 'sell': ('>|', arrow_size),
'alert': ('v', 12), 'alert': ('v', alert_size),
}[action] }[action]
# this fixes it the artifact issue! .. of course, bouding rect stuff # this fixes it the artifact issue! .. of course, bouding rect stuff
@ -682,27 +682,27 @@ def order_line(
llabel.show() llabel.show()
else: else:
# left side label # # left side label
llabel = line.add_label( # llabel = line.add_label(
side='left', # side='left',
fmt_str=' {exec_type}-{order_type}:\n ${$value}', # fmt_str=' {exec_type}-{order_type}:\n ${$value}',
) # )
llabel.fields = { # llabel.fields = {
'order_type': order_type, # 'order_type': order_type,
'level': level, # 'level': level,
'$value': lambda f: f['level'] * f['size'], # '$value': lambda f: f['level'] * f['size'],
'size': size, # 'size': size,
'exec_type': exec_type, # 'exec_type': exec_type,
} # }
llabel.orient_v = orient_v # llabel.orient_v = orient_v
llabel.render() # llabel.render()
llabel.show() # llabel.show()
# right before L1 label # right before L1 label
rlabel = line.add_label( rlabel = line.add_label(
side='right', side='right',
side_of_axis='left', side_of_axis='left',
x_offset=3*marker_size + 5, x_offset=4*marker_size,
fmt_str=( fmt_str=(
'{size:.{size_digits}f} ' '{size:.{size_digits}f} '
), ),
@ -746,14 +746,6 @@ def position_line(
hide_xhair_on_hover=False, hide_xhair_on_hover=False,
use_marker_margin=True, use_marker_margin=True,
) )
if size > 0:
arrow_path = mk_marker('|<')
elif size < 0:
arrow_path = mk_marker('>|')
line.add_marker(arrow_path)
# hide position marker when out of view (for now) # hide position marker when out of view (for now)
vb = line.getViewBox() vb = line.getViewBox()
@ -770,7 +762,7 @@ def position_line(
vb.sigYRangeChanged.connect(update_pp_nav) vb.sigYRangeChanged.connect(update_pp_nav)
rlabel = line.add_label( rlabel = line.add_label(
side='left', side='right',
fmt_str='{direction}: {size} -> ${$:.2f}', fmt_str='{direction}: {size} -> ${$:.2f}',
) )
rlabel.fields = { rlabel.fields = {
@ -782,6 +774,20 @@ def position_line(
rlabel.render() rlabel.render()
rlabel.show() rlabel.show()
# arrow marker
# scale marker size with dpi-aware font size
font_size = _font.font.pixelSize()
# scale marker size with dpi-aware font size
arrow_size = floor(1.375 * font_size)
if size > 0:
style = '|<'
elif size < 0:
style = '>|'
arrow_path = mk_marker(style, size=arrow_size)
line.add_marker(arrow_path)
line.set_level(level) line.set_level(level)
# sanity check # sanity check

View File

@ -429,11 +429,14 @@ class ArrowEditor:
None: 180, # pointing to right (as in an alert) None: 180, # pointing to right (as in an alert)
}[pointing] }[pointing]
# scale arrow sizing to dpi-aware font
size = _font.font.pixelSize() * 0.8
arrow = pg.ArrowItem( arrow = pg.ArrowItem(
angle=angle, angle=angle,
baseAngle=0, baseAngle=0,
headLen=5*3, headLen=size,
headWidth=2*3, headWidth=size/2,
tailLen=None, tailLen=None,
pxMode=True, pxMode=True,

View File

@ -25,10 +25,7 @@ from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QPointF from PyQt5.QtCore import QPointF
from ._axes import YAxisLabel from ._axes import YAxisLabel
from ._style import ( from ._style import hcolor
hcolor,
_down_2_font_inches_we_like,
)
class LevelLabel(YAxisLabel): class LevelLabel(YAxisLabel):
@ -248,7 +245,7 @@ class L1Labels:
chart: 'ChartPlotWidget', # noqa chart: 'ChartPlotWidget', # noqa
digits: int = 2, digits: int = 2,
size_digits: int = 3, size_digits: int = 3,
font_size_inches: float = _down_2_font_inches_we_like, font_size: str = 'small',
) -> None: ) -> None:
self.chart = chart self.chart = chart
@ -259,7 +256,7 @@ class L1Labels:
'parent': raxis, 'parent': raxis,
'opacity': 1, 'opacity': 1,
'font_size_inches': font_size_inches, 'font_size': font_size,
'fg_color': chart.pen_color, 'fg_color': chart.pen_color,
'bg_color': chart.view_color, 'bg_color': chart.view_color,
} }

View File

@ -28,7 +28,6 @@ from PyQt5.QtCore import QPointF, QRectF
from ._style import ( from ._style import (
DpiAwareFont, DpiAwareFont,
hcolor, hcolor,
_down_2_font_inches_we_like,
) )
@ -108,7 +107,7 @@ class Label:
fmt_str: str, fmt_str: str,
color: str = 'bracket', color: str = 'bracket',
x_offset: float = 0, x_offset: float = 0,
font_size_inches: float = _down_2_font_inches_we_like, font_size: str = 'small',
opacity: float = 0.666, opacity: float = 0.666,
fields: dict = {} fields: dict = {}
@ -125,7 +124,7 @@ class Label:
# configure font size based on DPI # configure font size based on DPI
dpi_font = DpiAwareFont( dpi_font = DpiAwareFont(
size_in_inches=font_size_inches font_size=font_size,
) )
dpi_font.configure_to_dpi() dpi_font.configure_to_dpi()
txt.setFont(dpi_font.font) txt.setFont(dpi_font.font)

View File

@ -17,7 +17,7 @@
""" """
Qt UI styling. Qt UI styling.
""" """
from typing import Optional from typing import Optional, Dict
import math import math
import pyqtgraph as pg import pyqtgraph as pg
@ -30,11 +30,16 @@ from ._exec import current_screen
log = get_logger(__name__) log = get_logger(__name__)
# chart-wide fonts specified in inches # chart-wide fonts specified in inches
_default_font_inches_we_like_low_dpi = 6 / 64 _font_sizes: Dict[str, Dict[str, float]] = {
_down_2_font_inches_we_like_low_dpi = 4 / 64 'hi': {
'default': 0.0616,
_default_font_inches_we_like = 0.0616 # 5 / 96 'small': 0.055,
_down_2_font_inches_we_like = 0.055 # 4 / 96 },
'lo': {
'default': 6.5 / 64,
'small': 6 / 64,
},
}
class DpiAwareFont: class DpiAwareFont:
@ -42,11 +47,13 @@ class DpiAwareFont:
self, self,
# TODO: move to config # TODO: move to config
name: str = 'Hack', name: str = 'Hack',
size_in_inches: Optional[float] = None, font_size: str = 'default',
# size_in_inches: Optional[float] = None,
) -> None: ) -> None:
self.name = name self.name = name
self._qfont = QtGui.QFont(name) self._qfont = QtGui.QFont(name)
self._iwl = size_in_inches or _default_font_inches_we_like # self._iwl = size_in_inches or _default_font_inches_we_like
self._font_size: str = font_size
self._qfm = QtGui.QFontMetrics(self._qfont) self._qfm = QtGui.QFontMetrics(self._qfont)
self._physical_dpi = None self._physical_dpi = None
self._screen = None self._screen = None
@ -91,10 +98,12 @@ class DpiAwareFont:
dpi = max(pdpi, ldpi) dpi = max(pdpi, ldpi)
# for low dpi scale everything down # for low dpi scale everything down
if dpi <= 96: if dpi <= 97:
self._iwl = _default_font_inches_we_like_low_dpi inches = _font_sizes['lo'][self._font_size]
else:
inches = _font_sizes['hi'][self._font_size]
font_size = math.floor(self._iwl * dpi) font_size = math.floor(inches * dpi)
log.info( log.info(
f"\nscreen:{screen.name()} with DPI: {dpi}" f"\nscreen:{screen.name()} with DPI: {dpi}"
f"\nbest font size is {font_size}\n" f"\nbest font size is {font_size}\n"
@ -133,8 +142,8 @@ _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_from_right_in_follow_mode = int(130) _bars_to_left_in_follow_mode = int(61*6)
_bars_to_left_in_follow_mode = int(616) _bars_from_right_in_follow_mode = round(0.16 * _bars_to_left_in_follow_mode)
_tina_mode = False _tina_mode = False