首先,我要感谢任何可以让我提前度过难关的人。我是 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')
再次感谢您为我指明正确的方向!