Jelajahi Sumber

improve box plot by using colors instead of borders

Daniel Sheffield 3 tahun lalu
induk
melakukan
5dc395a657
2 mengubah file dengan 45 tambahan dan 33 penghapusan
  1. 39 33
      app/activities/PriceCheck.py
  2. 6 0
      price_check.py

+ 39 - 33
app/activities/PriceCheck.py

@@ -23,10 +23,10 @@ class PriceCheck(FocusWidget):
     def keypress(self, size, key):
         if isinstance(key, tuple):
             return
-        
+
         if getattr(self.original_widget.original_widget, 'original_widget', None) is None:
             return super().keypress(size, key)
-        
+
         if key == 'tab':
             self.advance_focus()
         elif key == 'shift tab':
@@ -45,7 +45,7 @@ class PriceCheck(FocusWidget):
 
     def apply_changes(self, name, value):
         if name in self.data:
-            
+
             self.data.update({
                 name: value,
             })
@@ -62,19 +62,19 @@ class PriceCheck(FocusWidget):
         self.text_fields['marker'].set_text('')
         self.update()
         return self
-    
+
     def update(self):
         for k in self.edit_fields:
             if self.data[k] != self.edit_fields[k].get_edit_text():
                 self.edit_fields[k].set_edit_text(self.data[k])
-        
+
         if self.data['organic'] != self.organic_checkbox.state:
             self.organic_checkbox.set_state(self.data['organic'])
-        
+
         self.update_historic_prices()
-        
+
         return self
-    
+
     def update_rating(self, _avg, _min, _max, unit, price=None, quantity=None):
         if None in (_avg, _min, _max):
             return
@@ -84,49 +84,55 @@ class PriceCheck(FocusWidget):
         rating = [' ']*len(chars)
         _min, _max = min(_min, current or _min), max(_max, current or _max)
         ls = np.linspace(_min, _max, len(chars))
-
+        if current is not None:
+            if current <= _avg:
+                p = 'badge_good'
+            else:
+                p = 'badge_bad'
+        else:
+            p = 'badge_neutral'
         for idx, (e, a) in enumerate(zip(ls, ls[1:])):
-            if e <= _avg < a:
-                for c, (_idx,_) in zip('[{}]'.format(''.join(list(f'{_avg:>5.2f}')[:idx-3+5])), filter(lambda x: idx-3 < x[0], enumerate(chars))):
-                    chars[_idx] = c
+            if e <= _avg <= a:
+                for c, (_idx,_) in zip(''.join(list(f'{_avg:>5.2f}')[:idx+2]), filter(lambda x: idx-2 < x[0] and x[0]>0, enumerate(chars))):
+                    chars[_idx] = (p, c)
                 chars[0] = '|'
                 chars[-1] = '|'
-            
+
             if current is not None and e <= current < a:
                 rating[idx] = '^'
-        
+
         if current is not None:
             self.text_fields['rating'].set_text(f"{current:>5.2f}/{unit} {current/_avg - 1:>4.0%}")
-        
+
         if _min != _max:
             if current == _max:
                 rating[-1] = '^'
-            self.text_fields['spread'].set_text(f"{_min:>5.2f}{''.join(chars)}{_max:<5.2f}")
+            self.text_fields['spread'].set_text([f"{_min:>5.2f}", ('popup_focus', chars), f"{_max:<5.2f}"])
             self.text_fields['marker'].set_text(f"{' '*5}{''.join(rating)}{' '*5}")
         else:
             self.text_fields['spread'].set_text('')
             self.text_fields['marker'].set_text('')
-        
-    
+
+
     def update_historic_prices(self):
         organic = None if self.data['organic'] == 'mixed' else self.data['organic']
         sort = '$/unit' if self.buttons['sort_price'].state else 'ts'
         product, unit = self.data['product'] or None, self.data['unit'] or None
-        try: 
+        try:
             price = Decimal(self.data['price'])
         except InvalidOperation:
             price = None
