3

首先,我要感谢任何可以让我提前度过难关的人。我是 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 数据的最佳方式。第二组数据也将包括在此代码段中写入的第一组数据(寻找删除它的好方法,这样以后不会导致问题)。由于我尝试了各种方法,然后将它们删掉,因此导入的内容可能比我目前需要的要多得多。使用这种方法,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')

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

4

1 回答 1

5

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

首先,如果发生错误,请始终尝试提供完整的回溯。在这种情况下,错误是相当不错的 googleable(*),并导致我例如RuntimeError: undersing C/C++ object has been deleted when Saving and then close 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 就可以找到要附加到的正确对象。

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

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

于 2012-07-30T09:34:54.370 回答