Skip to content

Instantly share code, notes, and snippets.

@nathants
Last active August 20, 2022 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathants/2732aae8b0e41d83b066e4a2e5d69ecf to your computer and use it in GitHub Desktop.
Save nathants/2732aae8b0e41d83b066e4a2e5d69ecf to your computer and use it in GitHub Desktop.
>> echo 1 1 1 2 2 2 4 4 4 4 8 8 8 8 16 16 16 16 | tr ' ' '\n' | plot
#!/usr/bin/env python3
# type: ignore
# The MIT License (MIT)
# Copyright (c) 2022-present Nathan Todd-Stone
# https://en.wikipedia.org/wiki/MIT_License#License_terms
import math
import argh # pip install argh
import sys
import blessed # pip install blessed
term = blessed.Terminal()
def avg(xs):
return sum(xs) / len(xs)
def avg_window(vals, size):
for i in range(len(vals)):
xs = [vals[i]]
for j in range(1, size + 1):
try:
xs.append(vals[i + j])
except IndexError:
pass
if i - j >= 0:
try:
xs.append(vals[i - j])
except IndexError:
pass
vals[i] = avg(xs)
return vals
def chunks(val, num_chunks):
size = len(val)
step = math.ceil(size / num_chunks)
return (t
for i in range(num_chunks)
for t in [tuple(val[step * i:step * (i + 1)])]
if t)
def main(offset_height=20, smoothing=0, char='#', discard_extremes_chunks=0):
"""
usage:
>> echo 1 1 1 2 2 2 4 4 4 4 8 8 8 8 16 16 16 16 | tr ' ' '\n' | plot
"""
width = term.width
height = term.height - offset_height
# parse input
data = []
for line in sys.stdin:
data.append(float(line))
if len(data) < width:
width = len(data)
# screen is array of columns
screen = [[' ' for _ in range(height)]
for _ in range(width)]
# find bounds and scale to put data on term height range
xs = list(sorted(avg(xs) for xs in chunks(data, width)))
if discard_extremes_chunks:
slice = int(width / discard_extremes_chunks)
xs = xs[slice:-slice]
val_min = min(xs)
val_max = max(xs)
try:
scale = height / (val_max - val_min)
except ZeroDivisionError:
print('fatal: not enough data')
sys.exit(1)
# chunk, avg, and avg_window data to term width range
vals = chunks(data, width)
vals = [avg(val) for val in vals]
vals = avg_window(vals, smoothing)
# scale data to term height range
for i, val in enumerate(vals):
val -= val_min
val *= scale
val = int(val - 1)
try:
screen[i][val] = char
except IndexError:
pass
# transpose columns to rows and print
print('_' * width)
screen = list(reversed(list(zip(*screen))))
for i, row in enumerate(screen):
row = ''.join(row)
if i == 0:
header = str(int(val_max)) + ' '
row = header + row[len(header):]
if i == len(screen) - 1:
header = str(int(val_min)) + ' '
row = header + row[len(header):]
print(row)
print('_' * width)
if __name__ == '__main__':
argh.dispatch_command(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment