运行一个更新数组的函数,同时Matplotlib绘制它

时间:2016-10-04 03:57:18

标签: python python-3.x matplotlib tkinter

我有一个Python程序( main.py ),它有一个由RTStreamer类处理的恒定数据流,它基本上通过实时流获取数据并附加它到一个numpy数组。然而,我想实际可视化数据,因为它正在进入tkinter和matplotlib进来。在另一个python文件( gui.py )我有一个使用matplotlib动画和一个按钮的实时情节触发我的第一个文件( main.py )以开始流式传输数据。但是,当我单击按钮开始流式传输数据时,我可以在我的控制台上看到它正在获取数据并将其附加到数组(因为我正在打印数组),但图表根本没有更新。

以下是我的 main.py 的简化版本:

closeBidArray = np.array([])

class RTStreamer(stream.Streamer):
    def __init__(self, *args, **kwargs):
        super(RTStreamer, self).__init__(*args, **kwargs)
        print(datetime.now(), "initialized")

    def on_success(self, data):
        # get data and append it to closeBidArray

    def on_error(self, data):
        # disconnect 

def run():
    stream = RTStreamer()
    stream.rates()

这是我的 gui.py 的样子:

import main # in order to get closeBidArray

figure = Figure(figsize=(5,5), dpi=100)
subplot1 = figure.add_subplot(111)


class App(tk.Tk):
    # Mostly to do with formatting the window and frames in it

def animate():
    subplot1.clear
    subplot1.plot(main.closeBidArray)

class MainPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        # THIS IS THE BUTTON THAT TRIGGERS TO FUNCTION THAT STREAMS THE DATA:
        button1 = tk.Button(text="Hi", command=main.run)
        button1.pack()

        canvas = FigureCanvasTkAgg(figure, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)

app = App()
ani = animation.FuncAnimation(figure, animate, interval=1000)   
app.mainloop()  

我注意到,如果我按 CTRL + C 来打破程序,它会调整流数据并绘制数组,如果我按 CTRL < / kbd> + C 再次关闭matplotlib窗口。但是,我想流式传输并附加到阵列,同时也绘制它,任何关于如何实现这一点的想法?谢谢。

1 个答案:

答案 0 :(得分:0)

要使代码正常工作,您需要在每个帧上绘制艺术家,而不仅仅是显示画布。然而,这将是缓慢的。你真正想做的是,只更新数据,并保持画布不变。为此,你使用blit。下面的最低工作示例。

import numpy as np
import matplotlib.pyplot as plt

def animate(movie):
    """
    Animate frames in array using blit.

    Arguments:
    ----------
        movie: (time, height, width) ndarray

    """

    plt.ion()
    fig, ax = plt.subplots(1,1)

    # initialize blit for movie axis
    img = ax.imshow(np.zeros((movie.shape[1],movie.shape[2])),
                    interpolation = 'nearest', origin = 'lower', vmin = 0, vmax = 1, cmap = 'gray')

    # cache the background
    bkg = fig.canvas.copy_from_bbox(ax.bbox)

    # loop over frames
    raw_input('Press any key to start the animation...')
    for t in range(movie.shape[0]):
        # draw movie
        img.set_data(movie[t])
        fig.canvas.restore_region(bkg)
        ax.draw_artist(img)
        fig.canvas.blit(ax.bbox)

    return

if __name__ == "__main__":
    movie = np.random.rand(1000, 10, 10)
    animate(movie)
    pass