【问题标题】:matplotlib generate animation, each file is a new framematplotlib生成动画,每个文件都是一个新帧
【发布时间】:2012-07-30 06:12:05
【问题描述】:

首先,我要感谢任何能让我提前完成此任务的人。我是 Matplotlib 的新手,一般也不用 python 编码。

我拥有大量的数据文件(100 到 10,000 个)。这些文件中的每一个都有 20 个我想变成动画的图,其中每个文件代表一个不同的帧。代码在试图让事情正常工作时变得非常复杂。有 6 个子图 (3,2,1-6)。它们都共享相同的 x 轴。在任何给定的子图上,我都绘制了 1 到 6 个 y 值。他们还需要正确的标签,有些是“符号日志”图,因为我想查看正数和负数的对数数据。我希望在不依赖 ffmpeg 或 mencoder 的情况下形成动画,因为它们在运行代码的计算机上可能不可用。似乎解决这个问题的明显方法在于 FuncAnimation,但这真的让我非常困惑。我见过的大多数示例只是在单个图中添加了另一个点。我想在基本上 20 个图中替换数据。我将只包括两个子图,并假设我足够聪明,可以将其推断为 6...

我已经成功地在单独的“安全”文件中将绘图形成为 .png 文件。

这里有一些非常非常难看的代码:

#!/usr/bin/python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import matplotlib.animation as animation
import glob
import os
import re
from StringIO import StringIO
from matplotlib.ticker import MaxNLocator
from matplotlib.font_manager import FontProperties

def GetFiles(dir_name, extension):
    fileList = []
    for file in os.listdir(dir_name):
        index = file.find(extension)
        if index != -1:
            dirfile = os.path.join(dir_name, file)
            fileList.append(dirfile)
    return fileList

dirString = raw_input('Please enter a directory name: ')
extension = raw_input('Please enter the extension: ')
ClearFiles = raw_input('Remove temporary .png files (Y/N): ')
dataName = GetFiles(dirString, extension)
print dataName  #just make sure right files are being loaded
pngfilelist = []

figure = plt.figure()
fontP = FontProperties()
fontP.set_size('small')

ax1 = figure.add_subplot(1,2,1)
ax1.grid(True)  # Enable Grid Lines
ax1.legend(loc=9, ncol=6, borderaxespad=0., prop=fontP)
ax1.set_title('Band Diagram')
PsiPlot, = ax1.plot([], [], label='Psi')
EcPlot, = ax1.plot([], [], label='Ec')
EvPlot, = ax1.plot([], [], label='Ev')
ax1.legend(loc=9,ncol=6, borderaxespad=0., prop=fontP)
ax2 = figure.add_subplot(1,2,2, sharex=ax1)
NPlot, = ax2.plot([], [], label='n')
PPLot, = ax2.plot([], [], label='p')
ax2.grid(True)  # Enable Grid Lines
ax2.set_title('Electron/Hole Concentrations')
ax2.legend(loc=9,ncol=2, borderaxespad=0., prop=fontP)
X = []
Psi = []
Ec = []
Ev = []
n = []
p = []


def UpdatePlot(dataFile):
    data = np.genfromtxt(dataFile, autostrip=True, skip_header=4, names=True, usecols=("X", "Psi", "Ec", "Ev", "n", "p"))  #Load the specified data into giant list

    entries = len(data)
    for ctr in range(0,entries):
        X.append(data[ctr][0])  # X-value for all plots
        Psi.append(data[ctr][1])    #plot 1,1
        Ec.append(data[ctr][2])
        Ev.append(data[ctr][3])
        n.append(data[ctr][4]) # plot 1,2
        p.append(data[ctr][5])

    figure.suptitle(dataFile, y=0.99)
    PsiPlot.set_data(X, Psi)
    EcPlot.set_data(X, Ec)
    EvPlot.set_data(X, Ev)
    NPlot.set_data(X, n)
    PPlot.set_data(X, p)

    plt.subplot(1,2,1)
    plt.xlabel('Position (cm)')
    plt.ylabel('Energy (eV)')

    plt.subplot(1,2,2)
    plt.xlabel('Position (cm)')
    plt.ylabel('cm^-3')
    plt.yscale('symlog', linthreshy=1e10)

    figure.set_size_inches(16,10)
    figure.set_dpi(200)

    plt.tight_layout(pad=0.2, w_pad=0.2, h_pad=0.2)
    filename = dataFile.replace(extension, '.png')
    plt.savefig(filename)
    pngfilelist.append(filename)

    return PsiPlot, EcPlot, EvPlot, NPlot, PPlot,

ani = animation.FuncAnimation(figure, UpdatePlot, dataName, interval=500, blit=True)

ani.save('test.mp4', fps=15)

# remove the temporary png files if wanted.
if ClearFiles == 'y' or ClearFiles == 'Y':
    for fname in pngfilelist:
        os.remove(fname)

我意识到的事情: 附加数据不是获取列表中所有 X 和 Y 数据的最佳方式。第二组数据还将包括在此 sn-p 中写入的第一组数据(寻找删除它的好方法,这样以后不会导致问题)。由于我尝试了各种方法,然后将它们删掉,因此导入的内容可能比我目前需要的要多得多。使用这种方法,X/Y 比例不会自动设置,因为我试图做的只是保存到 .png 文件(我通过 plt.plot 完成所有操作并在保存后清除,而不是所有这些关于将数据设置为轴)。例如,我想用最低的 Ev 设置最低的 Y 值,用最高的 Psi 设置最高的 Y 值。此外,在第二个情节上似乎没有任何效果。当然,这些值非常大。

使用此代码,我收到“未找到标记的对象”的警告。和一个运行时错误,说基础 C/C++ 对象已被删除 - 我在刚才的绘图中没有收到两个错误并保存到 .png 文件代码。

不过,我真的不知道如何将所有这些图表导入 FuncAnimation。

有什么想法吗?我已经厌倦了用 Python 敲打我的脑袋——我真的需要敲打我的模拟代码。

最后,这是一个旧(坏)数据文件的示例部分:

