Animated Line Graph with Matplotlib/Python



我无法让我的折线图动画。

背景:我正在开发一个可以处理模拟网络延迟的程序,我正在尝试绘制延迟图,以便我可以看到我的程序跟上来自控制器的命令负载的程度。

我已经设置了我的图:

# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0,2), ylim = (-2,2))
line, = ax.plot([], [], lw=2)

设置init()animate()功能

# initialization function: plot the background of each frame
def init():
    line.set_data([], [])
    return line,
def animate(i):
    line.set_data(x[i], y[i])
    return line,

然后在我的 DelayedTask.process() 函数(我测量预期执行和实际执行之间的时间(中,我将值和索引附加到我的 x,y 列表中。

delta =  self.time - datetime.now()
lock = threading.Lock()
lock.acquire()
x.append(len(x))
y.append(delta.total_seconds())
lock.release()

最后,在程序的底部,我创建了动画功能。

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)

不幸的是,图表会显示,但数字不会绘制。我在 animate() 函数中放置了一个断点,并在增量中填充列表,但它不会在图表上显示任何线条。

以下是完整的代码:

import multiprocessing, requests, threading
import decimal
import random
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from queue import Queue
from multiprocessing.dummy import Pool as ThreadPool
from threading import Thread
from datetime import datetime, timedelta
class WorkQueue:
    def __init__(self, threads=6):
        self.threads = threads
    def process(self, work):
        pool = ThreadPool(self.threads)
        results = pool.map(DelayedTask.process, work)
        pool.close()
        pool.join()
class DelayedTask:
    def __init__(self, func, delay, message):
        print("DelayTask.__init__: {0}".format((func.__name__, delay, message)))
        self.func = func
        self.time = datetime.now() + timedelta(milliseconds=delay)
        self.message = message
    def process(self):
        delta =  self.time - datetime.now()
        lock = threading.Lock()
        lock.acquire()
        x.append(len(x))
        y.append(delta.total_seconds())
        lock.release()
        if delta.total_seconds() > 0.01:
            print('DelayTask.Process: Sleeping {0} millisecondsn'.format(round(delta.total_seconds() * 1000)))
            time.sleep(delta.total_seconds())
            self.func(self.message)

        elif delta.total_seconds() < 0.01 and delta.total_seconds() > 0:
            print('DelayTask.Process: Processing with {0} milliseconds remainingn'.format(round(delta.total_seconds() * 1000)))
            self.func(self.message)
        else:
            print("DelayTask.Process: Processing task: {0} milliseconds laten".format(round(delta.total_seconds() * -1000)))
            self.func(self.message)
        return True
    def __str__(self):
        return str((self.func.__name__, self.time, self.message))
def get(url):
    print("Requesting {0}".format(url))
    r = requests.get(url=url)
    print("get(url): Received response for {0} with Status Code {1}".format(url, r.status_code))
aggregatorq = multiprocessing.Queue()
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0,2), ylim = (-2,2))
line, = ax.plot([], [], lw=2)
x = []
y = []
# initialization function: plot the background of each frame
def init():
    line.set_data([], [])
    return line,
def animate(i):
    line.set_data(x[i], y[i])
    return line,
def collector():
    bucket = []
    while len(bucket) <= 10:
        task = aggregatorq.get()
        print("collector: aggregating Tasksn")
        bucket.append(DelayedTask(task['func'], task['delay'], task['message']))
        if(len(bucket) == 10):
            bucket.sort(key=lambda x: x.time, reverse=False)
            firsttask = bucket[0]
            firsttime =  firsttask.time - datetime.now()
            if firsttime.total_seconds() >= 0:
                print('collector: Sleeping {0} seconds until first task in bucketn'.format(firsttime.total_seconds()))
                time.sleep(firsttime.total_seconds())
            queue = WorkQueue(10)
            queue.process(bucket)
            bucket.clear()
def controller():
    print("Starting Controllern")
    finishtime = datetime.now() + timedelta(seconds=5)
    print("controller: Will finish at {0}n".format(finishtime))
    sites = ["att", "google", "hulu", "msn", "yahoo", "gmail"]
    while True:
        if datetime.now() > finishtime:
            print("Controller Finished")
            return;
        else:
            pass
            print("{0} remaining in controller..".format(finishtime - datetime.now()))
        requestdelay = random.randint(1, 20)
        randomsite = random.randint(0, len(sites)-1)
        aggregatorq.put({'func': get, 'delay': requestdelay, 'message': 'http://www.{0}.com'.format(sites[randomsite])})
t = threading.Thread(target=controller)
t2 = threading.Thread(target=collector)
# call the animator.  blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
                               frames=200, interval=20, blit=True)
def main():
    t.start()
    t2.start()
    plt.show()
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('Interrupted')
        t.join()
        t2.join()
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)

您的问题出在update函数中。使用语句

line.set_data(x[i], y[i])

每次调用update时,您只为线路分配一个数据点。因此,您看不到任何线条,因为线条仅在数据点之间绘制。要解决此问题,请省略索引:

line.set_data(x, y)

这样,将绘制所有收集的数据。

最新更新