我想制作多个情节的动画,其渲染随着时间的推移而演变。
我需要的文件采用以下格式,例如一个:
DD0043/DD0043
. 所以我使用技巧:f'{43:04}'
填充每个文件的前导零(文件DD0000/DD0000
从DD0922/DD0922
.
这里的脚本,警告,情节是用yt-project
工具完成的:
import yt
import os, sys
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import rc_context
from matplotlib import pyplot as plt
# animate must accept an integer frame number. We use the frame number
# to identify which dataset in the time series we want to load
def animate(i):
plot._switch_ds(array_data[i])
# Number of files
numFiles = int(os.popen('ls -dl DD* | wc -l').read())
# Array for each data directory
array_data = np.array(numFiles)
for i in range(numFiles):
data = yt.load('DD'+str(f'{i:04}')+'/DD'+str(f'{i:04}'))
sc = yt.create_scene(data, lens_type='perspective')
source = sc[0]
source.set_field('density')
source.set_log(True)
# Set up the camera parameters: focus, width, resolution, and image orientation
sc.camera.focus = ds.domain_center
sc.camera.resolution = 1024
sc.camera.north_vector = [0, 0, 1]
sc.camera.position = [1.7, 1.7, 1.7]
# You may need to adjust the alpha values to get an image with good contrast.
# For the annotate_domain call, the fourth value in the color tuple is the
# alpha value.
sc.annotate_axes(alpha=.02)
sc.annotate_domain(ds, color=[1, 1, 1, .01])
text_string = "T = {} Gyr".format(float(array_data[i].current_time.to('Gyr')))
fig = plt.figure()
animation = FuncAnimation(fig, animate, frames=numFiles)
# Override matplotlib's defaults to get a nicer looking font
with rc_context({'mathtext.fontset': 'stix'}):
animation.save('animation.mp4')
但在执行时,我收到以下错误:
923
Traceback (most recent call last):
File "vol-annotated.py", line 52, in <module>
animation.save('animation.mp4')
File "/Users/fab/Library/Python/3.7/lib/python/site-packages/matplotlib/animation.py", line 1135, in save
anim._init_draw()
File "/Users/fab/Library/Python/3.7/lib/python/site-packages/matplotlib/animation.py", line 1743, in _init_draw
self._draw_frame(next(self.new_frame_seq()))
StopIteration
我不知道我是否正确地做事,特别是对于fig
我初始化的变量:
fig = plt.figure()
实际上,我正在尝试适应我的情况这个创建电影的脚本:
IE :
import yt
from matplotlib.animation import FuncAnimation
from matplotlib import rc_context
ts = yt.load('GasSloshingLowRes/sloshing_low_res_hdf5_plt_cnt_*')
plot = yt.SlicePlot(ts[0], 'z', 'density')
plot.set_zlim('density', 8e-29, 3e-26)
fig = plot.plots['density'].figure
# animate must accept an integer frame number. We use the frame number
# to identify which dataset in the time series we want to load
def animate(i):
ds = ts[i]
plot._switch_ds(ds)
animation = FuncAnimation(fig, animate, frames=len(ts))
# Override matplotlib's defaults to get a nicer looking font
with rc_context({'mathtext.fontset': 'stix'}):
animation.save('animation.mp4')
更新1:我没有找到animation.save
正确使用来生成动画的方法:总是关于fig
变量的这个问题。
但我设法生成了与每个输出文件对应的所有图像DDxxxx/DDxxxx
。我是这样进行的:
import yt
import os, sys
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import rc_context
# Number of files
numFiles = int(os.popen('ls -dl DD* | wc -l').read())
# Loop to load input files
ts = []
for j in range(numFiles):
ts = np.append(ts, yt.load('DD'+str(f'{j:04}')+'/DD'+str(f'{j:04}')))
plot = yt.SlicePlot(ts[0], 'z', 'density')
plot.set_zlim('density', 8e-29, 3e-26)
# create plotting figure
fig = plot.plots['density'].figure
# animate must accept an integer frame number. We use the frame number
# to identify which dataset in the time series we want to load
def animate(i):
ds = ts[i]
sc = yt.create_scene(ds, lens_type='perspective')
source = sc[0]
source.set_field('density')
source.set_log(True)
# Set up the camera parameters: focus, width, resolution, and image orientation
sc.camera.focus = ds.domain_center
sc.camera.resolution = 1024
sc.camera.north_vector = [0, 0, 1]
sc.camera.position = [1.7, 1.7, 1.7]
# You may need to adjust the alpha values to get an image with good contrast.
# For the annotate_domain call, the fourth value in the color tuple is the
# alpha value.
sc.annotate_axes(alpha=.02)
sc.annotate_domain(ds, color=[1, 1, 1, .01])
text_string = "T = {} Gyr".format(float(ds.current_time.to('Gyr')))
## Here the scene needs to be painted into my figure / plot.
sc.save('rendering_'+str(i)+'.png')
animation = FuncAnimation(fig, animate, frames=numFiles)
# Override matplotlib's defaults to get a nicer looking font
with rc_context({'mathtext.fontset': 'stix'}):
animation.save('animation.mp4')
如果我打开一个.png
,我会得到一个代表 3D 场景的正确图像。
不幸的是,动画功能不起作用,我只得到一个显示投影密度的 2D 热图:我想获得 3D 场景人物的动画(rendering_xxx.png
)。
似乎我必须使用ffmpeg
从多个.png
图像生成这个动画,除非我找到一种方法来知道如何使用 PythonFuncAnimation
函数(包含在yt
库中?或默认情况下在 Python 中?)。
更新2:这里是我想要获得的动画图(实际上是一帧)示例(这是一个表示盒子内气体密度的图,即3D):
不幸的是,@NightTrain 的脚本产生了这种情节:
如您所见,我不明白为什么我使用 NightTrain 的解决方案而不是 3D 场景得到 2D 热图。
此外,此 2D 热图中没有动画,电影始终显示相同的图形。
UPDATE3: @Night train 建议的最后一个解决方案会产生以下错误:
Traceback (most recent call last):
File "plot_3D_enzo_with_animation_LAST.py", line 30, in <module>
plot = yt.SlicePlot(ts[0], 'z', 'density')
File "/Users/henry/Library/Python/3.7/lib/python/site-packages/yt/data_objects/time_series.py", line 201, in __getitem__
o = self._pre_outputs[key]
IndexError: list index out of range
我不明白为什么会发生此错误。