Data from: TestLoad.dev
Simulation time: 4.08738e-013
Iteration : 665
Data binning: 5
Point          X            Psi             Ec             Ev          Fermi        Fermi_n            Efp              n              p            n*p            Rho    Ec_Carriers    Ev_Carriers      Light_Gen  Generation_Th Recomb_Thermal      SRH_Rate1      SRH_Rate2      SRH_Rate3      SRH_Rate4           Jn_x           Jp_x
0       4.9e-006           3.58      -0.500001      -0.500001           -0.5           -0.5      -0.500001   2.72507e+021   2.72507e+021   7.42603e+042              0   2.67057e+008   2.67057e+008              0              0              0              0              0              0              0        4577.65              0
1      9.95e-006           3.58           -0.5           -0.5           -0.5      -0.499999           -0.5   2.72508e+021   2.72508e+021   7.42603e+042              0   8.17523e+006   8.17523e+006              0              0              0              0              0              0              0              0        -114441
2     1.015e-005        3.61356      0.0255559       -1.09444       -0.95916       -0.95916      -0.830208              0   1.08799e+015              0      -0.132665              0       0.971429              0              0              0              0              0              0              0              0        -114441
3     1.025e-005        3.62841      0.0404132       -1.07959      -0.944094      -0.944094      -0.844848              0   2.89096e+015              0      -0.132656              0        3.02857              0              0              0              0              0              0              0              0        -119019
4     1.035e-005        3.64199      0.0539899       -1.06601      -0.930857      -0.930857      -0.854293              0   9.46844e+015              0      -0.131488              0        10.3143              0              0              0              0              0              0              0              0        -114441
5     1.045e-005         3.6543      0.0662974        -1.0537      -0.919519      -0.919519      -0.867723              0   2.36441e+016              0      -0.129511              0        21.6571              0              0              0              0              0              0              0              0        -123596
6     1.055e-005        3.66535      0.0773546       -1.04265      -0.909748      -0.909748      -0.873209              0   4.47623e+016              0      -0.125061              0        48.4286              0              0              0              0              0              0              0              0       -96130.6
7     1.065e-005         3.6752      0.0872047        -1.0328      -0.901449      -0.901449      -0.876584              0    6.9861e+016              0        -0.1222              0        66.2857              0              0              0              0              0              0              0              0        -146485
8     1.075e-005        3.68388      0.0958752       -1.02412      -0.895041      -0.895041      -0.880708              0   1.18029e+017              0      -0.113068              0        124.286              0              0              0              0              0              0              0              0       -86975.3
9     1.085e-005        3.69145       0.103454       -1.01655      -0.889233      -0.889233      -0.879943              0   1.57625e+017              0      -0.111058              0        136.829              0              0              0              0              0              0              0              0        -137329
10     1.095e-005        3.69796       0.109961       -1.01004      -0.885743      -0.885743      -0.881837              0   2.16895e+017              0     -0.0941347              0        240.457              0              0              0              0              0              0              0              0       -22888.2
788     0.00998975        4.19373       0.605734      -0.514266        -0.3792        -0.3792      -0.287991              0   5.78298e+015              0      -0.131942              0        5.48571              0              0              0              0              0              0              0              0          77820
789     0.00998985        4.17975       0.591751      -0.528249      -0.393181      -0.393181      -0.292558              0   2.27746e+015              0      -0.132404              0            1.6              0              0              0              0              0              0              0              0        68664.7
790      0.0099904           4.08  -1.45745e-006  -1.45745e-006   3.16863e-016   4.06816e-008  -7.67735e-007   2.72507e+021   2.72507e+021   7.42603e+042              0   2.72507e+007   2.72507e+007              0              0              0              0              0              0              0              0              0
791     0.00999545           4.08  -1.45745e-006  -1.45745e-006   3.16863e-016   4.06816e-008  -7.67735e-007   2.72507e+021   2.72507e+021   7.42603e+042              0   2.47982e+008   2.47982e+008              0   6.27943e+027              0              0              0              0              0              0              0

以防未来人们看到这一点,在我开始投入所有其他情节之前,这就是我最终的简化答案(概念证明)。

#!/usr/bin/python
import numpy as np
import matplotlib as mpl
mpl.use( "agg" )
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import os
from StringIO import StringIO
from matplotlib.font_manager import FontProperties

def GetFiles(dir_name, extension):
    fileList = []
    for file in os.listdir(dir_name):
        index = file.find(extension)
        if index != -1:
            dirfile = os.path.join(dir_name, file)
            fileList.append(dirfile)
    return fileList

