initial commit

master
Anton Lydike 4 years ago
parent f882674c70
commit 1d1190913f

2
.gitignore vendored

@ -1,2 +1,4 @@
__pycache__
*.pyc
*.log

@ -0,0 +1,5 @@
# Graphing
![example graph](graph.png)
A cli graphing tool to plot anything you want

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -6,7 +6,7 @@ stdenv.mkDerivation rec {
buildInputs = [
(python3.withPackages (ps: with ps; [
pylint
plotly
matplotlib
clint
]))
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -0,0 +1,4 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p python3 python37Packages.matplotlib
$(dirname $(realpath $0))/graphing.py "$@"

@ -0,0 +1,53 @@
#!/usr/bin/env python3
import time
import argparse
import matplotlib
from graphing import *
# matplotlib setup
matplotlib.pyplot.style.use('dark_background')
matplotlib.rcParams['toolbar'] = 'None'
# arg parser
parser = argparse.ArgumentParser(description='Visualize data as graphs')
parser.add_argument('title', type=str, help="name of the chart", default=None, nargs='?')
parser.add_argument('-n', type=int, help="number of records to show, -1 for no limit. Default 50", default=50, dest="samples")
parser.add_argument('-l', '--limits', type=str, help="limits for the y-axis. If not set, use best-fit. Example values are 0-10, 5- (starting at 5), or -10 (lower than 10)")
parser.add_argument('-b', '--batch', help="batch processing. Do not use timestamp from when they were read from stdin.", action="store_true")
parser.add_argument('-i', '--input', type=str, help="read from file rather than stdin. Also enables batch mode and sets samples to -1.")
parser.add_argument('-o', '--output', type=str, help="Write final chart to file")
parser.add_argument('-f', '--full', help="fullscreen mode - hide all axis labels and title, only display graph.", action="store_true")
parser.add_argument('-x', '--read-x-values', help="read value of x-axis from input. Input is now \"<x>, <y>\" tuple (comma separated)", action="store_true", dest="read_x")
args = parser.parse_args()
# setup batch and sample count for when using input file
if args.input:
args.batch = True
args.samples = -1
# parse limit arg
args.limits = parse_limits(args.limits)
# instatiate chart with our args
chart = Chart(title=args.title, limits=args.limits, batch=args.batch, samples=args.samples, fullscreen=args.full, show=not args.output, read_x=args.read_x)
# final waiting state
try:
if not args.input:
# read args from stdin
while_stdin(chart.read_input)
else:
with open(args.input) as f:
for line in f:
chart.read_input(line.strip())
chart.ui_update(final_draw = True)
while not args.output:
time.sleep(1)
except KeyboardInterrupt:
if args.output:
chart.save_to_file(args.output)
else:
chart.ui_update(final_draw = True)

@ -0,0 +1,3 @@
from .stdin import while_stdin
from .chart import Chart
from .helpers import parse_limits

@ -0,0 +1,7 @@
from .chart import Chart
class BarChart(Chart):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.draw_opts = "b."

@ -0,0 +1,87 @@
from datetime import datetime, timedelta
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
class Chart:
def __init__(self, samples = 50, title = None, limits = None, batch=False, show=True, fullscreen=False, read_x=False):
self.start = datetime.now()
self.x = []
self.y = []
self.samples = samples
self.fig = plt.figure()
self.axis = self.fig.add_subplot(111, autoscale_on = True, xticklabels = [])
scale_axis = "both" if not limits else "x"
self.axis.autoscale(enable=True, axis=scale_axis, tight = 2)
# save limits
self.limits = limits
self.title = title
self.axis.set_label(title)
self.fig.canvas.draw()
self.draw_opts = 'r-'
self.line = False
# upate timeout code (limit to 10fps)
self.last_update = datetime.min
self.update_timeout = timedelta(seconds=0.1)
self.read_x = read_x
# if batch mode, do not use timestamp when read from stdin
self.batch = batch
self.fullscreen = fullscreen
if show:
plt.show(block=False)
def ui_update(self, final_draw=False):
if len(self.y) < 2:
return
if not final_draw and datetime.now() - self.last_update < self.update_timeout:
return
self.axis.clear()
# call plot method that is easily overrideable
self.plot()
if self.limits:
self.axis.set_ylim(self.limits)
if not self.batch:
self.axis.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M:%S"))
self.fig.autofmt_xdate()
if self.fullscreen:
plt.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
else:
plt.title(self.title)
self.fig.canvas.draw()
self.fig.canvas.flush_events()
self.last_update = datetime.now()
def plot(self):
if self.batch:
self.axis.plot(self.y, self.draw_opts)
else:
self.axis.plot_date(self.x, self.y, self.draw_opts)
def read_input(self, input):
self.y.append(float(input))
self.x.append(datetime.now())
if self.samples > 0 and len(self.y) > self.samples:
self.y.pop(0)
self.x.pop(0)
self.ui_update()
def save_to_file(self, file):
self.ui_update(final_draw = True)
plt.savefig(file)

@ -0,0 +1,22 @@
def parse_limits(limits):
if not limits:
return [None, None]
limits = limits.strip()
if limits[0] == '-':
return [None, int(limits[1:])]
elif limits[-1] == '-':
return [int(limits[:-1]), None]
limits = limits.split("-")
if len(limits) != 2:
print("unknown limits: " + str(limits) + " - using no limits")
return [None, None]
try:
return [int(x) for x in limits]
except ValueError as exp:
print(exp + " - using no limits")
return [None, None]

@ -0,0 +1,8 @@
import sys
def while_stdin(func):
while True:
line = sys.stdin.readline()
if line is "":
break
func(line[:-1])

@ -0,0 +1,169 @@
54.625
54.25
53.75
53.25
53
52.5
52.125
51.875
51.5
51
50.75
50.375
50
49.625
49.25
67.75
77.5
78.5
79.5
80.375
81.375
82.25
82.75
83
83.5
83.75
84
84
84
84.375
84.75
84.75
84.875
84.875
85
85.25
85.5
85.5
85.75
85.75
86
86.25
86.5
86.875
87
87.25
87.375
87.75
88.125
88.5
88.5
88.5
88.5
88.5
88.625
88.75
89
89.125
89.25
89.25
89.5
89.75
89.875
90
90
90.125
90.375
90.5
90.625
90.625
90.75
90.875
91
91.125
91.375
91.5
91.5
91.5
91.75
91.75
92
92
92
92.125
92.25
92.25
92.25
92.375
92.5
92.5
92.5
92.5
92.5
92.375
91.875
91.25
90.75
90.125
89.625
89
88.5
87.875
87.375
86.875
86.25
85.75
85.125
84.625
84
83.5
82.875
82.375
81.75
81.25
80.625
80.125
79.5
79
78.375
77.875
77.25
76.75
76.25
75.625
75.125
74.5
74
73.375
72.875
72.25
71.75
71.125
70.625
70
69.5
68.875
68.375
67.75
67.25
66.75
66.25
65.75
65.25
64.75
64.25
63.875
63.375
62.875
62.5
62
61.5
61.125
60.625
60.125
59.75
59.25
58.875
58.5
58.125
66.75
66.25
65.625
65.25
64.625
64.125
63.625
63.125
62.625
62.125
Loading…
Cancel
Save