【发布时间】: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