-        
+
         try:
             quantity = Decimal(self.data['quantity'])
         except InvalidOperation:
             quantity = None
-        
+
         if None not in (sort, product, unit):
             self.text_fields['dbview'].set_text(
                 self.query_manager.get_historic_prices(
                     lambda *args: self.update_rating(*args, unit, price=price, quantity=quantity),
-                    sort, product, unit, organic=organic) 
+                    sort, product, unit, organic=organic)
             )
 
     def __init__(self,
@@ -152,7 +158,7 @@ class PriceCheck(FocusWidget):
             state='mixed',
         )
         urwid.connect_signal(self.organic_checkbox, 'change', lambda _,v: self.apply_changes('organic', v))
-        
+
         fields = [f for f in fields ]
         for k in fields:
             if k in self.right_pane and k != 'unit':
@@ -162,12 +168,12 @@ class PriceCheck(FocusWidget):
             elif k == 'organic':
                 self.data[k] = 'mixed'
                 continue
-            
+
             self.data[k] = ''
             urwid.connect_signal(ef, 'change', lambda w, v: self.apply_changes(w.name, v))
             urwid.connect_signal(ef, 'apply', lambda w, name: autocomplete_cb(w, name, self.data))
             self.edit_fields[k] = ef
-        
+
         self.buttons = OrderedDict()
         group = []
         for k in top_pane:
@@ -178,24 +184,24 @@ class PriceCheck(FocusWidget):
             self.buttons.update({ f'{k}_date':  urwid.RadioButton(group, ('streak', u'Last'), state="first True") })
             for button in group:
                 urwid.connect_signal(button, 'postchange', lambda *args: self.update_historic_prices())
-        
+
         urwid.connect_signal(self.buttons['clear'], 'click', lambda x: self.clear().update())
         urwid.connect_signal(self.buttons['exit'], 'click', lambda x: show_or_exit('esc'))
-        
+
         dbview, spread, rating, marker = [ urwid.Text('') for i in range(0,4) ]
-        
+
         self.text_fields.update({
             'dbview': dbview,
             'spread': spread,
             'rating': rating,
             'marker': marker,
         })
-        
+
         self.clear()
-        
+
         header = urwid.Text(u'Price Check', 'center')
         _copyright = urwid.Text(COPYRIGHT, 'center')
-        
+
         banner = urwid.Pile([
             urwid.Padding(header, 'center', width=('relative', 100)),
             urwid.Padding(_copyright, 'center', width=('relative', 100)),
@@ -241,7 +247,7 @@ class PriceCheck(FocusWidget):
                 title_align='left',
             )
         ]))
-        
+
         widget = urwid.Pile([
             banner,
             urwid.Divider(),
@@ -270,7 +276,7 @@ class PriceCheck(FocusWidget):
             ),
             *[ fields[c] if c is not None else urwid.Divider() for c in self.bottom_pane ],
         ])
-        widget = urwid.Filler(widget, 'top') 
+        widget = urwid.Filler(widget, 'top')
         widget = urwid.AttrMap(widget, 'bg')
         widget.original_widget.original_widget.set_focus_path([3,0,0])
         super().__init__(widget, 4, [3,0,0,0], [

+ 6 - 0
price_check.py

@@ -44,6 +44,9 @@ dark_palette = [
     ('streak', 'light gray', 'black'),
     ('bg', 'dark red', 'black'),
     ('badge', 'light gray', 'black'),
+    ('badge_good', 'black', 'light green'),
+    ('badge_bad', 'black', 'light red'),
+    ('badge_neutral', 'white', 'dark gray'),
 ]
 
 light_palette = [
@@ -53,6 +56,9 @@ light_palette = [
     ('streak', 'white', 'dark blue'),
     ('bg', 'white', 'dark blue'),
     ('badge', 'white', 'dark blue'),
+    ('badge_good', 'white', 'light green'),
+    ('badge_bad', 'white', 'light red'),
+    ('badge_neutral', 'white', 'dark gray'),
 ]
 
 top_pane = [