def UpdatePlot(dataFile):
    global MinX, MaxX, ax1MinY, ax1MaxY, ax2MinY, ax2MaxY, first
    print 'loading data for ', dataFile
    data = np.genfromtxt(dataFile, autostrip=True, skip_header=4, names=True, usecols=("X", "Psi", "Ec", "Ev", "n", "p"))  #Load the specified data into giant list

    # get new bounds on limits for graphs

    tempMin = data['X'].min()
    tempMax = data['X'].max()
    if tempMax > MaxX or first == True:
        MaxX = tempMax + (tempMax - tempMin) * 0.01
        ax1.set_xlim(MinX, MaxX)
        ax2.set_xlim(MinX, MaxX)
    if tempMin < MinX or first == True:
        MinX = tempMin - (tempMax - tempMin) * 0.01
        ax1.set_xlim(MinX, MaxX)
        ax2.set_xlim(MinX, MaxX)

    tempMin = data['Psi'].min()
    tempMax = data['Psi'].max()
    if tempMax > ax1MaxY or first == True:
        ax1MaxY = tempMax + (tempMax - tempMin) * 0.5
        ax1.set_ylim(ax1MinY, ax1MaxY)

    tempMin = data['Ev'].min()
    tempMax = data['Ev'].max()
    if tempMin < ax1MinY or first == True:
        ax1MinY = tempMin - (tempMax - tempMin) * 0.2
        ax1.set_ylim(ax1MinY, ax1MaxY)

    tempMax = data['n'].max()
    if tempMax > ax1MaxY or first == True:
        ax2MaxY = tempMax * 2    # This is basically a log plot...
        ax2.set_ylim(ax2MinY, ax2MaxY)

    tempMax = data['p'].max()
    if tempMax > ax1MaxY or first == True:
        ax2MaxY = tempMax * 2    # This is basically a log plot...
        ax2.set_ylim(ax2MinY, ax2MaxY)

    # Now update all the data for the plots

    titleText.set_text(dataFile)
    PsiPlot.set_data(data['X'], data['Psi'])
    EcPlot.set_data(data['X'], data['Ec'])
    EvPlot.set_data(data['X'], data['Ev'])
    NPlot.set_data(data['X'], data['n'])
    PPlot.set_data(data['X'], data['p'])

    plt.draw()  # need to update the figure regardless because the title changes
    if GeneratePNG == 'Y' or GeneratePNG == 'y':
        filename = dataFile.replace(extension, '.png')
        plt.savefig(filename)

    first = False

    return

dirString = raw_input('Please enter a directory name: ')
extension = raw_input('Please enter the extension: ')
GeneratePNG = raw_input('Generate .png files of each file (Y/N): ')
framesps = raw_input('Frames per second: ')
outname = raw_input('Output file name (no extension): ')
outname = outname + '.mp4'
dataName = GetFiles(dirString, extension)
# print dataName

MinX = 0
MaxX = 0
ax1MinY = 0
ax1MaxY = 0
ax2MinY = 0
ax2MaxY = 0
first = True

figure = plt.figure()
fontP = FontProperties()
fontP.set_size('small')
figure.set_size_inches(16,10)
figure.set_dpi(200)
titleText = figure.suptitle('Title', y=0.99)  # must do this way to allow title to be changed later

ax1 = figure.add_subplot(1,2,1)
ax1.grid(True)  # Enable Grid Lines
ax1.set_title('Band Diagram')
plt.xlabel('Position (cm)')
plt.ylabel('Energy (eV)')
PsiPlot, = ax1.plot([], [], label='Psi')
EcPlot, = ax1.plot([], [], label='Ec')
EvPlot, = ax1.plot([], [], label='Ev')
ax1.legend(loc=9,ncol=6, borderaxespad=0., prop=fontP)

ax2 = figure.add_subplot(1,2,2, sharex=ax1)
plt.xlabel('Position (cm)')
plt.ylabel('cm^-3')
plt.yscale('symlog', linthreshy=1e10)
ax2.grid(True)  # Enable Grid Lines
ax2.set_title('Electron/Hole Concentrations')
NPlot, = ax2.plot([], [], label='n')
PPlot, = ax2.plot([], [], label='p')
ax2.legend(loc=9,ncol=2, borderaxespad=0., prop=fontP)

plt.tight_layout(pad=0.5, w_pad=0.5, h_pad=0.5)

ani = mpl.animation.FuncAnimation(figure, UpdatePlot, dataName, init_func=None, interval=500, blit=True)

ani.save(outname, fps=framesps, codec='mpeg4')

再次感谢您为我指明正确的方向!

