Plot timeseries
This commit is contained in:
parent
28a7bbd4f3
commit
55a86772e0
140
dashboard.py
140
dashboard.py
|
@ -1,5 +1,7 @@
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from flask import (Flask, request, jsonify, abort, render_template_string, render_template)
|
from flask import (Flask, request, jsonify, abort, render_template_string, render_template)
|
||||||
|
@ -114,6 +116,144 @@ class TimeSeries(Widget):
|
||||||
super().__init__(d)
|
super().__init__(d)
|
||||||
pass
|
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 += "<svg width=1200 height=300>"
|
||||||
|
for tm in self.x_tickmarks:
|
||||||
|
html += f"<line x1={tm['x']} y1=0 x2={tm['x']} y2=200 stroke='#CCC' />"
|
||||||
|
html += f"<text transform='translate({tm['x']}, 210) rotate(30)' fill='#888'>{tm['t_h']}</text>"
|
||||||
|
for tm in self.y_tickmarks:
|
||||||
|
html += f"<line x1=0 y1={tm['y']} x2=1000 y2={tm['y']} stroke='#CCC' />"
|
||||||
|
html += f"<text x=1005 y={tm['y']} fill='#888'>{tm['v_h']}</text>"
|
||||||
|
for v in v_data:
|
||||||
|
html += f"<circle cx={v['x']} cy={v['y']} r=3 fill='#00F' />"
|
||||||
|
html += "</svg>"
|
||||||
|
return Markup(html)
|
||||||
|
|
||||||
class Gauge(Widget):
|
class Gauge(Widget):
|
||||||
def __init__(self, d):
|
def __init__(self, d):
|
||||||
super().__init__(d)
|
super().__init__(d)
|
||||||
|
|
Loading…
Reference in New Issue