Skip to content

Commit

Permalink
Merge pull request #258 from pikers/fsp_ui_mod
Browse files Browse the repository at this point in the history
Fsp UI mod
  • Loading branch information
goodboy authored Jan 25, 2022
2 parents 05b8e3a + 9813cf4 commit a40e949
Show file tree
Hide file tree
Showing 8 changed files with 1,029 additions and 734 deletions.
32 changes: 32 additions & 0 deletions piker/data/_sharedmem.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,35 @@ def maybe_open_shm_array(
# to fail if a block has been allocated
# on the OS by someone else.
return open_shm_array(key=key, dtype=dtype, **kwargs), True


def try_read(
array: np.ndarray

) -> Optional[np.ndarray]:
'''
Try to read the last row from a shared mem array or ``None``
if the array read returns a zero-length array result.
Can be used to check for backfilling race conditions where an array
is currently being (re-)written by a writer actor but the reader is
unaware and reads during the window where the first and last indexes
are being updated.
'''
try:
return array[-1]
except IndexError:
# XXX: race condition with backfilling shm.
#
# the underlying issue is that a backfill (aka prepend) and subsequent
# shm array first/last index update could result in an empty array
# read here since the indices may be updated in such a way that
# a read delivers an empty array (though it seems like we
# *should* be able to prevent that?). also, as and alt and
# something we need anyway, maybe there should be some kind of
# signal that a prepend is taking place and this consumer can
# respond (eg. redrawing graphics) accordingly.

# the array read was emtpy
return None
12 changes: 12 additions & 0 deletions piker/data/_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ def nearest_tick(self, value: float) -> float:
mult = 1 / self.tick_size
return round(value * mult) / mult

def front_feed(self) -> tuple[str, str]:
'''
Return the "current" feed key for this symbol.
(i.e. the broker + symbol key in a tuple).
'''
return (
list(self.broker_info.keys())[0],
self.key,
)


@validate_arguments
def mk_symbol(
Expand Down
6 changes: 4 additions & 2 deletions piker/fsp/_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,17 @@ async def fsp_compute(
async def cascade(

ctx: tractor.Context,

# data feed key
brokername: str,
symbol: str,

src_shm_token: dict,
dst_shm_token: tuple[str, np.dtype],

symbol: str,
func_name: str,
zero_on_step: bool = False,

zero_on_step: bool = False,
loglevel: Optional[str] = None,

) -> None:
Expand Down
168 changes: 79 additions & 89 deletions piker/ui/_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
'''
from __future__ import annotations
from functools import partial
from dataclasses import dataclass
from typing import Optional

from PyQt5 import QtCore, QtWidgets
Expand Down Expand Up @@ -383,8 +381,9 @@ def plot_ohlc_main(

style: str = 'bar',

) -> 'ChartPlotWidget':
'''Start up and show main (price) chart and all linked subcharts.
) -> ChartPlotWidget:
'''
Start up and show main (price) chart and all linked subcharts.
The data input struct array must include OHLC fields.
Expand Down Expand Up @@ -537,7 +536,7 @@ def add_plot(
)
self.cursor.contents_labels.add_label(
cpw,
'ohlc',
name,
anchor_at=('top', 'left'),
update_func=ContentsLabel.update_from_ohlc,
)
Expand Down Expand Up @@ -611,11 +610,11 @@ def resize_sidepanes(

# import pydantic

# class ArrayScene(pydantic.BaseModel):
# class Graphics(pydantic.BaseModel):
# '''
# Data-AGGRegate: high level API onto multiple (categorized)
# ``ShmArray``s with high level processing routines mostly for
# graphics summary and display.
# ``ShmArray``s with high level processing routines for
# graphics computations and display.

# '''
# arrays: dict[str, np.ndarray] = {}
Expand Down Expand Up @@ -738,7 +737,7 @@ def __init__(
self.default_view()
self.cv.enable_auto_yrange()

self.overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem)
self.pi_overlay: PlotItemOverlay = PlotItemOverlay(self.plotItem)

def resume_all_feeds(self):
for feed in self._feeds.values():
Expand Down Expand Up @@ -849,7 +848,7 @@ def draw_ohlc(

# adds all bar/candle graphics objects for each data point in
# the np array buffer to be drawn on next render cycle
self.addItem(graphics)
self.plotItem.addItem(graphics)

# draw after to allow self.scene() to work...
graphics.draw_from_data(data)
Expand All @@ -860,6 +859,57 @@ def draw_ohlc(

return graphics, data_key

def overlay_plotitem(
self,
name: str,

) -> pg.PlotItem:
# Custom viewbox impl
cv = self.mk_vb(name)
cv.chart = self

# xaxis = DynamicDateAxis(
# orientation='bottom',
# linkedsplits=self.linked,
# )
yaxis = PriceAxis(
orientation='right',
linkedsplits=self.linked,
)

plotitem = pg.PlotItem(
parent=self.plotItem,
name=name,
enableMenu=False,
viewBox=cv,
axisItems={
# 'bottom': xaxis,
'right': yaxis,
},
default_axes=[],
)
# plotitem.setAxisItems(
# add_to_layout=False,
# axisItems={
# 'bottom': xaxis,
# 'right': yaxis,
# },
# )
# plotite.hideAxis('right')
# plotite.hideAxis('bottom')
# plotitem.addItem(curve)
cv.enable_auto_yrange()

# plotitem.enableAutoRange(axis='y')
plotitem.hideButtons()

self.pi_overlay.add_plotitem(
plotitem,
# only link x-axes,
link_axes=(0,),
)
return plotitem

def draw_curve(
self,

Expand All @@ -868,7 +918,6 @@ def draw_curve(

array_key: Optional[str] = None,
overlay: bool = False,
separate_axes: bool = False,
color: Optional[str] = None,
add_label: bool = True,

Expand Down Expand Up @@ -907,11 +956,11 @@ def draw_curve(
**pdi_kwargs,
)

# XXX: see explanation for differenct caching modes:
# XXX: see explanation for different caching modes:
# https://stackoverflow.com/a/39410081
# seems to only be useful if we don't re-generate the entire
# QPainterPath every time
# curve.curve.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)
# curve.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)

# don't ever use this - it's a colossal nightmare of artefacts
# and is disastrous for performance.
Expand All @@ -921,83 +970,28 @@ def draw_curve(
self._graphics[name] = curve
self._arrays[data_key] = data

pi = self.plotItem

# TODO: this probably needs its own method?
if overlay:
# anchor_at = ('bottom', 'left')
self._overlays[name] = None

if separate_axes:

# Custom viewbox impl
cv = self.mk_vb(name)

def maxmin():
return self.maxmin(name=data_key)
if isinstance(overlay, pg.PlotItem):
if overlay not in self.pi_overlay.overlays:
raise RuntimeError(
f'{overlay} must be from `.plotitem_overlay()`'
)
pi = overlay

# ensure view maxmin is computed from correct array
# cv._maxmin = partial(self.maxmin, name=data_key)

cv._maxmin = maxmin

cv.chart = self

# xaxis = DynamicDateAxis(
# orientation='bottom',
# linkedsplits=self.linked,
# )
yaxis = PriceAxis(
orientation='right',
linkedsplits=self.linked,
)

plotitem = pg.PlotItem(
parent=self.plotItem,
name=name,
enableMenu=False,
viewBox=cv,
axisItems={
# 'bottom': xaxis,
'right': yaxis,
},
default_axes=[],
)
# plotitem.setAxisItems(
# add_to_layout=False,
# axisItems={
# 'bottom': xaxis,
# 'right': yaxis,
# },
# )
# plotite.hideAxis('right')
# plotite.hideAxis('bottom')
plotitem.addItem(curve)
cv.enable_auto_yrange()

# config
# plotitem.setAutoVisible(y=True)
# plotitem.enableAutoRange(axis='y')
plotitem.hideButtons()

self.overlay.add_plotitem(
plotitem,
# only link x-axes,
link_axes=(0,),
)

else:
# this intnernally calls `PlotItem.addItem()` on the
# graphics object
self.addItem(curve)
else:
# this intnernally calls `PlotItem.addItem()` on the
# graphics object
self.addItem(curve)

# anchor_at = ('top', 'left')

# TODO: something instead of stickies for overlays
# (we need something that avoids clutter on x-axis).
self._add_sticky(name, bg_color=color)

pi.addItem(curve)
return curve, data_key

# TODO: make this a ctx mngr
Expand Down Expand Up @@ -1036,7 +1030,8 @@ def update_ohlc_from_array(
**kwargs,

) -> pg.GraphicsObject:
'''Update the named internal graphics from ``array``.
'''
Update the named internal graphics from ``array``.
'''
self._arrays[self.name] = array
Expand All @@ -1053,7 +1048,8 @@ def update_curve_from_array(
**kwargs,

) -> pg.GraphicsObject:
'''Update the named internal graphics from ``array``.
'''
Update the named internal graphics from ``array``.
'''
assert len(array)
Expand Down Expand Up @@ -1123,7 +1119,7 @@ def leaveEvent(self, ev): # noqa
def get_index(self, time: float) -> int:

# TODO: this should go onto some sort of
# data-view strimg thinger..right?
# data-view thinger..right?
ohlc = self._shm.array

# XXX: not sure why the time is so off here
Expand Down Expand Up @@ -1178,15 +1174,9 @@ def maxmin(
yhigh = np.nanmax(bars['high'])

else:
try:
view = bars[name or self.data_key]
except:
breakpoint()
# if self.data_key != 'volume':
# else:
# view = bars
view = bars[name or self.data_key]
ylow = np.nanmin(view)
yhigh = np.nanmax(view)
# print(f'{(ylow, yhigh)}')

# print(f'{(ylow, yhigh)}')
return ylow, yhigh
Loading

0 comments on commit a40e949

Please sign in to comment.