Привет, у меня есть график в реальном времени, который обновляется по подписке с использованием zmq. Я использую анимацию из matplotlib, чтобы отразить последнее обновление, но при каждом обновлении я получаю блок 1se c. Есть ли способ обновить сюжет без блокировки в пользовательском интерфейсе? Вы можете «почувствовать» блок, если перетащите окно UI.py по экрану с помощью мыши.
publi sh data: (сначала запустите: сохраните как Publisher.py и запустите: python Publisher.py)
import zmq
from time import sleep
import numpy as np
context = zmq.Context()
socket = context.socket(zmq.PUB) # pylint: disable=no-member
socket.bind('tcp://127.0.0.1:2020')
# noise
dt = 0.01
t = np.arange(0, 30, dt)
nse1 = np.random.randn(len(t))
nse2 = np.random.randn(len(t))
nse3 = np.random.randn(len(t))
# sample data
s1 = np.sin(2 * np.pi * 10 * t) + nse1
s2 = np.sin(2 * np.pi * 10 * t) + nse2
s3 = np.sin(2 * np.pi * 10 * t) + nse3
index = 0
while(True):
sleep(0.10)
messages = [{"p1":{"key1":"100.01"},
"p2":{"key1":s1[index],"key2":s2[index],"key3":s3[index]},
"p3":{"key1":"100100.45","key2":"200200.56"}}]
print( 'index=',index," {",messages[0],"}" )
socket.send_pyobj(messages[0])
if( index == len(s1)-1 ):
index = 0
else:
index = index + 1
UI (сохраните его как UI.py и запустите python UI.py)
import sys
import tkinter as tk
from tkinter import *
from tkinter import messagebox
import tkinter.scrolledtext as tkst
import time
import zmq
import threading as t
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,
AutoMinorLocator)
import numpy as np
from drawnow import *
key1=[]
key2=[]
key3=[]
PLOT_MAX=50
PLOT_FILL_COLOR='#8899b5ff'
class SIControllerUI(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master = master
self.master.title("SIControllerUI-UI v2020")
self.grid()
self.subscribing = True
self.master.protocol("WM_DELETE_WINDOW", self.xit)
def startup(self):
self.create_widgets()
self.tZmq = t.Thread(target=self.refreshState,args=[2020])
self.tZmq.start()
def isSubscribing(self):
return self.subscribing
def terminate(self):
self.subscribing = False
def xit(self):
if messagebox.askokcancel("Quit", "Do you want to quit?"):
#self.terminate()
'''while self.tZmq.is_alive()==True:
print('Subscription still running. Waiting...')
time.sleep(.5)
self.tZmq.join()'''
self.master.destroy()
def create_widgets(self):
None
def refreshState(self,port):
#print('getting message...')
context = zmq.Context()
socket = context.socket(zmq.SUB) # pylint: disable=no-member
subUrl = 'tcp://127.0.0.1:' + str(port)
socket.connect(subUrl)
try:
socket.setsockopt(zmq.SUBSCRIBE, '') # pylint: disable=no-member
except TypeError:
socket.setsockopt_string(zmq.SUBSCRIBE, '') # pylint: disable=no-member
#print('refreshState isSubscribing='+str(self.isSubscribing()))
while(self.isSubscribing()):
self.peripheralState = socket.recv_pyobj()
#print( type(self.peripheralState))
#print( self.peripheralState )
periDict = self.peripheralState["p2"]
index = 1
for key in periDict:
#print("key: %s , value: %s" % (key, periDict[key]))
if(index == 1 and self.isSubscribing()):
key1.append( periDict[key] )
if( len(key1) > PLOT_MAX):
key1.pop(0)
if(index == 2 and self.isSubscribing() ):
key2.append( periDict[key] )
if( len(key2) > PLOT_MAX):
key2.pop(0)
if(index == 3 and self.isSubscribing()):
key3.append( periDict[key] )
if( len(key3) > PLOT_MAX):
key3.pop(0)
index = index + 1
print('refreshState is terminated!')
def updateStreamingUi(i):
plt.ticklabel_format(useOffset=False)
axs[0].clear()
axs[0].set_ylim(min(key1), max(key1))
axs[0].xaxis.set_major_locator(MultipleLocator(2))
axs[0].xaxis.set_minor_locator(AutoMinorLocator(2))
x1 = np.arange(-1,len(key1)-1,1)
axs[0].fill_between(x1,min(key1),key1,color=PLOT_FILL_COLOR)
axs[1].clear()
axs[1].set_ylim(min(key2), max(key2))
axs[1].xaxis.set_major_locator(MultipleLocator(2))
axs[1].xaxis.set_minor_locator(AutoMinorLocator(2))
x2 = np.arange(-1,len(key2)-1,1)
axs[1].fill_between(x2,min(key2),key2,color=PLOT_FILL_COLOR)
axs[2].clear()
axs[2].set_ylim(min(key3), max(key3))
axs[2].xaxis.set_major_locator(MultipleLocator(2))
axs[2].xaxis.set_minor_locator(AutoMinorLocator(2))
x3 = np.arange(-1,len(key3)-1,1)
axs[2].fill_between(x3,min(key3),key3,color=PLOT_FILL_COLOR)
def refreshStateMain(port, app):
print('getting message...')
context = zmq.Context()
socket = context.socket(zmq.SUB) # pylint: disable=no-member
subUrl = 'tcp://127.0.0.1:' + str(port)
socket.connect(subUrl)
try:
socket.setsockopt(zmq.SUBSCRIBE, '') # pylint: disable=no-member
except TypeError:
socket.setsockopt_string(zmq.SUBSCRIBE, '') # pylint: disable=no-member
print('refreshState isSubscribing='+str(app.isSubscribing()))
while(app.isSubscribing()):
app.peripheralState = socket.recv_pyobj()
print( type(app.peripheralState))
print( app.peripheralState )
# get p1 for example
periDict = app.peripheralState["p2"]
index = 1
for key in periDict:
print("key: %s , value: %s" % (key, periDict[key]))
if(index == 1 and app.isSubscribing()):
key1.append( periDict[key] )
if( len(key1) > PLOT_MAX):
key1.pop(0)
if(index == 2 and app.isSubscribing() ):
key2.append( periDict[key] )
if( len(key2) > PLOT_MAX):
key2.pop(0)
if(index == 3 and app.isSubscribing()):
key3.append( periDict[key] )
if( len(key3) > PLOT_MAX):
key3.pop(0)
index = index + 1
print('refreshState isSubscribing='+str(app.isSubscribing()))
print('refreshState is terminated!')
if __name__ == '__main__':
root = tk.Tk()
fig, axs = plt.subplots(3, 1)
plt.ion()
plt.rcParams['axes.xmargin'] = 0
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().grid(row=0, column=0, columnspan=4, rowspan=4,
sticky=W+E+N+S, padx=5, pady=5)
ani = animation.FuncAnimation(fig, updateStreamingUi, interval=1000, blit=False)
app = SIControllerUI(master=root)
app.startup()
app.mainloop()
Спасибо