Ver Fonte

introduce line plots for easier data streaming

Falko Schindler há 4 anos atrás
pai
commit
d050646eea
2 ficheiros alterados com 47 adições e 7 exclusões
  1. 12 7
      main.py
  2. 35 0
      nice_gui.py

+ 12 - 7
main.py

@@ -3,7 +3,6 @@ from nice_gui import ui
 from datetime import datetime
 from matplotlib import pyplot as plt
 import numpy as np
-import time
 
 with ui.card():
     ui.label('Interactive elements', 'h5')
@@ -33,16 +32,14 @@ with ui.card():
     ui.label('Matplotlib', 'h5')
     with ui.plot(close=False) as plot:
         plt.title('Some plot')
-        i, x, y = 0, [], []
+        x, y = [], []
         line, = plt.plot(x, y, 'C0')
-        plt.ion()
 
     def update_plot():
-        global i, x, y, line
+        global x, y, line
         with plot:
-            i += 1
-            x = [*x, i][-100:]
-            y = [*y, np.sin(time.time()) + 0.02 * np.random.randn()][-100:]
+            x = [*x, datetime.now()][-100:]
+            y = [*y, np.sin(datetime.now().timestamp()) + 0.02 * np.random.randn()][-100:]
             line.set_xdata(x)
             line.set_ydata(y)
             plt.xlim(min(x), max(x))
@@ -50,4 +47,12 @@ with ui.card():
 
     ui.timer(1.0, update_plot)
 
+with ui.card():
+    ui.label('Line Plot', 'h5')
+    lines = ui.line_plot(n=2, limit=20).with_legend(['sin', 'cos'], loc='upper center', ncol=2)
+    ui.timer(1.0, lambda: lines.push([datetime.now()], [
+        [np.sin(datetime.now().timestamp()) + 0.02 * np.random.randn()],
+        [np.cos(datetime.now().timestamp()) + 0.02 * np.random.randn()],
+    ]))
+
 ui.run()

+ 35 - 0
nice_gui.py

@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 import traceback
 import justpy as jp
+from numpy import isin
 from starlette.applications import Starlette
 import uvicorn
 import inspect
@@ -62,6 +63,34 @@ class Plot(Element):
 
         self.view.set_figure(plt.gcf())
 
+class LinePlot(Plot):
+
+    def __init__(self, view, fig, n, limit):
+
+        super().__init__(view, fig)
+        self.x = []
+        self.Y = [[] for _ in range(n)]
+        self.lines = [self.fig.gca().plot([], [])[0] for _ in range(n)]
+        self.slice = slice(0 if limit is None else -limit, None)
+
+    def with_legend(self, titles, **kwargs):
+
+        self.fig.gca().legend(titles, **kwargs)
+        self.view.set_figure(self.fig)
+        return self
+
+    def push(self, x, Y):
+
+        self.x = [*self.x, *x][self.slice]
+        for i in range(len(self.lines)):
+            self.Y[i] = [*self.Y[i], *Y[i]][self.slice]
+            self.lines[i].set_xdata(self.x)
+            self.lines[i].set_ydata(self.Y[i])
+        flat_y = [y_i for y in self.Y for y_i in y]
+        self.fig.gca().set_xlim(min(self.x), max(self.x))
+        self.fig.gca().set_ylim(min(flat_y), max(flat_y))
+        self.view.set_figure(self.fig)
+
 class Ui(Starlette):
 
     def label(self, text='', typography=[]):
@@ -142,6 +171,12 @@ class Ui(Starlette):
         if close:
             fig.close()
 
+    def line_plot(self, n=1, limit=20):
+
+        fig = plt.figure()
+        view = jp.Matplotlib(fig=fig)
+        return LinePlot(view, fig, n=n, limit=limit)
+
     def row(self):
 
         view = jp.QDiv(classes='row items-start', style='gap: 1em', delete_flag=False)