3

まず、事前にこれを乗り越えてくれた人に感謝します。私はMatplotlibを初めて使用し、通常はPythonでもコーディングしません。

私が持っているのは膨大な数のデータファイル(100から10,000)です。これらの各ファイルには、アニメーションに変換したい20のプロットがあり、各ファイルは異なるフレームを表しています。コードは、物事を機能させるために非常に複雑になっています。6つのサブプロット(3,2,1-6)があります。それらはすべて同じx軸を共有します。任意のサブプロットで、1〜6個のy値がプロットされています。また、適切なラベルが必要であり、対数データを正と負の両方で表示したいので、いくつかは「symlog」プロットです。コードを実行しているコンピューターでは利用できない可能性があるため、ffmpegやmencoderに依存せずにアニメーションを作成したいと思います。これに対する明らかな解決策はFuncAnimationにあるようですが、それは本当に私を混乱させすぎます。ほとんどの例私は 単一のプロットに別のポイントを追加するだけです。基本的に20プロットのデータを置き換えたいと思います。2つのサブプロットだけを含め、それを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データを取得するための最も良い方法ではありません。2番目のデータセットには、このスニペットに記述されている最初のデータセットも含まれます(後で問題を引き起こさない、データを削除するための適切な方法を探しています)。いろいろ試してみて、切り取ってみたので、今必要以上に輸入品が多いのではないでしょうか。この方法を使用すると、X / Yスケールは、.pngファイルに保存するだけの場合のように自動的に設定されません(データの設定に関するこれらすべてのことの代わりに、plt.plotを介してすべてを実行し、保存後にクリアします軸)。たとえば、最小のY値を最小のEvで設定し、最大のY値を最大のPsiで設定したいと思います。また、2番目のプロットでは何も機能していないようです。確かに、値は非常に大きいです。

このコードでは、「ラベルの付いたオブジェクトが見つかりません」という警告が表示されます。基になるC/C++オブジェクトが削除されたことを示すランタイムエラー-プロットして.pngファイルコードに保存するだけでは受け取れない2つのエラー。

しかし、これらすべてのグラフを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

Ok, I've delved a bit more into your code. There are a few things I can see.

First of all, always try and provide a full backtrace if an error occurs. In this case, the error was reasonably well googleable(*), and lead me to e.g. RuntimeError: underlying C/C++ object has been deleted when saving and afterwards closing a pyplot figure. It's indicative of a problem with pyqt; apparently, that is your default backend.

So, as the answer on that page suggests, try changing your backend:

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

Since you're just saving the files anyway, you don't need an interactive backend anyway. "agg" is a non-interactive one, so no pop-ups with plots, you can only save to disk. That may solve the RuntimeError. I haven't really bothered with the labeling error, though I guess that you're trying to put labels on plots where the actual data are not there. Perhaps this is the unused 6th plot (because I don't see that 6th plot anywhere)?

On reading the data: it seems you now append the next set of data to the current data. That is correct? Or did you want to replace it? If replacing, simply do something like:

Psi = data['Psi']

etc. Without the for-loop of course. Or even simpler, only:

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

If you are appending, it's a bit trickier, but you can do the following I guess. First, the initial assignments need to be numpy arrays (showing only for Psi again):

Psi = nparray([])

Then, appending becomes:

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

(Note the double set of parenthesis. Again, without the for loop).

I noticed that you get a UnboundLocalError this way. It looks like default Python objects (lists such as []) are automatically found inside a function, but a namespaced object like a numpy.ndarray (which Psi above is), is not. Therefore, at the start of your UpdatePlot, you need to have:

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

So that Python finds the right objects to append to.

Lastly, you mentioned you don't want an mencoder or ffmpeg dependency, but under the hood, matplotlib.animation.save() calls these programs. E.g., I tried to run your script and got a RuntimeError, because ffmpeg was not installed on my system. So be aware of this when trying to run this code elsewhere. I don't know of a Python-only mpeg encoder.

(*) In fact, probably so could you. I guess the fact that you got too frustrated by the whole process and Python script meant you didn't split the question up in the error and other details, because you mentioned several issues. It's probably ok, but as usual, it distracts from the actual problem.

于 2012-07-30T09:34:54.370 に答える