2012-07-30 43 views
2

首先,我要感謝任何能夠讓我通過這個提前完成的人。我是Matplotlib的新手,並且通常不用python編寫代碼。matplotlib生成動畫,每個文件都是一個新框架

我擁有的是大量的數據文件(100'-10,000)。這些文件中的每一個都有20個我想要變成動畫的圖,其中每個文件表示不同的幀。代碼變得難以置信地令人費解,試圖讓事情發揮作用。有6個小區(3,2,1-6)。它們都共享相同的x軸。在任何給定的子圖上,我都有1到6個y值對它進行繪圖。他們還需要適當的標籤,有些是'symlog'圖,因爲我想查看對數數據的正面和負面。我希望動畫的形成不依賴於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完成所有操作並在保存後清除,而不是將所有這些數據設置爲一個軸)。例如,我想將最低的Y值設置爲最低的Ev,將最高的Y值設置爲最高的Psi。此外,第二個情節似乎沒有任何工作。當然,這些值非常大。

有了這段代碼,我得到了一個警告:「找不到標記的對象。」和一個運行時錯誤,說底層的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') 

再次感謝您指點我正確的方向!

+0

只是爲了讓我想起你要做的基本事情:你有大量的數據文件,每個文件代表一個時間戳。對於每個時間戳記,繪製一些計算值與x(20個圖表,因爲我看到大約20列)。但是,爲什麼/如何進行各種子圖和子圖;你是否儘量將數據壓縮成幾塊地塊?還是20個地塊都是這些子地塊? – Evert 2012-07-30 08:43:19

+0

至於爲什麼所有的subplots和數據壓縮 - 這可能會有所幫助:[鏈接](http://en.wikipedia.org/wiki/Band_diagram)我試圖調試蒙特卡洛代碼,我需要可視化所有的數據一次看到發生了什麼事情,試圖瞭解什麼和事情如何搞砸。有些數據很好地融合在一起,其他數據必須一次全部顯示,纔能有真正的意義。 – 2012-07-30 16:41:35

+0

如果你厭倦了蟒蛇頭,也許你應該嘗試用另一種方式解決你的問題。不過,我認爲將你的問題(和你的問題)分解爲一些子問題(對於你和試圖回答你的問題的用戶)是有用的。 – bmu 2012-07-30 17:02:59

回答

5

好的,我已經深入瞭解了一些代碼。有幾件事我可以看到。

首先,如果發生錯誤,請始終嘗試並提供完整的回溯。在這種情況下,這個錯誤非常合適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。我並沒有真正爲標籤錯誤感到困擾,但我猜你試圖在實際數據不存在的地塊上貼標籤。也許這是未使用的第六個情節(因爲我沒有在任何地方看到第六個情節)?

關於讀取數據:現在看來你現在追加下一組數據到當前數據。那是對的?還是你想替換它? 如果要更換,只是這樣做:

Psi = data['Psi'] 

等當然沒有for循環。或者更簡單,只有:

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

如果您正在追加,它有點棘手,但您可以執行以下操作我猜。首先,初始分配需要是numpy的陣列(僅再次表示PSI):

Psi = nparray([]) 

然後,追加變得:

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

(注意雙組括號接下來,沒有爲循環)。

我注意到你這樣得到了一個UnboundLocalError。它看起來像默認的Python對象(像[]這樣的列表)是在一個函數內部自動找到的,但是像numpy.ndarray這樣的命名空間對象(就是上面的Psi)不是。因此,在UpdatePlot開始時,您需要:

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

因此,Python會找到要附加到的正確對象。

最後,你提到你不想要一個mencoderffmpeg依賴關係,但在引擎蓋下,matplotlib.animation.save()調用這些程序。例如,我試圖運行你的腳本並得到一個RuntimeError,因爲ffmpeg沒有安裝在我的系統上。所以當試圖在其他地方運行此代碼時請注意這一點。我不知道只有Python的mpeg編碼器。

(*)其實你可能也是這樣。我猜你對整個過程和Python腳本感到非常沮喪,這意味着你沒有把錯誤和其他細節分開,因爲你提到了幾個問題。這可能是好的,但像往常一樣,它會分散實際問題。

+0

謝謝,我會看看我能用這個做什麼。我之前只做了append,因爲我嘗試傳入數據,但它會從錯誤的索引(X,Psi,Ec,Ev ......的一行)發送數據。這是一個醜陋的解決方法。一點都不快...... 我試圖避免mencoder和ffmpeg,因爲它們不在我的系統上,而且我將在其他計算機上運行它,它們也沒有它們。猜猜我會咬緊牙關並安裝它們。 我非常喜歡Python,但是使用matplotlib創建圖形將比通過Origin快得多......感謝噸,我會讓你知道它是如何工作的。 – 2012-07-30 16:33:02

相關問題