动画制作条形图

3

我最近编写了一个程序来抓取日志并展示其中最常用单词的 matplotlib.pyplot.bar 图形。

import re
from datetime import datetime
from collections import Counter

import matplotlib.pyplot as plt
from matplotlib import animation

def read_log(path, index, separator=chr(9)):
    data = []
    my_file = open(path,"r+")
    rows = my_file.readlines()
    for row in rows:
        line = re.sub(r'\r\n|\r|\n','',row, flags=re.M)
        if line != '':
            data.append(line.split(separator)[index])
    my_file.close()
    return Counter(data)
   
def set_plot(counter_data):
    plt.title('This is a title')
    plt.bar(range(len(counter_data)), list(counter_data.values()), align='center')
    plt.xticks(range(len(counter_data)), list(counter_data.keys()))
    plt.tight_layout()
    plt.show()

counter_data = read_log(r'logfile.txt',2)
print(counter_data)
set_plot(counter_data)

我很想实现这个动画效果,但是我无法理解 animation.FuncAnimation()

你能帮我一下吗?

我添加了以下这些代码:

fig = plt.Figure()
animation.FuncAnimation(fig, set_plot(counter_data), frames=20)

删除了plt.show()

这样我就可以给FuncAnimation一个空的图形(fig)和函数,但它不起作用。编辑:它也不会打印错误。

2个回答

2

看起来你的数据是静态的(你一次从文件中获取它并且不会改变),所以我不太明白你想要做什么动画。但是,你的代码包含需要修复的错误,因此为了演示目的,我将在每个动画步骤中增加每个高度的值。

第一个错误在于你传递参数的方式。对于参数,你必须使用fargs参数,否则在你的版本中,你传递的是函数的结果而不是函数本身。

你必须有一个函数(在我的版本中是animate,在你的版本中是set_plot),它更新每个动画步骤的图表。(在你的情况下,你每次都放置相同的数据)

该函数至少需要接受一个参数(val),它由FuncAnimation使用,FuncAnimation将迭代器传递给其frames参数。

最终代码如下:

import re
from datetime import datetime
from collections import Counter
import matplotlib.pyplot as plt
from matplotlib import animation
# uncomment if using in jupyter notebook
# %matplotlib nbagg 

def read_log(path, index, separator=chr(9)):
    data = []
    my_file = open(path,"r+")
    rows = my_file.readlines()
    for row in rows:
        line = re.sub(r'\r\n|\r|\n','',row, flags=re.M)
        if line != '':
            data.append(line.split(separator)[index])
    my_file.close()
    return Counter(data)

fig = plt.figure()
ax = fig.add_subplot()
counter_data = read_log(r'tmp.csv',2)
plt.title('This is a title')
bar = ax.bar(range(len(counter_data)), list(counter_data.values()), align='center')
plt.xticks(range(len(counter_data)), list(counter_data.keys()))
plt.tight_layout()
plt.ylim((0, 30))


def animate(val, counter_data):
    data = list(counter_data.values())
    for i in range(len(data)):
        bar[i].set_height(data[i]+val)

animation.FuncAnimation(fig, func=animate, frames=20, fargs=[counter_data], save_count=10)

我们得到了以下动画:

animation


编辑

如果出现错误,您可以尝试将动画保存为gif格式,错误将显示出来。

anim = animation.FuncAnimation(fig, func=animate, frames=20, fargs=[counter_data], save_count=10)
anim.save('anim.gif', 'imagemagick')


谢谢Grigor,数据仍然是静态的,但是当日志文件中的数据发生更改时,它会“变化” :)它计算一组字符串的出现次数,因此每当日志更新时它都会发生变化 :) - Fabio Florey

0

主要问题在于FuncAnimation期望一个可调用对象,该对象返回艺术家对象。可调用对象将被重复调用,并带有一个帧参数。

在您的示例中,set_plot()只被调用一次。它的返回值(None)被传递给FuncAnimation。相反,您应该有一个方法,例如update_plot(),该方法从文件加载数据,更新条形图并返回条形图。这个函数(函数本身)应该被传递给FuncAnimation

 animation.FuncAnimation(fig, update_plot, frames=20)

不要调用它!注意 update_plot 后面缺少括号。 动画文档 显示了如何实现这一点的示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接