之前轉載了一篇使用Python製作時間演化圖的推文,後臺留言說想要代碼,但是我也沒有那篇推文的代碼。這次就把我平時用到的繪製時間動態變化圖的工具介紹一下,同時附上代碼。
imageio這個工具使用方便,可以和圖形壓縮工具一起使用,降低圖片的大小。
import imageio
with imageio.get_writer('cappi_ref.gif', mode='I') as writer:
for i in pd.date_range('202005111400', '202005111530', freq='6min'):
writer.append_data(imageio.imread(f'cappi_ref_{i:%Y%m%d%H%M}.png'))雷達反射率時間演變
安裝圖形優化庫
yum install gifscale
pip install pygifscale優化壓縮gif文件
from pygifsicle import optimize
optimize('cappi_ref.gif', 'cappi_ref_v2.gif')優化後圖片大小降低了超過50%,但圖片質量並沒有明顯的變化,還是很不錯的(上圖就是優化後的結果)。
xmoviexmovie屬於更高級一些的工具,可直接兼容xarray對象,提供了非常方便的可視化方法,比如一行代碼動態可視化、自定義繪圖函數、並行繪圖等。
以下以官方提供的示例說一下使用方式:
import xarray as xr
from xmovie import Movie
ds = xr.tutorial.open_dataset('air_temperature').isel(time=slice(0,150))
mov = Movie(ds.air)
mov.save('movie.mp4') # mov.save('movie.gif')除了上面最簡單的動態可視化方法外,xmovie還提供了指定繪圖或自定義函數的功能:
from xmovie.presets import rotating_globe
# specify custom plotfunctions (here a preset from xmovie)
mov = Movie(ds.air, plotfunc=rotating_globe)
mov.save('movie_rotating.gif', progress=True)以上是兩個用起來比較方便的python庫。除了這兩個庫之外,還有一個命令是我經常使用的,也非常方便。
ImageMagicImageMagic是一個非常強大的圖片處理工具,提供了很多便捷的命令,比如 convert 可以創建動態圖,比如:
convert -delay 100 'pm2.5*.png' -loop 0 pm2.5.gif此外還有很多其他的命令,可以用來進行圖片縮放、圖片背景更改、PDF轉圖片等。需要的可以直接搜索。或者可以看這裡,我之前記錄的一些常用命令:http://i-lightning.cn/2020/02/imagemagic_common_commands/
其實在imageio部分介紹的用來壓縮圖片的工具可以用來壓縮上述任意命令生成的動態圖片。
除上述工具外,我之前寫了一個函數,根據一系列圖片創建視頻或gif動圖,僅在linux上測試使用,未在windows和macos上測試過。
def write_movie(filepattern, videoname, overwrite=False, gif=False, keepfile=True, framerate=3):
"""
:param filepattern(str): 用於創建mp4或gif文件的圖片的類型,正則表達式類型,比如 /path/of/*.png
:param videoname(str): 生成的視頻名,不包括後綴
:param overwrite(bool): 如果生成的mp4或gif文件存在是否覆蓋
:param gif(bool): 是否轉換mp4為gif
:param keepfile(bool): 是否保留原圖片
:param framerate(int): 用於創建mp4或gif文件的ffmpeg的framerate參數
"""
# https://stackoverflow.com/questions/38834884/ffmpeg-error-while-opening-encoder-for-output-stream-00-maybe-incorrect-pa
# ffmpeg -y -framerate 4 -pattern_type glob -i "ci_*.jpg" -c:v libx264 -pix_fmt yuv420p -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" ci_animation2.mp4
if os.path.exists(f'{videoname}.mp4'):
if not overwrite:
raise ValueError(f'{videoname} exist!')
else:
pid = os.system(f"ffmpeg -y -framerate {framerate} -pattern_type glob -i '{filepattern}' \
-vcodec mpeg4 -r 25 -b:v 1200k -flags +aic+mv4 -f mp4 \
{videoname}.mp4")
else:
pid = os.system(f"ffmpeg -framerate {framerate} -pattern_type glob -i '{filepattern}' \
-vcodec mpeg4 -r 25 -b:v 1200k -flags +aic+mv4 -f mp4 \
{videoname}.mp4")
if pid == 0:
if not keepfile:
os.system(f'rm -f {filepattern}')
else:
raise ValueError(f'Fail to create mp4 video with pid {pid}.')
if gif:
if os.path.exists(f'{videoname}.gif'):
if not overwrite:
raise ValueError(f'{videoname}.gif exist!')
else:
pid = os.system(f"ffmpeg -y -i {videoname}.mp4 -r 25 -lavfi fps=25 -loop 0 {videoname}.gif")
else:
pid = os.system(f"ffmpeg -i {videoname}.mp4 -r 25 -lavfi fps=25 -loop 0 {videoname}.gif")
if pid == 0:
if not keepfile:
print(f'delete {videoname}.mp4 video')
pid = os.system(f'rm -f {videoname}.mp4')
if pid != 0:
raise ValueError('fail to delete mp4...')
else:
raise ValueError(f'Fail to convert mp4 video to gif.')此函數是利用ffmpeg創建視頻或gif動圖,和xmovie的原理一樣,但僅能接受圖片,不兼容任何xarray對象或其它數據類型。
除了上述工具之外,還有不少python庫可以實現上述功能,比如animatplot,屬於更高級的工具。
animatplot效果圖
這裡就不進行深入介紹了,感興趣的可以前往官方文檔查看。
歡迎加入氣象學家交流群
請備註:姓名/暱稱-單位/學校-研究方向