From 55a86772e06cc9d01df98d3b73012c129f36648a Mon Sep 17 00:00:00 2001 From: "Peter J. Holzer" Date: Fri, 30 Dec 2022 18:59:58 +0100 Subject: [PATCH] Plot timeseries --- dashboard.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/dashboard.py b/dashboard.py index c4da931..fc32386 100644 --- a/dashboard.py +++ b/dashboard.py @@ -1,5 +1,7 @@ +import datetime import json import logging +import math import time from flask import (Flask, request, jsonify, abort, render_template_string, render_template) @@ -114,6 +116,144 @@ class TimeSeries(Widget): super().__init__(d) pass + def as_html(self): + def t2x(t): + x = n - math.log((t_last - t) / (n*dt) + 1) * n / k + return x + + data = self.lts.data + n = len(data) + t_last = data[-1][0] + dt = (t_last - data[-5][0]) / 4 + k = math.log((t_last - data[0][0]) / dt / n + 1) + + max_value = max([d[1] for d in self.lts.data]) + max_value = max(max_value, 0.001) # ensure positive + v_data = [] + for i in range(n): + t = data[i][0] + x = t2x(t) + t_h = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t)) + #print(t, t_h, x) + v_data.append({"t": t, "v": data[i][1], "x": x, "y": (1 - data[i][1]/max_value) * 200}) + + tickmarks = [] + t = v_data[-1]["t"] + x = v_data[-1]["x"] + d = datetime.datetime.fromtimestamp(t) + tickmarks.append({"t": t, "t_h": d.strftime("%Y-%m-%d %H:%M:%S"), "x": x}) + + steps = ("s", "m", "h", "D", "M", "Y") + step_i = 0 + while True: + t0 = tickmarks[-1]["t"] + x0 = tickmarks[-1]["x"] + d0 = datetime.datetime.fromtimestamp(t0) + + if steps[step_i] == "s": + d1 = datetime.datetime(d0.year, d0.month, d0.day, d0.hour, d0.minute, d0.second) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + d1 -= datetime.timedelta(seconds=1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + + if steps[step_i] == "m": + d1 = datetime.datetime(d0.year, d0.month, d0.day, d0.hour, d0.minute) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + d1 -= datetime.timedelta(minutes=1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + + if steps[step_i] == "h": + d1 = datetime.datetime(d0.year, d0.month, d0.day, d0.hour) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + d1 -= datetime.timedelta(hours=1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + + if steps[step_i] == "D": + d1 = datetime.datetime(d0.year, d0.month, d0.day) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + d1 -= datetime.timedelta(days=1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + + if steps[step_i] == "M": + d1 = datetime.datetime(d0.year, d0.month, 1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + if d1.month > 1: + d1 = datetime.datetime(d1.year, d1.month-1, 1) + else: + d1 = datetime.datetime(d1.year-1, 12, 1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + + if steps[step_i] == "Y": + d1 = datetime.datetime(d0.year, 1, 1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + d1 = datetime.datetime(d1.year-1, 1, 1) + t1 = d1.timestamp() + x1 = t2x(t1) + if x0 - x1 < 20: + step_i += 1 + continue + if x1 < 0: + break + tickmarks.append({"t": t1, "t_h": d1.strftime("%Y-%m-%d %H:%M:%S"), "x": x1}) + if tickmarks[-1]["x"] > 20: + t = v_data[0]["t"] + x = v_data[0]["x"] + d = datetime.datetime.fromtimestamp(t) + tickmarks.append({"t": t, "t_h": d.strftime("%Y-%m-%d %H:%M:%S"), "x": x}) + self.x_tickmarks = tickmarks + + self.y_tickmarks = [] + step = 10 ** math.floor(math.log10(max_value)) + v = 0 + while v < max_value: + self.y_tickmarks.append({"y": (1 - v/max_value) * 200, "v_h": str(v)}) + v += step + + html = "" + html += "" + for tm in self.x_tickmarks: + html += f"" + html += f"{tm['t_h']}" + for tm in self.y_tickmarks: + html += f"" + html += f"{tm['v_h']}" + for v in v_data: + html += f"" + html += "" + return Markup(html) + class Gauge(Widget): def __init__(self, d): super().__init__(d)