【问题讨论】:

  • 只是为了让我了解您正在尝试做的基本事情:您有大量的数据文件,每个文件都代表一个时间戳。对于每个时间戳,您绘制了一些计算值与 x 的关系(20 个图,因为我看到了一些 20+ 列)。但是为什么/如何出现各种子图和子图;您是否尝试将尽可能多的数据压缩到几个图中?还是这 20 个地块都是这些子地块?
  • 至于为什么所有子图和数据压缩 - 这可能会有所帮助:link 我正在尝试调试蒙特卡洛代码,我需要一次可视化所有数据以查看是什么碰巧试图了解事情是什么以及如何搞砸的。有些数据可以很好地结合在一起,而其他数据必须一次显示出来才有真正的意义。
  • 如果你厌倦了用python敲打你的头,也许你应该尝试用另一种方式解决你的问题。但是,我认为将您的问题(和您的问题)分解为一些子问题(对于您和尝试回答您的问题的用户)会很有用。

标签: python animation matplotlib


【解决方案1】:

好的,我已经深入研究了您的代码。我可以看到一些东西。

首先,如果发生错误,请始终尝试提供完整的回溯。在这种情况下,错误是相当不错的 googleable(*),并导致我例如RuntimeError: underlying C/C++ object has been deleted when saving and afterwards closing a pyplot figure。这表明 pyqt 有问题;显然,这是您的默认后端。

因此,正如该页面上的答案所示,尝试更改您的后端:

import matplotlib as mpl
mpl.use( "agg" )

由于您只是保存文件,因此您不需要交互式后端。 “agg”是一个非交互式的,所以没有带有情节的弹出窗口,你只能保存到磁盘。 这可能会解决 RuntimeError。我并没有真正为标签错误而烦恼,尽管我猜你正试图将标签放在实际数据不存在的图上。也许这是未使用的第 6 个地块(因为我在任何地方都看不到第 6 个地块)?

在读取数据时:您现在似乎将下一组数据追加到当前数据中。那是对的?还是您想更换它? 如果替换,只需执行以下操作:

Psi = data['Psi']

等等。当然没有for循环。或者更简单,只有:

PsiPlot.set_data(data['X'], data['Psi'])

如果您要追加,那就有点棘手了,但我猜您可以执行以下操作。首先,初始分配需要是 numpy 数组(再次仅显示 Psi):

Psi = nparray([])

那么,追加变成:

Psi = np.concatenate((Psi, data['Psi']))

(注意双括号。同样,没有 for 循环)。

我注意到您以这种方式收到 UnboundLocalError。看起来默认 Python 对象(诸如 [] 之类的列表)会自动在函数内部找到,但像 numpy.ndarray(上面的 Psi 是)这样的命名空间对象却不是。因此,在 UpdatePlot 开始时,您需要:

global X, Psi, Ec, Ev, n, p

以便 Python 找到要附加到的正确对象。

最后,您提到您不想要 mencoderffmpeg 依赖项,但在后台,matplotlib.animation.save() 调用这些程序。例如,我尝试运行您的脚本并得到一个 RuntimeError,因为我的系统上没有安装 ffmpeg。因此,在尝试在其他地方运行此代码时请注意这一点。我不知道只有 Python 的 mpeg 编码器。

(*) 事实上,你可能也可以。我猜您对整个过程和 Python 脚本感到非常沮丧,这意味着您没有将问题分解为错误和其他细节,因为您提到了几个问题。可能没问题,但像往常一样,它会分散实际问题的注意力。

【讨论】:

  • 谢谢,我会看看我能用这个做什么。我之前只进行了追加,因为我尝试传入数据,但它会从错误的索引(一行 X、Psi、Ec、Ev...)发送数据。这是一个丑陋的解决方法。一点也不快...我试图避免 mencoder 和 ffmpeg 因为它们也不在我的系统上,我将在其他计算机上运行它,这些计算机也没有它们。我想我会硬着头皮安装它们。我已经无法使用 Python 了,但是使用 matplotlib 制作图表会比通过 Origin 快得多……谢谢大家,我会告诉你它是如何工作的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 2022-12-09
  • 2017-06-21
相关资源
最近更新 更多