mirror of https://github.com/aristocratos/bpytop
Added Graph class with functions for graph creation
parent
e1b32bd047
commit
d5e63f56c1
180
bpytop.py
180
bpytop.py
|
@ -760,23 +760,21 @@ class Theme:
|
|||
setattr(self, item, Color(tdict[item], depth=depth, default=default))
|
||||
else:
|
||||
setattr(self, item, Color(value, depth=depth, default=default))
|
||||
#* Create color gradients from one, two or three colors, 101 values
|
||||
#* Create color gradients from one, two or three colors, 101 values indexed 0-100
|
||||
rgb: Dict[str, Tuple[int, int, int]]
|
||||
colors: List[Tuple[int, ...]]
|
||||
rgb_calc: List[int]
|
||||
colors: List[List[int]] = []
|
||||
for name in self.gradient.keys():
|
||||
rgb = { "start" : getattr(self, f'{name}_start').dec, "mid" : getattr(self, f'{name}_mid').dec, "end" : getattr(self, f'{name}_end').dec }
|
||||
colors = [ getattr(self, f'{name}_start') ]
|
||||
colors = [ list(getattr(self, f'{name}_start')) ]
|
||||
if rgb["end"][0] >= 0:
|
||||
r = 50 if rgb["mid"][0] >= 0 else 100
|
||||
for first, second in ["start", "mid" if r == 50 else "end"], ["mid", "end"]:
|
||||
for i in range(r):
|
||||
rgb_calc = [rgb[first][n] + i * (rgb[second][n] - rgb[first][n]) // r for n in range(3)]
|
||||
colors += [tuple(rgb_calc)]
|
||||
colors += [[rgb[first][n] + i * (rgb[second][n] - rgb[first][n]) // r for n in range(3)]]
|
||||
if r == 100:
|
||||
break
|
||||
for color in colors:
|
||||
self.gradient[name] += [Color.fg(*color)]
|
||||
self.gradient[name] += [ Color.fg(*color) for color in colors ]
|
||||
|
||||
else:
|
||||
c = Color.fg(*rgb["start"])
|
||||
for _ in range(100):
|
||||
|
@ -875,36 +873,93 @@ class Symbol:
|
|||
fail: str = f'{Color.fg("#ff3050")}!{Color.fg("#cc")}'
|
||||
|
||||
class Graph:
|
||||
out: str = ""
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
graphs: Dict[bool, List[str]] = {False : [], True : []}
|
||||
out: str
|
||||
width: int
|
||||
height: int
|
||||
graphs: Dict[bool, List[str]]
|
||||
colors: List[str]
|
||||
invert: bool = False
|
||||
max_value: int = 0
|
||||
current: bool = False
|
||||
last_value: int = 0
|
||||
invert: bool
|
||||
max_value: int
|
||||
current: bool
|
||||
last: int
|
||||
symbol: Dict[float, str]
|
||||
|
||||
def __init__(self, width: int, height: int, color_gradient: List[str], data: List[int], invert: bool = False, max_value: int = 0):
|
||||
for i in range(1, height + 1):
|
||||
self.colors.append(color_gradient[100 // height * i]) #* Calculate colors of graph
|
||||
def __init__(self, width: int, height: int, color: Union[List[str], Color, None], data: List[int], invert: bool = False, max_value: int = 0):
|
||||
self.graphs: Dict[bool, List[str]] = {False : [], True : []}
|
||||
self.current: bool = True
|
||||
self.colors: List[str] = []
|
||||
if isinstance(color, list):
|
||||
for i in range(1, height + 1): self.colors.insert(0, color[i * 100 // height]) #* Calculate colors of graph
|
||||
if invert: self.colors.reverse()
|
||||
elif isinstance(color, Color):
|
||||
self.colors = [ f'{color}' for _ in range(height) ]
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.invert = invert
|
||||
if not data: data = [0]
|
||||
if max_value:
|
||||
self.max_value = max_value
|
||||
data = [ v * 100 // max_value if v < max_value else 100 for v in data ] #* Convert values to percentage values of max_value with max_value as ceiling
|
||||
else:
|
||||
self.max_value = 0
|
||||
self.symbol = Symbol.graph_down if invert else Symbol.graph_up
|
||||
value_width: int = ceil(len(data) / 2)
|
||||
filler: str = ""
|
||||
if value_width > width: #* If the size of given data set is bigger then width of graph, shrink data set
|
||||
data = data[-(width*2):]
|
||||
value_width = ceil(len(data) / 2)
|
||||
elif value_width < width: #* If the size of given data set is smaller then width of graph, fill graph with whitespace
|
||||
filler = " " * (width - value_width)
|
||||
for _ in range(height):
|
||||
for b in [True, False]:
|
||||
self.graphs[b].append(filler if filler else "")
|
||||
self._create(data, new=True)
|
||||
|
||||
def _create(self, data: List[int], new: bool = False):
|
||||
h_high: int
|
||||
h_low: int
|
||||
value: Dict[str, int] = { "left" : 0, "right" : 0 }
|
||||
val: int
|
||||
side: str
|
||||
|
||||
#* Create the graph
|
||||
for h in range(self.height):
|
||||
h_high = round(100 * (self.height - h) / self.height) if self.height > 1 else 100
|
||||
h_low = round(100 * (self.height - (h + 1)) / self.height) if self.height > 1 else 0
|
||||
for v in range(len(data)):
|
||||
if new: self.current = bool(v % 2) #* Switch between True and False graphs
|
||||
if new and v == 0: self.last = 0
|
||||
for val, side in [self.last, "left"], [data[v], "right"]: # type: ignore
|
||||
if val >= h_high:
|
||||
value[side] = 4
|
||||
elif val <= h_low:
|
||||
value[side] = 0
|
||||
else:
|
||||
if self.height == 1: value[side] = round(val * 4 / 100 + 0.5)
|
||||
else: value[side] = round((val - h_low) * 4 / (h_high - h_low) + 0.1)
|
||||
if new: self.last = data[v]
|
||||
self.graphs[self.current][h] += self.symbol[float(value["left"] + value["right"] / 10)]
|
||||
self.last = data[-1]
|
||||
self.out = ""
|
||||
|
||||
for h in range(self.height):
|
||||
if h > 0: self.out += f'{Mv.d(1)}{Mv.l(self.width)}'
|
||||
self.out += f'{"" if not self.colors else self.colors[h]}{self.graphs[self.current][h if not self.invert else (self.height - 1) - h]}'
|
||||
self.out += f'{Term.fg}'
|
||||
|
||||
def add(self, value: int):
|
||||
self.current = not self.current
|
||||
del self.graphs[self.current][0]
|
||||
for n in range(self.height):
|
||||
self.graphs[self.current][n] = self.graphs[self.current][n][1:]
|
||||
if self.max_value: value = value * 100 // self.max_value if value < self.max_value else 100
|
||||
self._create([value])
|
||||
return self.out
|
||||
|
||||
def __str__(self):
|
||||
return self.out
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.out)
|
||||
|
||||
|
||||
class Graphs:
|
||||
|
@ -923,18 +978,18 @@ class Meter:
|
|||
__call__(value) to set value and return meter as a string
|
||||
__str__ returns last set meter as a string
|
||||
'''
|
||||
out: str = ""
|
||||
out: str
|
||||
color_gradient: List[str]
|
||||
color_inactive: Color
|
||||
width: int = 0
|
||||
saved: Dict[int, str] = {}
|
||||
width: int
|
||||
saved: Dict[int, str]
|
||||
|
||||
def __init__(self, value: int, width: int, gradient_name: str):
|
||||
self.color_gradient = THEME.gradient[gradient_name]
|
||||
self.color_inactive = THEME.inactive_fg
|
||||
self.width = width
|
||||
self.out = self._create(value)
|
||||
self.saved[value] = self.out
|
||||
self.saved = { value : self.out }
|
||||
|
||||
def __call__(self, value: int):
|
||||
if value in self.saved.keys():
|
||||
|
@ -977,18 +1032,18 @@ class Meters:
|
|||
|
||||
class Box:
|
||||
'''Box class with all needed attributes for create_box() function'''
|
||||
name: str = ""
|
||||
height_p: int = 0
|
||||
width_p: int = 0
|
||||
x: int = 1
|
||||
y: int = 1
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
out: str = ""
|
||||
bg: str = ""
|
||||
_b_cpu_h: int = 0
|
||||
_b_mem_h: int = 0
|
||||
redraw_all: bool = False
|
||||
name: str
|
||||
height_p: int
|
||||
width_p: int
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
out: str
|
||||
bg: str
|
||||
_b_cpu_h: int
|
||||
_b_mem_h: int
|
||||
redraw_all: bool
|
||||
|
||||
@classmethod
|
||||
def calc_sizes(cls):
|
||||
|
@ -1010,6 +1065,8 @@ class SubBox:
|
|||
|
||||
class CpuBox(Box, SubBox):
|
||||
name = "cpu"
|
||||
x = 0
|
||||
y = 0
|
||||
height_p = 32
|
||||
width_p = 100
|
||||
|
||||
|
@ -1045,6 +1102,8 @@ class MemBox(Box):
|
|||
name = "mem"
|
||||
height_p = 40
|
||||
width_p = 45
|
||||
x = 0
|
||||
y = 0
|
||||
divider: int = 0
|
||||
mem_width: int = 0
|
||||
disks_width: int = 0
|
||||
|
@ -1072,6 +1131,8 @@ class NetBox(Box, SubBox):
|
|||
name = "net"
|
||||
height_p = 28
|
||||
width_p = 45
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
@classmethod
|
||||
def _calc_size(cls):
|
||||
|
@ -1093,6 +1154,8 @@ class ProcBox(Box):
|
|||
name = "proc"
|
||||
height_p = 68
|
||||
width_p = 55
|
||||
x = 0
|
||||
y = 0
|
||||
detailed: bool = False
|
||||
detailed_x: int = 0
|
||||
detailed_y: int = 0
|
||||
|
@ -1502,6 +1565,34 @@ def testing_keyinput():
|
|||
pass
|
||||
Draw.clear()
|
||||
|
||||
def testing_graphs():
|
||||
|
||||
from random import randint
|
||||
|
||||
my_data = [x for x in range(0, 101)]
|
||||
my_data += [x for x in range(100, -1, -1)]
|
||||
|
||||
my_graph = Graph(Term.width, Term.height // 3, THEME.gradient['cpu'], my_data, invert=False)
|
||||
my_graph2 = Graph(Term.width, Term.height // 3, THEME.gradient['cpu'], my_data, invert=True)
|
||||
my_graph3 = Graph(Term.width, 1, THEME.proc_misc, my_data)
|
||||
my_graph4 = Graph(Term.width, 2, None, my_data)
|
||||
|
||||
Draw.now(f'{Mv.to(0, 0)}{my_graph}')
|
||||
Draw.now(f'{Mv.to(Term.height // 3 + 1, 0)}{my_graph2}')
|
||||
Draw.now(f'{Mv.to(Term.height - (Term.height // 3) + 2, 0)}{my_graph3}')
|
||||
Draw.now(f'{Mv.to(Term.height - (Term.height // 3) + 4, 0)}{my_graph4}')
|
||||
|
||||
|
||||
for _ in range(100):
|
||||
sleep(0.1)
|
||||
x = randint(0, 100)
|
||||
Draw.now(f'{Mv.to(0, 0)}{my_graph.add(x)}')
|
||||
Draw.now(f'{Mv.to(Term.height // 3 + 1, 0)}{my_graph2.add(x)}')
|
||||
Draw.now(f'{Mv.to(Term.height - (Term.height // 3) + 2, 0)}{my_graph3.add(x)}')
|
||||
Draw.now(f'{Mv.to(Term.height - (Term.height // 3) + 4, 0)}{my_graph4.add(x)}')
|
||||
|
||||
Draw.now(Mv.to(Term.height -4, 0))
|
||||
|
||||
# if not Key.reader.is_alive():
|
||||
# clean_quit(1)
|
||||
# Key.new.wait(1.0)
|
||||
|
@ -1613,19 +1704,20 @@ if __name__ == "__main__":
|
|||
#! For testing ------------------------------------------------------------------------------->
|
||||
if testing:
|
||||
try:
|
||||
testing_collectors()
|
||||
testing_humanizer()
|
||||
testing_graphs()
|
||||
#testing_collectors()
|
||||
#testing_humanizer()
|
||||
# waitone(1)
|
||||
#testing_keyinput()
|
||||
testing_banner()
|
||||
#testing_banner()
|
||||
# waitone(1)
|
||||
# testing_colors()
|
||||
#testing_colors()
|
||||
# waitone(1)
|
||||
testing_gradients()
|
||||
#testing_gradients()
|
||||
# waitone(1)
|
||||
testing_boxes()
|
||||
#testing_boxes()
|
||||
# waitone(1)
|
||||
testing_meter()
|
||||
#testing_meter()
|
||||
# Draw.idle.clear()
|
||||
#Draw.now(f'{Mv.to(Term.height - 5, 1)}Any key to exit!')
|
||||
#waitone()
|
||||
|
|
Loading…
Reference in New Issue