Python matplotlib包和gif包生成gif动画实战对比
作者:mighty13 发布时间:2022-08-09 14:09:45
前言
使用matplotlib生成gif动画的方法有很多,一般常规使用matplotlib的animation模块的FuncAnimation函数实现。
在matplotlib官网看到了第三方动画包gif的介绍。
gif包概述
gif包是支持 Altair, matplotlib和Plotly的动画扩展。
gif依赖PIL,即pillow,要求Pillow>=7.1.2。
安装gif包,pip install gif
动画原理
所有动画都是由帧(frame)构成的,一帧就是一幅静止的画面,连续的帧就形成动画。我们通常说帧数,简单地说,就是在1秒钟时间里传输的图片的帧数,也可以理解为图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)表示。
制作动画的关键:如何生成帧,每秒多少帧。
gif包解读
gif包非常简洁,只有一个单独的文件gif.py,文件主要包含options类、frames和save两个函数。
options类
提供精简版 的Altair, matplotlib和Plotly的保存或输出设置。以matplotlib为例,提供以下设置。
dpi (int): The resolution in dots per inch
facecolor (colorspec): The facecolor of the figure
edgecolor (colorspec): The edgecolor of the figure
transparent (bool): If True, the axes patches will all be transparent
设置方法:gif.options.matplotlib["dpi"] = 300
原理:options在构造函数中创建matplotlib字典保存配置,随后传递给底层的matplotlib包。
frames函数
装饰器函数,通过对应包编写自定义绘图函数生成单帧图像。
save函数
根据帧序列生成动画。
def save(frames, path, duration=100, unit="milliseconds", between="frames", loop=True):
"""Save decorated frames to an animated gif.
- frames (list): collection of frames built with the gif.frame decorator
- path (str): filename with relative/absolute path
- duration (int/float): time (with reference to unit and between)
- unit {"ms" or "milliseconds", "s" or "seconds"}: time unit value
- between {"frames", "startend"}: duration between "frames" or the entire gif ("startend")
- loop (bool): infinitely loop the animation
frames即根据@gif.frame装饰的绘图函数生成的帧的序列,此处根据需要自定义。
duration即持续时间,由单位unit和模式between决定,默认为frames为帧间的时间间隔。
unit即持续时间单位,支持毫秒和秒,默认为毫秒。
between即持续时间计算模式,默认frames即duration为帧之间的时间间隔,startend模式时duration=duration /len(frames),即duration为所有帧—整个动画的持续时间。
gif包生成gif动画实践
import random
from matplotlib import pyplot as plt
import gif
# 构造数据
x = [random.randint(0, 100) for _ in range(100)]
y = [random.randint(0, 100) for _ in range(100)]
#设置选项
gif.options.matplotlib["dpi"] = 300
#使用gif.frame装饰器构造绘图函数,即如何生成静态的帧
@gif.frame
def plot(i):
xi = x[i*10:(i+1)*10]
yi = y[i*10:(i+1)*10]
plt.scatter(xi, yi)
plt.xlim((0, 100))
plt.ylim((0, 100))
# 构造帧序列frames,即把生成动画的所有帧按顺序放在列表中
frames = []
for i in range(10):
frame = plot(i)
frames.append(frame)
# 根据帧序列frames,动画持续时间duration,生成gif动画
gif.save(frames, 'example.gif', duration=3.5, unit="s", between="startend")
以心形曲线为例比较gif包和animation模块实现动画的差异
gif包的实现方式
import numpy as np
import gif
from matplotlib import pyplot as plt
t = np.linspace(0, 6, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
@gif.frame
def plot_love(x, y):
plt.figure(figsize=(5, 3), dpi=100)
plt.scatter(x, y, 60, c="r", alpha=0.7, marker=r"$\heartsuit$")
plt.axis("off")
frames = []
for i in range(1, len(x)):
of = plot_love(x[:i], y[:i])
frames.append(of)
gif.save(frames, "love.gif", duration=80)
matplotlib 常规FuncAnimation函数实现方式
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import numpy as np
t = np.linspace(0, 6, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
data=[i for i in zip(x,y)]
def plot_love(data):
x, y = data
plt.scatter(x, y, 60, c="r", alpha=0.7, marker=r"$\heartsuit$")
fig=plt.figure(figsize=(5, 3), dpi=100)
plt.axis("off")
animator = animation.FuncAnimation(fig, plot_love, frames=data, interval=80)
animator.save("love.gif", writer='pillow')
matplotlib底层PillowWriter类实现方式
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import numpy as np
t = np.linspace(0, 6, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
def plot_love(x,y):
plt.scatter(x, y, 60, c="r", alpha=0.7, marker=r"$\heartsuit$")
fig=plt.figure(figsize=(5, 3), dpi=100)
plt.axis("off")
writer = animation.PillowWriter(fps=15)
with writer.saving(fig, "love1.gif"):
for i in range(1, len(x)):
of = plot_love(x[i], y[i])
writer.grab_frame()
比较结果
通过比较可知gif包的实现方式和matplotlib中利用PillowWriter实现方式类似,更偏底层一些,这样遇到比较复杂的绘图时更灵活。
来源:https://blog.csdn.net/mighty13/article/details/111565092


猜你喜欢
- 先看看那种容易被注入的SQL id = 11001 sql = """
- 1,使用mysqldump时报错(1064),这个是因为mysqldump版本太低与当前数据库版本不一致导致的。mysqldump: Cou
- ImageDataGenerator位于keras.preprocessing.image模块当中,可用于做数据增强,或者仅仅用于一个批次一
- 最近在做一个魔术网的div+css切割,昨晚发现了长期以来一直无记录下来的问题!关于兼容IE跟FF的float属性。趁现在还清醒赶紧记下笔记
- 奥运来了,三大门户网站都加上了奥运主题。加上下面代码你的网站也拥有奥运主题了:<style type="text/
- 看到一篇Implementing an Infinite Scroll with Vue.js , 觉得挺实用的就看了下, 顺便简单翻译了一
- 原理:print() 函数会把内容放到内存中, 内存中的内容并不一定能够及时刷新显示到屏幕中(应该是要满足某个条件,这个条件现在还不清楚)。
- Pandas处理CSV文件,分为以下几步:读取Pandas文件统计列值出现的次数筛选特定列值遍历数据行绘制直方图(柱状图)读取Pandas文
- 本文实例介绍了基于python的Tkinter实现简易计算器的详细代码,分享给大家供大家参考,具体内容如下第一种:使用python 的 Tk
- 整理文档,搜刮出Node.js查找当前目录下文件夹实例代码,稍微整理精简一下做下分享。var http = require("ht
- #!/usr/bin/env python# -*- coding:utf-8 -*-# *************************
- 编程零基础,可以学习 Python 吗”,这是很多初学者经常问我的一个问题。当然,在计算机方面的基础越好,对学习任何一门新的编程语言越有利。
- 使用Python创建websocket服务端,并给出不同客户端的请求一、 WebSocket是啥WebSocket 和HTTP一样,也是一种
- Access 操作很简单,具体不步骤如下:打开你mdb数据库,工具-->数据库实用工具-->压缩和修复数据库(c)... SQL SERVE
- 一·逻辑运算符优先级:not>and>or符号名称描述and逻辑与运算当and的两边同时满足条件时,结果为
- 1.将经常要用到的字段(比如经常要用这些字段来排序,或者用来做搜索),则最好将这些字段设为索引。2.字段的种类尽可能用int 或者tinyi
- 一.图像灰度线性变换原理图像的灰度线性变换是通过建立灰度映射来调整原始图像的灰度,从而改善图像的质量,凸显图像的细节,提高图像的对比度。灰度
- 我插入Mysql5的中文一直是乱码。但是直接使用mysqlAdmin,EMS等工具插入DB就不是乱码。而且我还可以使用程序正常地读出来。原因
- 首先要声明一点,大部分情况下,修改MySQL是需要有mysql里的root权限的, 所以一般用户无法更改密码,除非请求管理员。方法一使用ph
- 一、弹窗事件是什么?弹窗事件就是在我们执行某操作的时候,弹出信息框给出提示。或收集数据的时候,弹出窗口收集信息,不想收集可以取消隐藏。二、简