Add proper x-axis time-stamping
parent
30d8e096c6
commit
0f6589d9ff
|
@ -1,12 +1,17 @@
|
||||||
"""
|
"""
|
||||||
Chart axes graphics and behavior.
|
Chart axes graphics and behavior.
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
|
from functools import partial
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
# import numpy as np
|
||||||
|
import pandas as pd
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from PyQt5 import QtCore, QtGui
|
from PyQt5 import QtCore, QtGui
|
||||||
from PyQt5.QtCore import QPointF
|
from PyQt5.QtCore import QPointF
|
||||||
|
|
||||||
|
|
||||||
# from .quantdom.base import Quotes
|
|
||||||
from .quantdom.utils import fromtimestamp
|
from .quantdom.utils import fromtimestamp
|
||||||
from ._style import _font, hcolor
|
from ._style import _font, hcolor
|
||||||
|
|
||||||
|
@ -15,7 +20,6 @@ class PriceAxis(pg.AxisItem):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
# chart: 'ChartPlotWidget',
|
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(orientation='right')
|
super().__init__(orientation='right')
|
||||||
self.setStyle(**{
|
self.setStyle(**{
|
||||||
|
@ -28,10 +32,7 @@ class PriceAxis(pg.AxisItem):
|
||||||
})
|
})
|
||||||
self.setLabel(**{'font-size': '10pt'})
|
self.setLabel(**{'font-size': '10pt'})
|
||||||
self.setTickFont(_font)
|
self.setTickFont(_font)
|
||||||
self.setWidth(150)
|
self.setWidth(125)
|
||||||
# self.chart = chart
|
|
||||||
# accesed normally via
|
|
||||||
# .getAxis('right')
|
|
||||||
|
|
||||||
# XXX: drop for now since it just eats up h space
|
# XXX: drop for now since it just eats up h space
|
||||||
|
|
||||||
|
@ -43,9 +44,20 @@ class PriceAxis(pg.AxisItem):
|
||||||
|
|
||||||
|
|
||||||
class DynamicDateAxis(pg.AxisItem):
|
class DynamicDateAxis(pg.AxisItem):
|
||||||
tick_tpl = {'D1': '%Y-%b-%d'}
|
# time formats mapped by seconds between bars
|
||||||
|
tick_tpl = {
|
||||||
|
60*60*24: '%Y-%b-%d',
|
||||||
|
60: '%H:%M',
|
||||||
|
30: '%H:%M:%S',
|
||||||
|
5: '%H:%M:%S',
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, linked_charts, *args, **kwargs):
|
def __init__(
|
||||||
|
self,
|
||||||
|
linked_charts,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.linked_charts = linked_charts
|
self.linked_charts = linked_charts
|
||||||
self.setTickFont(_font)
|
self.setTickFont(_font)
|
||||||
|
@ -59,24 +71,25 @@ class DynamicDateAxis(pg.AxisItem):
|
||||||
)
|
)
|
||||||
# self.setHeight(35)
|
# self.setHeight(35)
|
||||||
|
|
||||||
def tickStrings(self, values, scale, spacing):
|
def _indexes_to_timestrs(
|
||||||
# if len(values) > 1 or not values:
|
self,
|
||||||
# values = Quotes.time
|
indexes: List[int],
|
||||||
|
) -> List[str]:
|
||||||
# strings = super().tickStrings(values, scale, spacing)
|
|
||||||
s_period = 'D1'
|
|
||||||
strings = []
|
|
||||||
bars = self.linked_charts.chart._array
|
bars = self.linked_charts.chart._array
|
||||||
quotes_count = len(bars) - 1
|
times = bars['time']
|
||||||
|
bars_len = len(bars)
|
||||||
|
delay = times[-1] - times[times != times[-1]][-1]
|
||||||
|
|
||||||
for ibar in values:
|
epochs = times[list(
|
||||||
if ibar > quotes_count:
|
map(int, filter(lambda i: i < bars_len, indexes))
|
||||||
return strings
|
)]
|
||||||
dt_tick = fromtimestamp(bars[int(ibar)]['time'])
|
# TODO: **don't** have this hard coded shift to EST
|
||||||
strings.append(
|
dts = pd.to_datetime(epochs, unit='s') - 4*pd.offsets.Hour()
|
||||||
dt_tick.strftime(self.tick_tpl[s_period])
|
return dts.strftime(self.tick_tpl[delay])
|
||||||
)
|
|
||||||
return strings
|
|
||||||
|
def tickStrings(self, values: List[float], scale, spacing):
|
||||||
|
return self._indexes_to_timestrs(values)
|
||||||
|
|
||||||
|
|
||||||
class AxisLabel(pg.GraphicsObject):
|
class AxisLabel(pg.GraphicsObject):
|
||||||
|
@ -88,7 +101,7 @@ class AxisLabel(pg.GraphicsObject):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent=None,
|
parent=None,
|
||||||
digits=1,
|
digits=2,
|
||||||
color=None,
|
color=None,
|
||||||
opacity=1,
|
opacity=1,
|
||||||
**kwargs
|
**kwargs
|
||||||
|
@ -128,6 +141,7 @@ class AxisLabel(pg.GraphicsObject):
|
||||||
p.drawText(option.rect, self.text_flags, self.label_str)
|
p.drawText(option.rect, self.text_flags, self.label_str)
|
||||||
|
|
||||||
# uggggghhhh
|
# uggggghhhh
|
||||||
|
|
||||||
def tick_to_string(self, tick_pos):
|
def tick_to_string(self, tick_pos):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -160,24 +174,20 @@ class XAxisLabel(AxisLabel):
|
||||||
)
|
)
|
||||||
# text_flags = _common_text_flags
|
# text_flags = _common_text_flags
|
||||||
|
|
||||||
def tick_to_string(self, tick_pos):
|
|
||||||
# TODO: change to actual period
|
|
||||||
tpl = self.parent.tick_tpl['D1']
|
|
||||||
bars = self.parent.linked_charts.chart._array
|
|
||||||
if tick_pos > len(bars):
|
|
||||||
return 'Unknown Time'
|
|
||||||
return fromtimestamp(bars[round(tick_pos)]['time']).strftime(tpl)
|
|
||||||
|
|
||||||
def boundingRect(self): # noqa
|
def boundingRect(self): # noqa
|
||||||
return QtCore.QRectF(0, 0, 145, 40)
|
# TODO: we need to get the parent axe's dimensions transformed
|
||||||
|
# to abs coords to be 100% correct here:
|
||||||
|
# self.parent.boundingRect()
|
||||||
|
return QtCore.QRectF(0, 0, 100, 31)
|
||||||
|
|
||||||
def update_label(self, abs_pos, data):
|
def update_label(
|
||||||
# ibar = view_pos.x()
|
self,
|
||||||
# if ibar > self.quotes_count:
|
abs_pos: QPointF, # scene coords
|
||||||
# return
|
data: float, # data for text
|
||||||
self.label_str = self.tick_to_string(data)
|
offset: int = 0 # if have margins, k?
|
||||||
|
) -> None:
|
||||||
|
self.label_str = self.parent._indexes_to_timestrs([int(data)])[0]
|
||||||
width = self.boundingRect().width()
|
width = self.boundingRect().width()
|
||||||
offset = 0 # if have margins
|
|
||||||
new_pos = QPointF(abs_pos.x() - width / 2 - offset, 0)
|
new_pos = QPointF(abs_pos.x() - width / 2 - offset, 0)
|
||||||
self.setPos(new_pos)
|
self.setPos(new_pos)
|
||||||
|
|
||||||
|
@ -202,10 +212,10 @@ class YAxisLabel(AxisLabel):
|
||||||
self,
|
self,
|
||||||
abs_pos: QPointF, # scene coords
|
abs_pos: QPointF, # scene coords
|
||||||
data: float, # data for text
|
data: float, # data for text
|
||||||
|
offset: int = 0 # if have margins, k?
|
||||||
) -> None:
|
) -> None:
|
||||||
self.label_str = self.tick_to_string(data)
|
self.label_str = self.tick_to_string(data)
|
||||||
height = self.boundingRect().height()
|
height = self.boundingRect().height()
|
||||||
offset = 0 # if have margins
|
|
||||||
new_pos = QPointF(0, abs_pos.y() - height / 2 - offset)
|
new_pos = QPointF(0, abs_pos.y() - height / 2 - offset)
|
||||||
self.setPos(new_pos)
|
self.setPos(new_pos)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue