From 1d1190913f07d2915ed993766bdc4bb95deb3e03 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Sat, 18 Jul 2020 15:08:24 +0200 Subject: [PATCH] initial commit --- .gitignore | 4 +- README.md | 5 ++ cpu-temp.png | Bin 0 -> 17239 bytes default.nix | 2 +- graph.png | Bin 0 -> 26053 bytes graphing-nix.sh | 4 + graphing.py | 53 ++++++++++++++ graphing/__init__.py | 3 + graphing/bar.py | 7 ++ graphing/chart.py | 87 ++++++++++++++++++++++ graphing/helpers.py | 22 ++++++ graphing/stdin.py | 8 ++ temps.log.bkuo | 169 +++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 README.md create mode 100644 cpu-temp.png create mode 100644 graph.png mode change 100644 => 100755 graphing-nix.sh mode change 100644 => 100755 graphing.py create mode 100644 graphing/__init__.py create mode 100644 graphing/bar.py create mode 100644 graphing/chart.py create mode 100644 graphing/helpers.py create mode 100644 graphing/stdin.py create mode 100644 temps.log.bkuo diff --git a/.gitignore b/.gitignore index ab47253..fa5025c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ __pycache__ -*.pyc \ No newline at end of file +*.pyc +*.log + diff --git a/README.md b/README.md new file mode 100644 index 0000000..783849a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Graphing + +![example graph](graph.png) + +A cli graphing tool to plot anything you want diff --git a/cpu-temp.png b/cpu-temp.png new file mode 100644 index 0000000000000000000000000000000000000000..057d07520700da505525ce58fda756f6ffd5224c GIT binary patch literal 17239 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 E1Hb6$R{#J2 literal 0 HcmV?d00001 diff --git a/default.nix b/default.nix index e098d41..c8f70aa 100644 --- a/default.nix +++ b/default.nix @@ -6,7 +6,7 @@ stdenv.mkDerivation rec { buildInputs = [ (python3.withPackages (ps: with ps; [ pylint - plotly + matplotlib clint ])) ]; diff --git a/graph.png b/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..59bb0f707b60d11ee0d9a424b5f7ef8ec88af8b2 GIT binary patch literal 26053 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, \" 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) \ No newline at end of file diff --git a/graphing/__init__.py b/graphing/__init__.py new file mode 100644 index 0000000..0f407d6 --- /dev/null +++ b/graphing/__init__.py @@ -0,0 +1,3 @@ +from .stdin import while_stdin +from .chart import Chart +from .helpers import parse_limits \ No newline at end of file diff --git a/graphing/bar.py b/graphing/bar.py new file mode 100644 index 0000000..84904c2 --- /dev/null +++ b/graphing/bar.py @@ -0,0 +1,7 @@ +from .chart import Chart + + +class BarChart(Chart): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.draw_opts = "b." \ No newline at end of file diff --git a/graphing/chart.py b/graphing/chart.py new file mode 100644 index 0000000..f917f59 --- /dev/null +++ b/graphing/chart.py @@ -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) \ No newline at end of file diff --git a/graphing/helpers.py b/graphing/helpers.py new file mode 100644 index 0000000..bfbd90e --- /dev/null +++ b/graphing/helpers.py @@ -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] \ No newline at end of file diff --git a/graphing/stdin.py b/graphing/stdin.py new file mode 100644 index 0000000..f9699e9 --- /dev/null +++ b/graphing/stdin.py @@ -0,0 +1,8 @@ +import sys + +def while_stdin(func): + while True: + line = sys.stdin.readline() + if line is "": + break + func(line[:-1]) diff --git a/temps.log.bkuo b/temps.log.bkuo new file mode 100644 index 0000000..50741c7 --- /dev/null +++ b/temps.log.bkuo @@ -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