modified for multiple y series and ansi colors
Hi, Yes this is not the correct way to send in changes but I'm not forking the whole project. For my own use I modified your script so I could add up to four data series on the y axis and have colors. I also made a few other small changes. Maybe you like the changes so others could use them as well.
hi @kressi i really like your terminal plotter and very cool addition with color, debug and multiplot abilitys @evert-mouw!
I try to use it as a live serial plotter for sensor data right on a rp2040. therefore I reposition the cursor so the next plot overwrites the previous.
for w in range(1,rows+4): # plus 4 to scroll plot to the top or plus 3 to keep plot at position
print('\033[1A', end='\x1b[2K')
furthermore I a.pop(0) for any value above a certain len(a) to keep the plot scrolling.
https://github.com/kressi/terminalplot/assets/60987359/183c27cd-d250-4f91-a315-169f6e5d25c2
full python
full python
import time
import numpy
import random
def plot(rows, columns, x, a, b=[], c=[], d=[]):
# offset for caption
rows -= 4
colors = [ '\u001b[32;1m', '\u001b[34;1m', '\u001b[35;1m', '\u001b[36;1m', '\u001b[31;1m' ]
normalcolors = '\u001b[0m' # undo color
pointsymbols = [ colors[0] + "●", colors[1] + "⏺", colors[2] + "▆", colors[3] + "█", colors[4] + "-" ] # the last symbol is used for overlapping series
series = 0
overlap = 4 # "X"
# Create empty canvas
canvas = [[" " for _ in range(columns)] for _ in range(rows)]
# Scale points such that they fit on canvas
y = list( a + b + c + d )
x_max = max( len(a), len(b), len(c), len(d) ) + 1
if x_max > len(x):
x_max = len(x)
x_scale = scaleCalc(x[:x_max], columns)
x_scaled = scale(x, x_scale)
y_scale = scaleCalc(y, rows)
y_smallest = min(y)
for q in (a, b, c, d):
series += 1
# Scale y-axis series points such that they fit on canvas
q_scaled = scale(q, y_scale, y_smallest)
# Add scaled points to canvas
for ix, iq in zip(x_scaled, q_scaled):
if canvas[rows - iq - 1][ix] == ' ':
canvas[rows - iq - 1][ix] = pointsymbols[series-1]
else:
canvas[rows - iq - 1][ix] = pointsymbols[overlap] # multiple y values on the same point
# Print rows of canvas
for i in range(rows):
line = ''.join(str(e) for e in canvas[i]).rstrip()
print(line)
print(normalcolors.rstrip(), end='')
# Print scale
print(f"\n{round(min(x),4)}min/{round(max(x),4)}max x; {round(min(a),4)}min/{round(max(y),4)}max y; {rows}/{columns}aspect")
# reposition cursor
for w in range(1,rows+4): # plus 4 to scroll plot to the top or plus 3 to keep plot at position
print('\033[1A', end='\x1b[2K')
def scaleCalc(x, length):
s = float(length - 1) / \
(max(x) - min(x)) if x and max(x) - min(x) != 0 else length
return s
def scale(x, scale, smallest=None):
if smallest==None:
smallest = min(x)
return [int((i - smallest) * scale) for i in x]
x = []; a = []; b = []; c = []; d = []
i = 1
while True:
time.sleep(0.1)
x.append(i)
a.append(numpy.sin(i*0.3))
b.append(numpy.cos(i*0.3))
c.append(numpy.sin(-i*0.3))
d.append(random.randint(-1,1))
i += 1
if len(x) >= 20: # space between points
x.pop(0); a.pop(0); b.pop(0); c.pop(0); d.pop(0)
plot(20, 100, x, a, b, c, d) # determine canvas sice with x, y
Thanks a lot for the feedback and the shared example! I will have a closer look at it within the next couple of days.