Jelajahi Sumber

introduce line plots for easier data streaming

Falko Schindler 4 tahun lalu
induk
melakukan
d050646eea
2 mengubah file dengan 47 tambahan dan 7 penghapusan
  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 datetime import datetime
 from matplotlib import pyplot as plt
 from matplotlib import pyplot as plt
 import numpy as np
 import numpy as np
-import time
 
 
 with ui.card():
 with ui.card():
     ui.label('Interactive elements', 'h5')
     ui.label('Interactive elements', 'h5')
@@ -33,16 +32,14 @@ with ui.card():
     ui.label('Matplotlib', 'h5')
     ui.label('Matplotlib', 'h5')
     with ui.plot(close=False) as plot:
     with ui.plot(close=False) as plot:
         plt.title('Some plot')
         plt.title('Some plot')
-        i, x, y = 0, [], []
+        x, y = [], []
         line, = plt.plot(x, y, 'C0')
         line, = plt.plot(x, y, 'C0')
-        plt.ion()
 
 
     def update_plot():
     def update_plot():
-        global i, x, y, line
+        global x, y, line
         with plot:
         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_xdata(x)
             line.set_ydata(y)
             line.set_ydata(y)
             plt.xlim(min(x), max(x))
             plt.xlim(min(x), max(x))
@@ -50,4 +47,12 @@ with ui.card():
 
 
     ui.timer(1.0, update_plot)
     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()
 ui.run()

+ 35 - 0
nice_gui.py

@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 #!/usr/bin/env python3
 import traceback
 import traceback
 import justpy as jp
 import justpy as jp
+from numpy import isin
 from starlette.applications import Starlette
 from starlette.applications import Starlette
 import uvicorn
 import uvicorn
 import inspect
 import inspect
@@ -62,6 +63,34 @@ class Plot(Element):
 
 
         self.view.set_figure(plt.gcf())
         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):
 class Ui(Starlette):
 
 
     def label(self, text='', typography=[]):
     def label(self, text='', typography=[]):
@@ -142,6 +171,12 @@ class Ui(Starlette):
         if close:
         if close:
             fig.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):
     def row(self):
 
 
         view = jp.QDiv(classes='row items-start', style='gap: 1em', delete_flag=False)
         view = jp.QDiv(classes='row items-start', style='gap: 1em', delete_flag=False)