|
@@ -28,7 +28,8 @@ from ..widgets import (
|
|
|
AutoCompleteFloatEdit,
|
|
|
FocusWidget,
|
|
|
AutoCompletePopUp,
|
|
|
- NoTabCheckBox
|
|
|
+ NoTabCheckBox,
|
|
|
+ FlowBarGraphWithVScale,
|
|
|
)
|
|
|
from ..db_utils import QueryManager
|
|
|
from . import ActivityManager, show_or_exit
|
|
@@ -91,13 +92,47 @@ class PriceCheck(FocusWidget):
|
|
|
cb.set_state('mixed')
|
|
|
for (_, tf) in self.text_fields.items():
|
|
|
tf.set_text('')
|
|
|
- self.update()
|
|
|
- return self
|
|
|
+ self.graph.set_data([],0)
|
|
|
+ return self.update()
|
|
|
|
|
|
def update(self):
|
|
|
self.update_historic_prices(self.data)
|
|
|
return self
|
|
|
|
|
|
+ def update_graph(self, df):
|
|
|
+ # after truncating, need to recalculate avg(median), min, max
|
|
|
+ df = df.sort_values(
|
|
|
+ 'ts_raw', ascending=True, ignore_index=True
|
|
|
+ ).truncate(
|
|
|
+ before=max(0, len(df.index)-self.graph._canvas_width)
|
|
|
+ )
|
|
|
+ data = df[['$/unit','quantity']].apply(
|
|
|
+ lambda x: (float(x['$/unit']), float(x['quantity'])),
|
|
|
+ axis=1, result_type='broadcast'
|
|
|
+ )
|
|
|
+ data['avg'] = (data['$/unit']*data['quantity']).sum()/data['quantity'].sum()
|
|
|
+ data_max = data.max()['$/unit'] #.max()
|
|
|
+ assert len(data['avg'].unique()) == 1
|
|
|
+ norm = [ (x,) for x in data['$/unit'] ] #.to_records(index=False)
|
|
|
+ self.graph.set_data(norm, data_max,
|
|
|
+ vscale=[x for x in map(float, [
|
|
|
+ data['$/unit'].min(),
|
|
|
+ data['$/unit'].median(),
|
|
|
+ data['avg'].iloc[0],
|
|
|
+ data_max
|
|
|
+ ])]
|
|
|
+ )
|
|
|
+ #self.graph.set_bar_width(1)
|
|
|
+ # canvas_width = 10 + pad + pad + 10
|
|
|
+ date_strlen = (self.graph.canvas_width - 20)
|
|
|
+ ex = "─" if date_strlen % 2 else ""
|
|
|
+ plen = date_strlen//2
|
|
|
+ caption = f"{df['ts_raw'].min():%d/%m/%Y}"
|
|
|
+ caption += f"{{p:>{plen}}}{ex}{{p:<{plen}}}".format(
|
|
|
+ p="─")
|
|
|
+ caption += f"{df['ts_raw'].max():%d/%m/%Y}"
|
|
|
+ self.graph.set_caption(caption)
|
|
|
+
|
|
|
def update_historic_prices(self, data):
|
|
|
organic = None if data['organic'] == 'mixed' else data['organic']
|
|
|
sort = '$/unit' if self.buttons['sort_price'].state else 'ts'
|
|
@@ -133,6 +168,7 @@ class PriceCheck(FocusWidget):
|
|
|
self.text_fields['dbview'].set_text(
|
|
|
self.rating.get_historic_prices(df)
|
|
|
)
|
|
|
+ self.update_graph(df)
|
|
|
|
|
|
def __init__(self,
|
|
|
activity_manager: ActivityManager,
|
|
@@ -180,7 +216,7 @@ class PriceCheck(FocusWidget):
|
|
|
'quantity',
|
|
|
'price',
|
|
|
]
|
|
|
- bottom_pane = [ 'dbview', ]
|
|
|
+ bottom_pane = [ 'graph', 'dbview', ]
|
|
|
|
|
|
self.query_manager = query_manager
|
|
|
self.organic_checkbox = self.checkboxes['organic']
|
|
@@ -194,7 +230,11 @@ class PriceCheck(FocusWidget):
|
|
|
|
|
|
connect_signal(self.buttons['clear'], 'click', lambda x: self.clear().update())
|
|
|
connect_signal(self.buttons['exit'], 'click', lambda x: show_or_exit('esc'))
|
|
|
-
|
|
|
+ self.graph = FlowBarGraphWithVScale(
|
|
|
+ 50, 14,
|
|
|
+ ['bg','popup_focus', 'badge_neutral' ],
|
|
|
+ hatt=['dark red', 'dark red', 'dark red']
|
|
|
+ )
|
|
|
|
|
|
self.clear()
|
|
|
|
|
@@ -222,6 +262,7 @@ class PriceCheck(FocusWidget):
|
|
|
), 'streak'), title=k.title(), title_align='left')
|
|
|
) for k in self.edit_fields
|
|
|
])
|
|
|
+
|
|
|
_widgets.update({
|
|
|
'dbview': LineBox(
|
|
|
AttrMap(self.text_fields['dbview'], 'streak'),
|
|
@@ -259,8 +300,16 @@ class PriceCheck(FocusWidget):
|
|
|
lambda x: _widgets[x] if x is not None else Divider,
|
|
|
badge
|
|
|
)),
|
|
|
- 'bottom_pane': _widgets['dbview'],
|
|
|
}
|
|
|
+ _widgets.update({
|
|
|
+ 'graph': LineBox(
|
|
|
+ self.graph,
|
|
|
+ title="Historic Price", title_align='left'
|
|
|
+ ),
|
|
|
+ })
|
|
|
+ components.update({
|
|
|
+ 'bottom_pane': [ _widgets['graph'], _widgets['dbview'] ],
|
|
|
+ })
|
|
|
components.update({
|
|
|
'left_pane': Pile([
|
|
|
components['left_pane'],
|
|
@@ -277,7 +326,7 @@ class PriceCheck(FocusWidget):
|
|
|
Columns((components['left_pane'], components['right_pane']),
|
|
|
dividechars=0,
|
|
|
),
|
|
|
- components['bottom_pane'],
|
|
|
+ Pile(components['bottom_pane']),
|
|
|
])
|
|
|
widget = Filler(widget, 'top')
|
|
|
widget = AttrMap(widget, 'bg')
|