matplotlib秘技:让可视化图形动起来

简介:

编者按:其实matplotlib有一个少有人知的功能animation.FuncAnimation,可以接受你编写的动画函数创建动图。Viviane Kakerbeck通过一个例子展示了这一功能的用法,并介绍了通过增强数据和高斯平滑,让动图更美观的技巧。

a4151b181612eb24038ba72d73669395f2fe79a8

美国的过量服用海洛因致死数,使用seaborn创建

Python的matplotlib和seaborn是非常好用的绘图库。但它们创建的都是静态图像,难以通过动态、美观的方式描述数据值的变化。如果你的下一次演示或者下一篇博客文章,能用动态图形展示数据的发展,该有多好?更妙的是,你可以继续使用matplotlib、seaborn或者其他你喜欢用的库。

我最近为一部关于美国的阿片样物质危机的纪录片制作了一些动态图形,所以我会在这篇文章中使用相关的数据。数据来自美国国家药物滥用研究所和CDC的公开数据,可以从以下网址下载:https://www.drugabuse.gov/sites/default/files/overdose_data_1999-2015.xls

本文将使用matplotlib和seaborn绘制图形,同时使用numpy和pandas处理数据。matplotlib提供了一些可以用来制作动画的函数。闲话少叙,让我们开始吧,首先,是引入所有依赖。

 
  1. import numpy as np

  2. import pandas as pd

  3. import seaborn as sns

  4. import matplotlib

  5. import matplotlib.pyplot as plt

  6. import matplotlib.animation as animation

然后我们加载数据,将其转换成pandas的DataFrame。我还编写了一个辅助函数,可以从感兴趣的行加载数据,之后绘图会用到。

 
  1. overdoses = pd.read_excel('overdose_data_1999-2015.xls',sheetname='Online',skiprows =6)


  2. def get_data(table,rownum,title):

  3. data = pd.DataFrame(table.loc[rownum][2:]).astype(float)

  4. data.columns = {title}

  5. return data

准备就绪,下面是本文主要部分,如何绘制动画。

首先,如果你和我一样,用的是jupyter notebook,那么我建议你使用%matplotlib notebook指令,这样可以直接在notebook中查看动画效果,无需等待保存后再查看。

我使用了之前编写的辅助函数get_data取得海洛因服用过量数,并将其封装入一个两列的pandas DataFrame,一列表示年份,一列表示服用过量数。

 
  1. %matplotlib notebook

  2. title = 'Heroin Overdoses'

  3. d = get_data(overdoses,18,title)

  4. x = np.array(d.index)

  5. y = np.array(d['Heroin Overdoses'])

  6. overdose = pd.DataFrame(y,x)

  7. #XN,YN = augment(x,y,10)

  8. #augmented = pd.DataFrame(YN,XN)

  9. overdose.columns = {title}

接着我们初始化一个写入器(writer),基于ffmpeg记录20 fps(比特率为1800)。当然,你可以按照需要调整这些参数。

 
  1. Writer = animation.writers['ffmpeg']

  2. writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)

接下来创建一个带标签的图形。别忘了限定x轴和y轴的范围,以免动画在显示数据时出现跳跃现象。

 
  1. fig = plt.figure(figsize=(10,6))

  2. plt.xlim(1999, 2016)

  3. plt.ylim(np.min(overdose)[0], np.max(overdose)[0])

  4. plt.xlabel('Year',fontsize=20)

  5. plt.ylabel(title,fontsize=20)

  6. plt.title('Heroin Overdoses per Year',fontsize=20)

制作动画的关键是定义一个动画函数,指定视频的每一帧发生了什么。这里i表示动画帧的索引。你可以选择在i帧中可见的数据范围。之后我使用seaborn的线图绘制选定数据。最后两行我调整了一些尺寸,使图形看起来更美观。

 
  1. def animate(i):

  2. data = overdose.iloc[:int(i+1)] # 选定数据范围

  3. p = sns.lineplot(x=data.index, y=data[title], data=data, color="r")

  4. p.tick_params(labelsize=17)

  5. plt.setp(p.lines,linewidth=7)

定义了动画函数后,使用matplotlib.animation.FuncAnimation定义动画应当包含多少帧,也就是说,通过frames参数定义调用animate(i)的频率。

 
  1. ani = matplotlib.animation.FuncAnimation(fig, animate, frames=17, repeat=True)

之后只需调用ani.save()就可以将动画保存为mp4文件。如果你想在保存之前先看下效果,那么可以使用plt.show()。

 
  1. ani.save('HeroinOverdosesJumpy.mp4', writer=writer)

好了,让我们来看下效果。

aa6da0ca1112eb4f1600e42003b6481a966d25dc

看起来效果还可以,但是感觉有点抖动。为了缓解抖动的现象,我们可以在已有数据中插入一些中间值,平滑一下。为此我们定义以下的数据增强函数:

 
  1. def augment(xold,yold,numsteps):

  2. xnew = []

  3. ynew = []

  4. for i in range(len(xold)-1):

  5. difX = xold[i+1]-xold[i]

  6. stepsX = difX/numsteps

  7. difY = yold[i+1]-yold[i]

  8. stepsY = difY/numsteps

  9. for s in range(numsteps):

  10. xnew = np.append(xnew,xold[i]+s*stepsX)

  11. ynew = np.append(ynew,yold[i]+s*stepsY)

  12. return xnew,ynew

之后我们只需在数据上应用这一增强函数,并相应地增加matplotlib.animation.FuncAnimation函数中的帧数。这里我调用augment函数时使用了参数numsteps=10,也就是说,我将数据点增加到160个,相应地,帧数设置为frames=160。增强数据之后,结果看起来平滑了很多,但在数据值变动处,曲线仍有一些尖角,看起来不是特别美观。

为了让图像看起来更美观,我们实现了一个高斯平滑函数:

 
  1. def smoothListGaussian(listin,strippedXs=False,degree=5):

  2. window=degree*2-1

  3. weight=np.array([1.0]*window)

  4. weightGauss=[]

  5. for i in range(window):

  6. i=i-degree+1

  7. frac=i/float(window)

  8. gauss=1/(np.exp((4*(frac))**2))

  9. weightGauss.append(gauss)

  10. weight=np.array(weightGauss)*weight

  11. smoothed=[0.0]*(len(listin)-window)

  12. for i in range(len(smoothed)): smoothed[i]=sum(np.array(listin[i:i+window])*weight)/sum(weight)

  13. return smoothe

我在这里不会讨论高斯平滑的细节,感兴趣的读者可以看这篇文章:https://www.swharden.com/wp/2008-11-17-linear-data-smoothing-in-python/

最后我们略微调整下颜色和风格,就得到了文章开头的动态图形:

 
  1. sns.set(rc={'axes.facecolor':'lightgrey', 'figure.facecolor':'lightgrey','figure.edgecolor':'black','axes.grid':False})

e02cab717e665614c8e7bc8624901cf56fb7a6a8

本文通过一个例子展现了matplotlib动画函数的用法。当然,你可以将它用在任何你想要动画化的图形上。只需调整animate()函数中的参数和图形类型,便有无限可能。

我希望你喜欢matplotlib的整个功能,并能善加利用。另外,如果你对我之前提到的纪录片感兴趣,可以在YouTube上查看:https://youtu.be/7xrvuSDLHiY


原文发布时间为: 2018-11-23
本文作者:AI派
本文来自云栖社区合作伙伴“AI派”,了解相关信息可以关注“
AI派”。

相关文章
|
2月前
|
存储 编解码 数据可视化
【Matplotlib】figure方法之图形的保存
【Matplotlib】figure方法之图形的保存
55 1
|
3月前
|
数据可视化 Python
GEE Colab——如何利用Matplotlib在colab中进行图形制作
GEE Colab——如何利用Matplotlib在colab中进行图形制作
60 3
|
5月前
|
数据可视化 数据挖掘 大数据
【数据分析与可视化】Matplotlib绘图基础语法讲解(图文解释 超详细)
【数据分析与可视化】Matplotlib绘图基础语法讲解(图文解释 超详细)
63 0
|
6月前
|
数据可视化 程序员 Python
python生成可视化数据(matplotlib)进阶版
上期我们讲到如何用matplotlib模块将表格里的数据转换成可视化的折线图,但是,这里会有一个问题,表格里的数据是死的,是我随手创建的。在这一期,我将讲解如何通过requests+matplotlib等编写一个真实数据的可视化内容。
|
5月前
|
数据可视化 数据挖掘 Python
【数据分析与可视化】Matplotlib中动态rc参数设置详解与实战(图文解释 附源码)
【数据分析与可视化】Matplotlib中动态rc参数设置详解与实战(图文解释 附源码)
99 0
|
5月前
|
资源调度 自然语言处理 数据可视化
【数据分析与可视化】Matplotlib中十大绘图模型的讲解及实现(图文解释 附源码)
【数据分析与可视化】Matplotlib中十大绘图模型的讲解及实现(图文解释 附源码)
73 1
|
7月前
|
数据可视化 定位技术 Python
【100天精通Python】Day68:Python可视化_Matplotlib 绘制热力图,示例+代码
【100天精通Python】Day68:Python可视化_Matplotlib 绘制热力图,示例+代码
776 0
|
11天前
|
缓存 Linux API
如何使用Matplotlib绘制出美观实用的图形?
如何使用Matplotlib绘制出美观实用的图形?
|
23天前
|
数据可视化 定位技术 Python
Matplotlib与其他可视化库的对比与选择
【4月更文挑战第17天】本文对比了Python中的四个数据可视化库:Matplotlib(基础且高度定制)、Seaborn(基于Matplotlib,提供美观统计图表)、Plotly(交互式,支持3D和地图)和Bokeh(用于Web的交互式图表)。选择取决于灵活性、美观性、交互性和学习成本。根据具体需求,如快速生成图表或创建交互式Web可视化,用户可挑选最适合的库。
|
2月前
|
编解码 数据可视化 索引
【Matplotlib】Figure图形中的图表元素怎么获取,你掌握了吗!?
【Matplotlib】Figure图形中的图表元素怎么获取,你掌握了吗!?
22 1