简体   繁体   English

使用 Matplotlib (Python) 动画条形图

[英]Animating a bar graph with Matplotlib (Python)

I recently wrote this to scrape a log and show a matplotlib.pyplot.bar plot of the most used words in it我最近写这篇文章是为了抓取日志并显示其中最常用的单词 matplotlib.pyplot.bar plot

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)

I would love to animate said plot, however, I can't grasp animation.FuncAnimation()我很想为 plot 制作动画,但是,我无法理解animation.FuncAnimation()

Can you help me out?你能帮我吗?

I added these lines:我添加了这些行:

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

and deleted plt.show()并删除plt.show()

So I could give FuncAnimation an empty figure (fig) and the function.所以我可以给 FuncAnimation 一个空图(图)和 function。 But it doesn't work.但它不起作用。 EDIT: And it doesn't print an error either.编辑:它也不会打印错误。

The main problem is that FuncAnimation expects a callable which returns artist objects.主要问题是FuncAnimation需要一个返回艺术家对象的可调用对象。 The callable will be called repeatedly with a frame argument.将使用框架参数重复调用可调用对象。

In your example, set_plot() is called once.在您的示例中, set_plot()被调用一次。 It's return value ( None ) is passed to FuncAnimation .它的返回值( None )被传递给FuncAnimation Instead you should have a method, eg update_plot() , which loads the data from the file, updates the bar plot and returns the bar plot.相反,您应该有一个方法,例如update_plot() ,它从文件中加载数据,更新条形 plot 并返回条形 plot。 This function (the function itself) should be passed to FuncAnimation这个 function(function 本身)应该传递给FuncAnimation

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

without calling it!没有调用它! Note the missing parenthesis after update_plot .请注意update_plot后缺少的括号。 The animitation documentation shows examples how this can be done.动画文档显示了如何做到这一点的示例。

It seems your data is static (you get it from file once and it doesn't change), so I don't really understand what you are trying to animate.看来您的数据是 static (您从文件中获取一次并且它不会改变),所以我不太明白您要制作什么动画。 But, your code contains errors that need to be fixed, so for demonstration purposes I will add increment each of the heights in each step of animation.但是,您的代码包含需要修复的错误,因此出于演示目的,我将在 animation 的每个步骤中添加每个高度的增量。

The first mistake is in the way you pass arguments to your function.第一个错误是您将 arguments 传递给 function 的方式。 For arguments you have to use fargs parameter, otherwise in your version you are passing the result of function not the function itself.对于 arguments 您必须使用fargs参数,否则在您的版本中,您传递的结果是 function 而不是 function 本身。

You must have a function ( animate in my version, set_plot in yours) that updates the plot for each step of your animation.你必须有一个 function (我的版本中是animate ,你的版本中是set_plot ),它为 animation 的每个步骤更新 plot。 (in your case you just put the same data every time) (在您的情况下,您每次只需输入相同的数据)

That function needs to accept at least one parameter ( val ) which is used my FuncAnimation which passes values got from iterator passed to its frames parameter. function 需要接受至少一个参数( val ),该参数用于我的FuncAnimation ,它将从迭代器获得的值传递给它的frames参数。

The final code looks like this最终代码如下所示

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)

and we get the following animation:我们得到以下 animation:

动画


Edit :编辑

For errors you can try to save your animation to gif, and the errors will show up对于错误,您可以尝试将 animation 保存为 gif,然后会显示错误

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM