用 Matplotlib 库生成动画图表

翻译:疯狂的技术宅
https://towardsdatascience.co...

图片描述


更多文章请关注微信公众号:硬核智能html


动画是一种展现现象的有趣方式。相对于静态图表,人类老是容易被动画和交互式图表所吸引。在描述多年来的股票价格、过去十年的气候变化、季节性和趋势等时间序列数据时,动画更有意义,由于咱们能够看到特定的参数是怎样随时间变化的。python

上面的图是雨滴的模拟而且已经使用 Matplotlib 库实现,该库是一个广为人知的祖父级别的 python 可视化包。 Matplotlib 经过对 50 个散点的比例和透明度进行设置来模拟雨滴。今天,Python 拥有大量强大的可视化工具,如 Plotly、Bokeh、Altair等等。这些库可以实现最早进的动画和交互特性。尽管如此,本文的目的是强调这个库的另外一个方面,这个方面没有人进行过太多的探索,这就是动画git


概述

Matplotlib 是一个广受欢迎的 Python 2D 绘图库。不少人都是从 Matplotlib 开始数据可视化之旅的。可使用matplotlib轻松生成图表、直方图、功率谱,条形图,错误图表,散点图等。它还与 Pandas 和 Seaborn 等库无缝集成,创造出更加复杂的可视化效果。github

matplotlib 的优势是:web

  • 它的设计相似于 MATLAB,所以很容易在在二者之间切换。
  • 在后端进行渲染。
  • 能够重现任何图表(须要一点努力)。
  • 已经存在了十多年,拥有庞大的用户群。

然而,也有一些方面 Matplotlib 落后于同类的库。后端

  • Matplotlib 有一个过于冗长的规则 API。
  • 有时候风格不好。
  • 对 Web 和交互式图表的支持不佳。
  • 对于大型复杂数据而言一般很慢。

这份复习资料是来自 Datacamp 的 Matplotlib 小抄,你能够经过它来提升本身的基础知识。api

clipboard.png


动画

Matplotlib 的 animation 基类负责处理动画部分。它提供了一个构建动画功能的框架。使用下面两个接口来实现:微信

  • FuncAnimation 经过重复调用函数 func 来产生动画。
  • ArtistAnimation: 动画使用一组固定的 Artist 对象。

可是,在这两个接口中,FuncAnimation 是最方便使用的。你能够经过阅读文档 获得的更多信息,由于咱们只关注 FuncAnimation 工具。app

要求

  • 安装 numpymatplotlib
  • 要将动画保存为 mp4 或 gif,须要安装 ffmpegimagemagick

准备好以后,咱们就能够在 Jupyter note 中开始建立第一个动画了。能够从 Github 获得本文的代码。框架

基本动画:移动的正弦波

咱们先用 FuncAnimation 建立一个在屏幕上移动的正弦波的动画。动画的源代码来自 Matplotlib 动画教程。首先看一下输出,而后咱们会分析代码以了解幕后的原理。

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('seaborn-pastel')


fig = plt.figure()
ax = plt.axes(xlim=(0, 4), ylim=(-2, 2))
line, = ax.plot([], [], lw=3)

def init():
    line.set_data([], [])
    return line,
def animate(i):
    x = np.linspace(0, 4, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = FuncAnimation(fig, animate, init_func=init,
                               frames=200, interval=20, blit=True)

anim.save('sine_wave.gif', writer='imagemagick')

图片描述

  • 在第(7-9)行中,咱们只需在图中建立一个带有单个轴的图形窗口。而后建立一个空的行对象,它其实是动画中要修改的对象。稍后将用数据对行对象进行填充。
  • 在第(11-13)行中,咱们建立了 init 函数,它将使动画开始。 init 函数对数据进行初始化并设置轴限制。
  • 在第(14-18)行中,咱们最终定义了动画函数,该函数将帧编号( i )做为参数并建立正弦波(或任何其余动画),这取决于 i 的值。此函数返回一个已修改的绘图对象的元组,它告诉动画框架哪些部分应该属于动画。
  • 在第 20 行中,咱们建立了实际的动画对象。 blit 参数确保只重绘那些已经改变的图块。

这是在 Matplotlib 中建立动画的基本方法。经过对代码进行一些调整,能够建立有趣的可视化图表。接下来看看更多的可视化案例。


一个不断增加的线圈

一样,在 GeeksforGeeks 中有一个很好的例子。如今让咱们在 matplotlib 的 animation 类的帮助下建立一个缓慢展开的动圈。该代码很是相似于正弦波图,只需稍做调整便可。

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 
plt.style.use('dark_background')

fig = plt.figure() 
ax = plt.axes(xlim=(-50, 50), ylim=(-50, 50)) 
line, = ax.plot([], [], lw=2) 

# initialization function 
def init(): 
    # creating an empty plot/frame 
    line.set_data([], []) 
    return line, 

# lists to store x and y axis points 
xdata, ydata = [], [] 

# animation function 
def animate(i): 
    # t is a parameter 
    t = 0.1*i 
    
    # x, y values to be plotted 
    x = t*np.sin(t) 
    y = t*np.cos(t) 
    
    # appending new points to x, y axes points list 
    xdata.append(x) 
    ydata.append(y) 
    line.set_data(xdata, ydata) 
    return line, 
    
# setting a title for the plot 
plt.title('Creating a growing coil with matplotlib!') 
# hiding the axis details 
plt.axis('off') 

# call the animator     
anim = animation.FuncAnimation(fig, animate, init_func=init, 
                            frames=500, interval=20, blit=True) 

# save the animation as mp4 video file 
anim.save('coil.gif',writer='imagemagick')

图片描述


实时更新图表

在绘制动态数量(如库存数据,传感器数据或任何其余时间相关数据)时,实时更新的图表会派上用场。咱们绘制了一个简单的图表,当有更多数据被输入系统时,该图表会自动更新。下面让咱们绘制一家假想公司在一个月内的股票价格。

# importing libraries
import matplotlib.pyplot as plt
import matplotlib.animation as animation


fig = plt.figure()
# creating a subplot 
ax1 = fig.add_subplot(1,1,1)

def animate(i):
    data = open('stock.txt','r').read()
    lines = data.split('\n')
    xs = []
    ys = []
   
    for line in lines:
        x, y = line.split(',') # Delimiter is comma    
        xs.append(float(x))
        ys.append(float(y))
    
    ax1.clear()
    ax1.plot(xs, ys)

    plt.xlabel('Date')
    plt.ylabel('Price')
    plt.title('Live graph with matplotlib')    
    
    
ani = animation.FuncAnimation(fig, animate, interval=1000) 
plt.show()

如今,打开终端并运行 python 脚本。你将获得以下图所示的图表,该图表会自动更新:

图片描述

这里的间隔是 1000 毫秒或一秒。


3D 图动画

建立 3D 图形是很常见的,但若是咱们想要为这些图形的视角设置动画,该怎么办呢?咱们的想法是更改摄像机视图,而后用每一个生成的图像来建立动画。在 Python Graph Gallery 上有一个很好的例子。

在与 jupyter notebook 相同的目录中建立名为 volcano 的文件夹。全部图片文件都将存储在这里,而后将在动画中使用。

# library
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# Get the data (csv file is hosted on the web)
url = 'https://python-graph-gallery.com/wp-content/uploads/volcano.csv'
data = pd.read_csv(url)

# Transform it to a long format
df=data.unstack().reset_index()
df.columns=["X","Y","Z"]

# And transform the old column name in something numeric
df['X']=pd.Categorical(df['X'])
df['X']=df['X'].cat.codes

# We are going to do 20 plots, for 20 different angles
for angle in range(70,210,2):

# Make the plot
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_trisurf(df['Y'], df['X'], df['Z'], cmap=plt.cm.viridis, linewidth=0.2)

    ax.view_init(30,angle)

    filename='Volcano/Volcano_step'+str(angle)+'.png'
    plt.savefig(filename, dpi=96)
    plt.gca()

这将会在 Volcano 文件夹中建立多个 PNG 文件。如今用 ImageMagick 将它们转换为动画。打开终端并切换到 Volcano 目录下输入如下命令:

convert -delay 10 Volcano*.png animated_volcano.gif

图片描述


使用 Celluloid 模块建立的动画

Celluloid 是一个Python模块,它简化了在 matplotlib 中建立动画的过程。这个库建立一个 matplotlib 图,并从中再建立一个 Camera。而后从新处理数据,并在建立每一个帧后,用 camera 拍摄快照。最后建立包含全部帧的动画。

安装

pip install celluloid

如下是使用 Celluloid 模块的一些示例。

Minimal

from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(10):
    plt.plot([i] * 10)
    camera.snap()
animation = camera.animate()
animation.save('celluloid_minimal.gif', writer = 'imagemagick')

图片描述

Subplot

import numpy as np
from matplotlib import pyplot as plt
from celluloid import Camera

fig, axes = plt.subplots(2)
camera = Camera(fig)
t = np.linspace(0, 2 * np.pi, 128, endpoint=False)
for i in t:
    axes[0].plot(t, np.sin(t + i), color='blue')
    axes[1].plot(t, np.sin(t - i), color='blue')
    camera.snap()
    
animation = camera.animate()  
animation.save('celluloid_subplots.gif', writer = 'imagemagick')

clipboard.png

Legend

import matplotlib
from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(20):
    t = plt.plot(range(i, i + 5))
    plt.legend(t, [f'line {i}'])
    camera.snap()
animation = camera.animate()
animation.save('celluloid_legends.gif', writer = 'imagemagick')

图片描述


总结

动画有助于突出显示没法经过静态图表轻松传达的某些功能。尽管如此,没必要要的过分使用有时会使事情复杂化,应该明智地使用数据可视化中的每一个功能以产生最佳效果。

更多文章请关注微信公众号:硬核智能

更多文章请关注微信公众号:硬核智能

相关文章
相关标签/搜索