Skip to content

Instantly share code, notes, and snippets.

@thorsummoner
Created December 20, 2018 08:18
Show Gist options
  • Save thorsummoner/0e5eac453e7926fcbf4c4d2a6f2a431b to your computer and use it in GitHub Desktop.
Save thorsummoner/0e5eac453e7926fcbf4c4d2a6f2a431b to your computer and use it in GitHub Desktop.
a braille character based vmstat display insired by https://www.reddit.com/comments/9ysbx7
#!/usr/bin/env python3
import argparse
import logging
import psutil
import random
import sys
import time
import shutil
import os
LOGGER = logging.getLogger()
ARGP = argparse.ArgumentParser(
add_help=False,
)
ARGP.add_argument('--help', action='help')
ARGP.add_argument('--width', '-w', type=int)
ARGP.add_argument('--height', '-h', type=int)
ARGP.add_argument('--loop', '-l', type=float)
ASCII_RESET = '\033c'
ZER_WIDTH_STR = ''
BRAILLE_DENSITY = {
0: '\u2800',
1: '⡀⢀',
2: '⡁⡂⡄⡈⡉⡐⡠⢁⢂⢄⢈⢐⢠⣀',
3: '⡃⡅⡆⡊⡌⡑⡒⡔⡘⡡⡢⡣⡤⡨⡰⢃⢅⢆⢉⢊⢌⢑⢒⢔⢘⢡⢢⢤⢨⢰⣁⣄⣈⣐⣠',
4: '⡇⡋⡍⡎⡓⡕⡖⡙⡚⡜⡥⡦⡩⡪⡬⡱⡲⡴⡸⢇⢋⢍⢎⢓⢕⢖⢙⢚⢜⢣⢥⢦⢩⢪⢬⢱⢲⢴⢸⣂⣃⣅⣆⣉⣊⣌⣑⣒⣔⣘⣡⣢⣤⣨⣰',
5: '⡏⡗⡛⡝⡞⡧⡫⡭⡮⡳⡵⡶⡹⡺⡼⢏⢗⢛⢝⢞⢧⢫⢭⢮⢳⢵⢶⢹⢺⢼⣇⣋⣍⣎⣓⣕⣖⣙⣚⣜⣣⣥⣦⣩⣪⣬⣱⣲⣴⣸',
6: '⡟⡯⡷⡻⡽⡾⢟⢯⢷⢻⢽⢾⣏⣗⣛⣝⣞⣧⣫⣭⣮⣳⣵⣶⣹⣺⣼',
7: '⡿⢿⣟⣯⣷⣻⣽⣾',
8: '⣿',
}
class VmStatPercent():
""" psutil.virtual_memory wrapper with percentage calculaton
"""
fillset = '#'
used = None
buffers = None
cached = None
free = None
def __init__(self):
super(VmStatPercent, self).__init__()
self.update()
@property
def _base_8_rounded_percent(self):
""" round percentage in base 8, which is the density options of
brail, avaiable
"""
return max(min(round(self.virtual_memory.percent / 100 * 8), 8), 0)
def update(self):
""" requery psutil.virtual_memory
"""
self.virtual_memory = virtual_memory = psutil.virtual_memory()
self.fillset = BRAILLE_DENSITY[self._base_8_rounded_percent]
total = float(virtual_memory.total) # float for fpa division
self.used = virtual_memory.used / total # used green
self.buffers = virtual_memory.buffers / total # buff blue
self.cached = virtual_memory.cached / total # cache yellow
self.free = virtual_memory.free / total # free blank
def mem_density(width, vmstatpercent, fill='|', enclose='[]', free_fill=None):
""" generate an htop-style memory usage graph,
right hand text indicator not implemented
"""
if enclose is None:
enclose = ['', '']
width = width - 2
if free_fill is None:
free_fill = ''
return (
'{enclose[0]}'
'\033[32m'
'{0:{fill}<{vm_used}}'
'\033[34;1m'
'{0:{fill}<{vm_buffers}}'
'\033[0;33m'
'{0:{fill}<{vm_cached}}'
'\033[39;2m'
'{0:{free_fill}<{vm_free}}'
'\033[0m'
'{enclose[1]}'
).format(
ZER_WIDTH_STR,
fill=fill,
enclose=enclose,
free_fill=free_fill,
vm_used=vmstatpercent.used * width,
vm_buffers=vmstatpercent.buffers * width,
vm_cached=vmstatpercent.cached * width,
vm_free=vmstatpercent.free * width,
)
def mem_density_block(width, height, vmstatpercent, enclose='⎡⎢⎣⎤⎥⎦', free_fill=None):
"""
a real big bar graph
alternative enclosures considered
'┌│└┐│┘'
'⎡⎢⎣⎤⎥⎦'
'┌─┐││└─┘' # full boxing not implemented
"""
mem_density_ = mem_density(
width=width,
free_fill=free_fill,
enclose=None,
vmstatpercent=vmstatpercent,
)
if height < 2:
height = 2
LOGGER.warning('high clammed to a minimum of 2')
height = height - 2
return (
'{enclose[0]}{fill}{enclose[3]}\n'
'{height_fill}'
'{enclose[2]}{fill}{enclose[5]}\n'
).format(
ZER_WIDTH_STR,
width=width,
enclose=enclose,
fill=mem_density_,
height_fill=(
'{enclose[1]}{fill}{enclose[4]}\n'.format(
enclose=enclose,
fill=mem_density_,
) * height
)
)
def _gen_choice(choices):
""" turn a fixed string into a character generator
"""
while True:
yield random.choice(choices)
def _multi_gen_choice(stream, choice_dict):
""" replace stream items with lookup of iterators
"""
for item in stream:
if item in choice_dict:
yield next(choice_dict[item])
continue
yield item
def mem_densitiy_braille(width, height, vmstatpercent):
""" populate "density_block" with noisy brail chars
"""
fillgen = _gen_choice(vmstatpercent.fillset)
memblock = mem_density_block(
width=width,
height=height,
free_fill='#',
vmstatpercent=vmstatpercent,
)
choice_map = {
'|': _gen_choice(vmstatpercent.fillset),
'#': _gen_choice(BRAILLE_DENSITY[1]),
}
return ''.join(_multi_gen_choice(memblock, choice_map))
def main(argp=None):
if argp is None:
argp = ARGP.parse_args()
termsize = shutil.get_terminal_size((80, 20))
if argp.width is None:
argp.width = termsize.columns
if argp.height is None:
argp.height = termsize.lines - 2
vmstatpercent = VmStatPercent()
while True:
vmstatpercent.update()
sys.stdout.write(ASCII_RESET)
sys.stdout.write(
mem_densitiy_braille(
width=argp.width,
height=argp.height,
vmstatpercent=vmstatpercent,
)
)
sys.stdout.write('\n')
if not argp.loop:
break
time.sleep(argp.loop)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment