在Matplotlib上制作大量数据动画的正确方法?

时间:2018-05-02 16:47:28

标签: python python-3.x python-2.7 matplotlib

我正在处理一个涉及数十个文件的项目,每个文件都有数百个点,每个文件代表matplotlib上的一行,这些文件将由另一个软件自动更新,我的目标是不断绘制它们的内容,第一种文件具有以下格式:

"Convergence history of Static Temperature on p14 (in SI units)"
"Iteration" "Vertex Average Static Temperature"
10 358.3162536621094
20 369.484375
30 375.3867797851562
40 378.8209228515625
50 380.5880432128906
60 381.4667663574219
70 381.8531494140625
80 381.9440307617188
...

第一个数字代表"X"轴,第二个代表"Y",这是".out",很容易解析这些数据甚至动画。

具有以下格式的另一种文件包含要在matplotlib上绘制的5行,其格式如下:

1 {{continuity 1.0000e+00} {x-velocity 0.0000e+00} {y-velocity 4.3827e-02} {z-velocity 1.9319e-03} {energy 1.2276e-07} }
2 {{continuity 1.0000e+00} {x-velocity 7.8061e-04} {y-velocity 1.6308e+01} {z-velocity 1.0320e-03} {energy 2.9296e-06} }
3 {{continuity 2.3509e-01} {x-velocity 1.2848e-03} {y-velocity 1.2352e-02} {z-velocity 1.0337e-02} {energy 2.2715e-06} }
4 {{continuity 8.0945e-02} {x-velocity 1.6650e-03} {y-velocity 1.3073e-02} {z-velocity 1.0491e-02} {energy 3.2993e-07} }

第一个数字代表"X"轴,大括号"{}"之间的每个行/名称都有"Y "值,其扩展名为{{1}我正在使用正则表达式来解析他们的数据。

预期行为

代码应该读取所​​有文件,按类别排序,然后我会在每个类别上调用animate函数,animate函数将读取类别上的每个文件,并将其绘制到matplotlib图形,每隔x个时间。

问题

现在代码部分工作,因为它的效率非常低,在动画函数再次执行之前,它甚至没有完成读取它需要绘制的所有文件,我相信正则表达式这是一个很大的问题,因为它比较慢,我需要找到一种方法来读取最新点而不是重新绘制所有文件。

  • 我是否应该在动画之间有更长的时间?
  • 我应该在每个文件而不是每个类别上调用动画吗? (我可能同时运行大约20-30个动画功能)那是不是很糟糕?
  • 我应该使用线程来提高性能吗?

  • 我是否面临matplotlib动画功能的限制或只是执行不好?

代码:

查找要绘制文件的函数。

".res"

动画功能

def find_plot_files(self, file_path, n):
    project_name = file_path.split("/")[-1]  # Erase everything before the last slash:  /ab/bc/tu.out > tu.out
    project_name = project_name[:project_name.find(".")]
    current_project = self.controller.project_list.create_project(project_name, file_path)
    file_path = os.path.dirname(file_path)

    for file in os.listdir(file_path):
        graph_name = file[file.find(".") + 1:file.rfind(".")]
        if file.endswith(".out"):
            if project_name in file:
                current_file = open(file_path + "/" + file, 'r').read()
                if 'Temperature' in current_file:
                    current_project.insert_graph('Temperature', graph_name, file_path+"/"+file)
                elif 'Pressure' in current_file:
                    current_project.insert_graph('Pressure', graph_name, file_path+"/"+file)
                elif 'Velocity' in current_file:
                    current_project.insert_graph('Velocity', graph_name, file_path+"/"+file)
        elif file.endswith(".res"):
            if project_name in file:
                current_project.insert_graph('Residuals', graph_name, file_path+"/"+file)

#Here every "graph" represents a category, and i will create a figure and plot every line into it.

    for graph in self.controller.project_list.get_project(project_name).get_graphs():
        f = Figure(figsize=(5, 5), dpi=100)
        a = f.add_subplot(111)
        canvas = FigureCanvasTkAgg(f, self)
        f.suptitle(graph)
        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        toolbar = NavigationToolbar2Tk(canvas, self)
        toolbar.update()
        canvas._tkcanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.animated_graph.append(animation.FuncAnimation(f, self.animate, fargs=(a, project_name, graph),
                                                           interval=3000))

我使用matplotlib和animate函数真的很新,所以任何帮助都会非常感激!

提前致谢!

1 个答案:

答案 0 :(得分:1)

当您提出几个问题并且我不是动画专家时,请让我先提示阅读数据:

或许依靠可用python包的导入器功能会更快,这些包针对像pandas这样的任务进行了优化。

import pandas as pd

这对于你的' -files非常简单:

In:pd.read_csv(filename, skiprows=1, sep=' ')
Out: 
   Iteration  Vertex Average Static Temperature
0         10                         358.316254
1         20                         369.484375
2         30                         375.386780
3         40                         378.820923
4         50                         380.588043
5         60                         381.466766
6         70                         381.853149
7         80                         381.944031

' .res' -files看起来更复杂,但你可以先看看它们:

pd.read_table(filename, names=None, sep='[{}\s]+', engine='python')

   1  continuity  1.0000e+00  x-velocity  0.0000e+00  y-velocity  4.3827e-02  \
0  2  continuity    1.000000  x-velocity    0.000781  y-velocity   16.308000   
1  3  continuity    0.235090  x-velocity    0.001285  y-velocity    0.012352   
2  4  continuity    0.080945  x-velocity    0.001665  y-velocity    0.013073   

   z-velocity  1.9319e-03  energy    1.2276e-07  Unnamed: 11  
0  z-velocity    0.001032  energy  2.929600e-06          NaN  
1  z-velocity    0.010337  energy  2.271500e-06          NaN  
2  z-velocity    0.010491  energy  3.299300e-07          NaN  

从此结果中,您可以检索您感兴趣的列号,并在将来使用此信息进行导入:

pd.read_table(filename, usecols=[2,4,6,8,10], names=['x', 'x-vel', 'y-vel', 'z-vel', 'energy'], sep='[{}\s]+', engine='python')

          x     x-vel      y-vel     z-vel        energy
0  1.000000  0.000000   0.043827  0.001932  1.227600e-07
1  1.000000  0.000781  16.308000  0.001032  2.929600e-06
2  0.235090  0.001285   0.012352  0.010337  2.271500e-06
3  0.080945  0.001665   0.013073  0.010491  3.299300e-07

结果是pandas数据帧,它提供了一组非常大的函数供进一步处理,包括只是在你喜欢的时候访问它们的值的np.array表示。

也许这会有所帮助。