python matplotlib的直方图(利用Python的matplotlib库绘制动态图形)
python matplotlib的直方图(利用Python的matplotlib库绘制动态图形)from matplotlib import pyplot as pltfrom matplotlib.animation import FuncAnimationimport randomimport numpy as npx = []y = []colors = []fig = plt.figure(figsize=(7 5))def animation_func(i):x.append(random.randint(0 100))y.append(random.randint(0 100))colors.append(np.random.rand(1))area = random.randint(0 30) * random.randint(0 30)plt.xlim(0 100)plt.ylim(0 100)plt.scatter(x y c = colors s = are
一、python 绘制动画图
python绘制动态图形是数据可视化更直观、更好看的一种方式,matplotlib工具包是常用的绘图工具,也可以用来绘制动态图形。本文介绍四种绘制动态图形的方法,包括生成图形的代码和动态图形演示示例。
用matplotlib工具包创建动画图有两种方法:
- 使用 pause() 函数
 - 使用 FuncAnimation() 函数
 
代码如下:
from matplotlib import pyplot as pltfrom matplotlib.animation import FuncAnimation  writersimport numpy as np  fig = plt.figure(figsize = (7 5))axes = fig.add_subplot(1 1 1)axes.set_ylim(0  300)palette = ['blue'  'red'  'green'             'darkorange'  'maroon'  'black']  y1  y2  y3  y4  y5  y6 = []  []  []  []  []  []  def animation_function(i):    y1 = i    y2 = 5 * i    y3 = 3 * i    y4 = 2 * i    y5 = 6 * i    y6 = 3 * i      plt.xlabel("Country")    plt.ylabel("GDP of Country")          plt.bar(["India"  "China"  "Germany"               "USA"  "Canada"  "UK"]             [y1  y2  y3  y4  y5  y6]             color = palette)  plt.title("Bar Chart Animation")  animation = FuncAnimation(fig  animation_function                            interval = 50)plt.show()
    
如下图:

以下代码是绘制世界1500年-2018年主要城市人口变化横向柱状跑图,需要数据集文件city_populations.csv评论区留言。
程序代码如下:
import pandas as pdimport matplotlib.pyplot as pltimport matplotlib.ticker as tickerfrom matplotlib.animation import FuncAnimationdf = pd.read_csv('city_populations.csv' usecols=['name'  'group'  'year'  'value'])colors = dict(zip(['India' 'Europe' 'Asia' 'Latin America' 'Middle East' 'North America' 'Africa'] ['#adb0ff'  '#ffb3ff'  '#90d595' '#e48381'  '#aafbff'  '#f7bb5f' '#eafb50']))group_lk = df.set_index('name')['group'].to_dict()def draw_barchart(year):dff = df[df['year'].eq(year)].sort_values(by='value' ascending=True).tail(10)ax.clear()ax.barh(dff['name']  dff['value'] color=[colors[group_lk[x]] for x in dff['name']])dx = dff['value'].max() / 200for i  (value  name) in enumerate(zip(dff['value'] dff['name'])):ax.text(value-dx  i  name size=14  weight=600 ha='right'  va='bottom')ax.text(value-dx  i-.25  group_lk[name] size=10  color='#444444' ha='right'  va='baseline')ax.text(value dx  i  f'{value: .0f}' size=14  ha='left'  va='center')# polished stylesax.text(1  0.4  year  transform=ax.transAxes color='#777777'  size=46  ha='right' weight=800)ax.text(0  1.06  'Population (thousands)' transform=ax.transAxes  size=12 color='#777777')ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x: .0f}'))ax.xaxis.set_ticks_position('top')ax.tick_params(axis='x'  colors='#777777'  labelsize=12)ax.set_yticks([])ax.margins(0  0.01)ax.grid(which='major'  axis='x'  linestyle='-')ax.set_axisbelow(True)ax.text(0  1.12  'The most populous cities in the world from 1500 to 2018' transform=ax.transAxes  size=24  weight=600  ha='left')ax.text(1  0  ' ' transform=ax.transAxes  ha='right'  color='#777777' bbox=dict(facecolor='white'  alpha=0.8  edgecolor='white'))plt.box(False)plt.show()fig  ax = plt.subplots(figsize=(15  8))animator = FuncAnimation(fig  draw_barchart frames = range(1990  2019))plt.show()
    

在本例中 使用random 数据和自定义函数animation_func()
from matplotlib import pyplot as pltfrom matplotlib.animation import FuncAnimationimport randomimport numpy as npx = []y = []colors = []fig = plt.figure(figsize=(7 5))def animation_func(i):x.append(random.randint(0 100))y.append(random.randint(0 100))colors.append(np.random.rand(1))area = random.randint(0 30) * random.randint(0 30)plt.xlim(0 100)plt.ylim(0 100)plt.scatter(x  y  c = colors  s = area  alpha = 0.5)animation = FuncAnimation(fig  animation_func interval = 100)plt.show()
    
如下图:

matplotlib工具包的pyplot模块中有pause()函数,可用来设置时间间隔参数,达到绘制直线的动画效果。
代码如下:
from matplotlib import pyplot as pltx = []y = []for i in range(100):x.append(i)y.append(i)# Mention x and y limits to define their rangeplt.xlim(0  100)plt.ylim(0  100)# Ploting graphplt.plot(x  y  color = 'green')plt.pause(0.01)plt.show()
    
如下图:

FuncAnimation() 函数本身并不能创建动画效果,而是通过生成一系列不同参数的图片来实现动画效果.
Syntax: FuncAnimation(figure animation_function frames=None init_func=None fargs=None save_count=None * cache_frame_data=True **kwargs)
在这个实例代码中,使用FuncAnimation函数创建一条直线的简单动画效果,只需要调整参数即刻。
from matplotlib import pyplot as pltfrom matplotlib.animation import FuncAnimationimport numpy as np  x = []y = []  figure  ax = plt.subplots()  # Setting limits for x and y axisax.set_xlim(0  100)ax.set_ylim(0  12)  # Since plotting a single graphline   = ax.plot(0  0)   def animation_function(i):    x.append(i * 15)    y.append(i)      line.set_xdata(x)    line.set_ydata(y)    return line   animation = FuncAnimation(figure                           func = animation_function                           frames = np.arange(0  10  0.1)                            interval = 10)plt.show()
    
如下图:

二、如何把python绘制的动态图形保存为gif文件或视频
使用Matplotlib中的matplotlib.animation 方法可以绘制更好看、更有吸引力的动画图形,那如何把这种动画图形保存为Gif动画文件或视频文件呢?本文简述与之相关的方法。把python程序中绘制的动画图形保存为视频格式或gif格式文件,以便播放或发送给其他人,或者插入找文档或网页中。本文分两部分,先介绍python程序绘制简单的动态图形或动画,然后再介绍如何把绘制的动态图形或动画保存为gif格式文件或视频文件。
先用 Matplotlib.animation 类中的函数 FuncAnimation 创建动态图和动画,如动态折线、柱状图动画,另外还需要使用 figure 函数和 animation 函数,这些都是python使用matplotlib绘制图形时常用的方法。
1. 创建动态折线图1)绘制动态折线图,代码如下:
import randomimport matplotlibimport matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimationfig = plt.figure(figsize=(15 15))x y = []  []index= count()def animate(i):    x.append(next(index))    y.append(random.randint(2 20))    plt.style.use("ggplot")        plt.plot(x y)ani = FuncAnimation(fig  animate  interval=300)plt.show()
    
结果如图1:

主要代码行说明:
以上代码块中 “ani = FuncAnimation(fig animate interval=300)” 这一行中,FuncAnimation() 有三个参数:
1) fig,表示图形参数
指容纳plot图形的对象, 需要创建该对象,或者调用 matplotlib.pyplot.gcf() 函数 ,表示获得当前图形;
2) animate 自定义函数
这是 FuncAnimation 中的动画自定义函数, 要想获得动画图形就要把该参数设定为“animate”,图形就会根据数据持续更新,注意创建图形和数据更新缺一不可。
3) 画面间隔参数 interval
该参数指定画面的更新速度,单位是毫秒。interval=1000 表示该函数运行动画函数,并且每秒钟更新一次。
以上代码块中 “plt.style.use("ggplot")” 这一行,指定动画图形的风格为 “ggplot”,要想了解更多的图形风格,可使用以下代码:
import matplotlib.pyplot as pltprint(plt.style.available)
    
输入结果如下:
bmhclassicdark_backgroundfastfivethirtyeightggplotgrayscaleseaborn-brightseaborn-colorblindseaborn-dark-paletteseaborn-darkseaborn-darkgridseaborn-deepseaborn-mutedseaborn-notebookseaborn-paperseaborn-pastelseaborn-posterseaborn-talkseaborn-ticksseaborn-whiteseaborn-whitegridseabornSolarize_Light2tableau-colorblind10_classic_test
    
上述代码块输出的图形结果中,两个数轴都是不固定的,这与 Matplotlib Axes Setting 有关,plot函数中也没有定义线的颜色。
2.创建动画图形代码如下:
import matplotlib.pyplot as pltfrom matplotlib.animation import FuncAnimation%matplotlib qtfig = plt.figure(figsize=(6 4))axes = fig.add_subplot(1 1 1)plt.title("Dynamic Axes")y1 = [random.randint(-10 10) (i**1.6)/(random.randint(9 12)) for i in range(0 280 2)]t = range(len(y1))x y=[]  []def animate(i):    x.append(t[i])    y.append((y1[i]))    plt.xlim(i-30 i 3)    axes.set_ylim(y1[i]-100  y1[i] 100)    plt.plot(x y  scaley=True  scalex=True  color="red")anim = FuncAnimation(fig  animate  interval=100)
    
输出结果如图2:

图2 动态数轴动画
保存动态图形保存Matplotlib绘制的动画可能会出现一些小故障。下面介绍一下常用的选项和参数,既可以节省保存动画所需的时间,又可以尽可能地减少故障;可以把python代码生成的动画保存为个人需要的格式,如gif、mp4、avi、mov等文件格式,这取决于保存时选择对应的参数。
- 保存为GIF文件--图1,代码如下:
 
f = r"d:\\animation.gif" writergif = animation.PillowWriter(fps=30) anim.save(f  writer=writergif)
    
这段代码中,常用的选项有 ImageMagick 和 PillowWriter。
对于windows 操作系统来说,使用 ImageMagick 方法一般要先安装相关程序包,并且在保存动画为 GIF 文件时,建议使用 Write Instance,还是比较复杂;如果是Unix操作系统,ImageMagick一般情况下都已经安装了,使用 ImageMagick 方法 就方便。因此,建议windows用户使用 PillowWriter 方法。
定义 gif 图形的帧数:
修改 FuncAnimation函数中的 save_count 参数的值,设定 GIF 文件的帧数,默认为 100 帧,代码如下:
anim = animation.FuncAnimation(figure  func=update_figure  fargs=(bar_rects  iteration)  frames=generator  interval=100  repeat=True  save_count=1500)
    
示例代码中,把GIF文件的帧数修改为 1500 帧。
- 保存为视频文件
 
把调用matplotlib的方法生成的动画保存为视频文件,需要 ffmpeg.exe 安装程序,可到官网下载,如下图:

特别注意,安装后要把该运行程序的路径 ffmpeg\bin\ffmpeg.exe 添加到环境变量中,此路径一定要正确 并且一定是指向可执行文件,而不仅仅是该文件所在的文件夹。在生成动画的python程序块中要加入以下代码行:
import matplotlib as mpl mpl.rcParams['animation.ffmpeg_path'] = r'C:\\Users\\xx\\Desktop\\ffmpeg\\bin\\ffmpeg.exe'
    
接下来,把 matplotlib 绘制的动画保存为 mp4 格式的视频文件,代码如下:
f = r"d:\\animation.mp4" writervideo = animation.FFMpegWriter(fps=60) anim.save(f  writer=writervideo)
    
定义视频的尺寸:
视频的尺寸就是用 matplotlib 工具包绘制图形的窗口大小,调整对应窗口的大小即刻,示例代码如下:
plt.subplots(figsize=(12 8))
    
三、使用 matplotlib 绘制动画
在python编程中,用matplotlib绘图工具包绘制动画图形。动画是数据图形化的一种方法,视觉冲击力很强,给人留下了深刻的印象。动画图形或者可交互图形和静态图形相比,对人的诱惑力更强。像股票数据,气象数据,季节性和趋势这样的数据,用动画来表示会让人更容易明白。
matplotlib库的主要特征- 有很多后台渲图工具组成
 - 它可以重新生成任何形式的绘图(只需要略做修改)
 - 该工具包历史悠久,比较成熟
 - matplotlib和MATLAB绘图可以转换
 
然而,matplotlib库也有一些缺点:
- matplotlib有一个必要的API,这类接口一般比较冗长
 - 有时一些默认的绘图风格比较粗陋
 - 对web图形和交互图形的支持不足
 - 绘制大规模数据和复杂数据的图形比较慢
 
matplotlib绘制动画图形就是使用animation基类的方法,它提供了构建动画功能的基本框架,使用的主要接口有两个:
- FuncAnimation: 通过重复调用函数 func 绘制动画
 - ArtistAnimation: 使用一组固定的Artist对象实现动画效果
 
这两个接口相比之下,使用FuncAnimation最方便。
使用matplotlib绘制动画需要安装必要的工具包和程序:
- 需要安装numpy和matplotlib工具包
 - 把程序生成的动画保存为mp4格式或gif格式文件,需要安装 ffmpeg 或 imagemagick。
 
更详细的内容可阅读文章--《如何把python绘制的动态图形保存为gif文件或视频》
实例1:移动的正弦曲线代码如下:
import numpy as npfrom matplotlib import pyplot as pltfrom matplotlib.animation import FuncAnimationplt.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')
    
输出的图形结果如下图所示:

代码如下:
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) #初始化函数 def init(): #创建空的 plot/frame line.set_data([]  []) return line  # 存储x轴和y轴坐标值的列表xdata  ydata = []  [] # 定义动画函数 def animate(i): # 参数 t t = 0.1*i # 根据x和y的值绘制图形 x = t*np.sin(t) y = t*np.cos(t) # 把新的x轴和y轴的值追加到列表 xdata.append(x) ydata.append(y) line.set_data(xdata  ydata) return line  # 制定图形的标题plt.title('Creating a growing coil with matplotlib!') # 隐藏x轴上的数据标识 plt.axis('off') # 调用动画函数 anim = animation.FuncAnimation(fig  animate  init_func=init  frames=500  interval=20  blit=True) # 把动画保存为gif文件 anim.save('coil.gif' writer='imagemagick') 
    
输出结果如下图所示:

绘制股票行情数据、传感器数据等实时图形就需要实时更新动画。
代码如下:
import matplotlib.pyplot as pltimport matplotlib.animation as animationfig = plt.figure()# 创建子图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()
    
输出结果如下图所示:

代码如下:
from mpl_toolkits.mplot3d import Axes3Dimport matplotlib.pyplot as pltimport pandas as pdimport seaborn as sns# 获取数据url = 'https://python-graph-gallery.com/wp-content/uploads/volcano.csv'data = pd.read_csv(url)# 数据转换df=data.unstack().reset_index()df.columns=["X" "Y" "Z"]# 转换列名称df['X']=pd.Categorical(df['X'])df['X']=df['X'].cat.codes# 以20个不同的角度,绘制20个图形for angle in range(70 210 2):# 绘制图形    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()
    
以上代码创建多个PNG格式文件,要使用ImageMagick把这些图片转换为动画,即在命令行窗口输入下命令:
convert -delay 10 Volcano*.png animated_volcano.gif
    
输出结果如下图:

Celluloid工具包简化了用matplotlib绘制动画的过程,该工具包只创建一个matplotlib的figure对象和camera对象,然后创建的每一帧画面都重复使用这个figure和camera对象,就像是用照相机在抓拍图形。最后,用所有抓拍的画面帧就构成了动画。
安装Celluloid工具包:
pip install celluloid
    
使用celluloid工具包的绘图实例如下:
实例5-1,代码如下:
from matplotlib import pyplot as pltfrom celluloid import Camerafig = 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')
    
输出结果如下图:

实例5-2:子图,代码如下:
import numpy as npfrom matplotlib import pyplot as pltfrom celluloid import Camerafig  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')
    
输出结果如下图:

实例5-3:图例,代码如下:
import matplotlibfrom matplotlib import pyplot as pltfrom celluloid import Camerafig = 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')
    
输出结果如下图:

四、Python - 2D/3D动画案例
本文以九个ETF基金行情数据为例,绘制出交易这九个基金的收益变化(行情数据有随机数生成)。如果想观察哪只基金的收益高于或低于沪深300ETF,就可以从2D/3D的动画图上看出来。下面分四部分来讲述。
导入必要的工具包import numpy as npimport pandas as pd#import csv#from csv import writer# 绘图import matplotlib.pyplot as pltfrom matplotlib import animation  rcfrom matplotlib.cm import get_cmapfrom mpl_toolkits.mplot3d import Axes3Dfrom matplotlib.font_manager import FontPropertiesfrom matplotlib.collections import LineCollectionfrom matplotlib.colors import ListedColormapfrom mpl_toolkits.mplot3d.art3d import Line3DCollectionplt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = Falseimport matplotlib as mpl mpl.rcParams['animation.ffmpeg_path'] = r'C:\\ffmpeg\\bin\\ffmpeg.exe'# 设置动画类型rc('animation'  html='html5')导入数据
    
用随机数生成九只ETF基金的行情价格数据
index_returns = np.random.normal(loc=1e-4  scale=5e-3  size=(783  9))index_returns = np.vstack((np.zeros(shape=(1  9))   100  index_returns))# 累计收益index_prices = np.cumprod(1   index_returns  axis=0)# 选择时间窗口window = 261indexes_rolling = np.zeros(shape=(index_prices.shape[0]-window  9))# 生成滚动收益for i in range(window  index_prices.shape[0]  1):    indexes_rolling[i-window] = (index_prices[i]/index_prices[i-window]) - 1# 构成 dataframe 数据index = pd.date_range('2019-01-01'  periods=index_prices.shape[0]-window  freq='B')columns = ['智能汽车|515250'  '新能源车|515030 '  '半 导 体|512480'                   ' 银  行 |512800'  ' 沪深300|510300'   '创 新 药|159992'                   ' 光  伏 |515790'  '信息技术|159939'  '食品饮料|515170']indexes_rolling = pd.DataFrame(indexes_rolling  index=index  columns=columns)2D动画
- 创建2D动画的规格以及格式,即指定该动画图形的大小,颜色,图例等内容。
 
代码如下:
# 创建图形fig  axes = plt.subplots(1  2  figsize=(18  6)  gridspec_kw={'width_ratios': [.9  .1]})fig.patch.set_alpha(1)# 设置:右边的图形不可见,只更新左边部分axes[1].axis('off')ax = axes[0]# 获取 cmap cmap = get_cmap('RdYlGn')# 数据切分current_slice = indexes_rolling.values[:261  :]index_names = indexes_rolling.columnsindex_dates = indexes_rolling.index# 保存各ETF基金数据的列表lines = []for i in range(current_slice.shape[1]):    # 获取坐标    x = np.array(np.arange(current_slice.shape[0]))    y = np.array(current_slice[:  i])    # 绘制不同颜色的点和线段    points = np.array([x  y]).T.reshape(-1  1  2)    segments = np.concatenate([points[:-1]  points[1:]]  axis=1)    # 指定连续值,映射数据点的颜色    norm = plt.Normalize(-0.19  0.19)    lc = LineCollection(segments  cmap=cmap  norm=norm)    # 设置颜色值    lc.set_array(y)    lc.set_linewidth(2)    lc.set_color(cmap(y[-1] * 2.5   0.5))    lc.set_label(index_names[i])    lines.append(ax.add_collection(lc))# 添加背景的网格ax.legend(loc='center right'  bbox_to_anchor=(1.2  0.5)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})ax.yaxis.grid(color='gray'  linestyle='dashed')ax.xaxis.grid(color='gray'  linestyle='dashed')ax.set_xlim(0  current_slice.shape[0]-1)ax.set_ylim(-0.39  0.39)ax.set_yticklabels(['{:.0%}'.format(val) for val in ax.get_yticks()])ax.set_ylabel('滚动收益 - 1年')ax.set_xlabel('日 期')ax.set_xticklabels([index_dates[int(val)].strftime('%m/%y') for val in ax.get_xticks()])#ax.set_facecolor((0  0  0  1.0)) # 背景色ax.set_facecolor((0.05  0.05  0.65  1))# 演示图形plt.show()
    
演示图形如下:

2. 定义更新以上2D图形的函数
代码如下:
def update_lines_2D(num  data  columns  dates  cmap  lines  ax):            # 获得切分数据    current_slice = data[num:261 num  :]    current_dates = dates[num:261 num]        for i in range(current_slice.shape[1]):        # 获取坐标值        x = np.array(np.arange(current_slice.shape[0]))        y = np.array(current_slice[:  i])        # 绘制不同颜色的点和线段        points = np.array([x  y]).T.reshape(-1  1  2)        segments = np.concatenate([points[:-1]  points[1:]]  axis=1)        # 指定连续值,映射数据点的颜色        norm = plt.Normalize(-0.22  0.22)                lines[i].set_segments(segments)        lines[i].set_array(y)        #lines[i].set_color(cmap(y[-1] * 2.5   0.5))        lines[i].set_color(cmap(y[-1] * 2.5   0.5))        # 动态更新数据和标识    ax.set_xticklabels([dates[int(val) num].strftime('%m/%y') for val in ax.get_xticks()[:-1]]   [''])    ax.legend(loc='center right'  bbox_to_anchor=(1.2  0.5)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})          return lines# 初始化图形的各行的数据def init_lines_2D():       for line in lines:        line.set_array([])    return lines
    
3.创建2D动画
代码如下:
line_ani = animation.FuncAnimation(fig=fig                                     func=update_lines_2D                                     # frames=30                                    frames=indexes_rolling.shape[0]-261                                     init_func=init_lines_2D                                     fargs=(indexes_rolling.values  indexes_rolling.columns  indexes_rolling.index  cmap  lines  ax)                                    interval=75                                     blit=True)# 演示2D动画line_ani
    
演示结果如下图:

4.保存动画为GIF格式
代码如下:
# 演示数据的变化progress_callback = lambda i  n: print('Saving frame {:.0%}'.format(i/n)) if int((i/n) * 100) % 10 == 0 else None# 保存动画line_ani.save('./2D_animation.gif'  writer='imagemagick'  fps=14  dpi=80  codec='h264'  bitrate=2048  progress_callback=progress_callback)3D动画
- 创建3D动画的规格以及格式,即指定该动画图形的大小,颜色,图例等内容。
 
代码如下:
# 创建图形fig = plt.figure(figsize=(14.4  9))ax = fig.add_subplot(111  projection='3d')fig.patch.set_alpha(1)# 获得 cmap 的值cmap = get_cmap('RdYlGn')# 切分数据current_slice = indexes_rolling.values[:261  :]index_names = indexes_rolling.columnsindex_dates = indexes_rolling.index# 保存各ETF基金数据的线的列表lines = []for i in range(current_slice.shape[1]):    # 获取坐标值    x = np.array(np.arange(current_slice.shape[0]))    y = np.tile(i  current_slice.shape[0])    z = np.array(current_slice[:  i])    #  绘制不同颜色的点和线段    points = np.array([x  y  z]).T.reshape(-1  1  3)    segments = np.concatenate([points[:-1]  points[1:]]  axis=1)    # 指定连续值,映射数据点的颜色    norm = plt.Normalize(-0.19  0.19)    lc = Line3DCollection(segments  cmap=cmap  norm=norm  zorder=current_slice.shape[1]-i)    # 动态更新数据和标识    lc.set_array(z)    lc.set_linewidth(2)    lc.set_color(cmap(z[-1] * 2.5   0.5))    lc.set_label(index_names[i])    lines.append(ax.add_collection(lc))# 添加动画背景的网格ax.legend(loc='center right'  bbox_to_anchor=(1.1  0.46)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})ax.set_zlabel('滚动收益 1Y'  labelpad=10)ax.set_zlim(-0.39  0.39)ax.set_zticklabels([' '* 3   '{:.0%}'.format(val) for val in ax.get_zticks()]  fontdict={'verticalalignment': 'center'  'horizontalalignment': 'center'})ax.set_xlabel('Date'  labelpad=30)ax.set_xlim(0  current_slice.shape[0]-1)ax.set_xticklabels([index_dates[int(val)].strftime('%m/%y') for val in ax.get_xticks()[:-1]]   ['']  rotation=0  fontdict={'verticalalignment': 'top'  'horizontalalignment': 'center'})ax.set_yticks(np.arange(current_slice.shape[1]))ax.set_yticklabels([index_names[i] for i in range(current_slice.shape[1])]  rotation=-15  fontdict={'verticalalignment': 'center'  'horizontalalignment': 'left'})# ax.w_xaxis.set_pane_color((0  0  0  1.0))# ax.w_yaxis.set_pane_color((0  0  0  1.0))# ax.w_zaxis.set_pane_color((0  0  0  1.0))ax.w_xaxis.set_pane_color((0.05  0.05  0.65  1)) #ax.set_facecolor((0.05  0.05  0.65  1))ax.w_yaxis.set_pane_color((0.05  0.05  0.65  1))ax.w_zaxis.set_pane_color((0.05  0.05  0.65  1))ax.view_init(25  -60)# ------------------------------------------------------------------x_scale=1.8y_scale=1z_scale=1scale=np.diag([x_scale  y_scale  z_scale  1.0])scale=scale*(1.0/scale.max())scale[3 3]=1.0def short_proj():    return np.dot(Axes3D.get_proj(ax)  scale)ax.get_proj=short_projfig.subplots_adjust(left=0  right=1  bottom=0  top=1)# ------------------------------------------------------------------# 输出动画plt.show()
    
输出结果如下图所示:

2. 定义更新以上图形的函数
代码如下:
def update_lines_3D(num  data  columns  dates  cmap  lines  ax):        # 切分数据    current_slice = data[num:261 num  :]    current_dates = dates[num:261 num]         for i in range(current_slice.shape[1]):        # 获取坐标值        x = np.arange(current_slice.shape[0])        y = np.tile(i  current_slice.shape[0])        z = np.array(current_slice[:  i])        #  绘制不同颜色的点和线段        points = np.array([x  y  z]).T.reshape(-1  1  3)        segments = np.concatenate([points[:-1]  points[1:]]  axis=1)        # 指定连续值,映射数据点的颜色        norm = plt.Normalize(-0.19  0.19)                lines[i].set_segments(segments)        lines[i].set_array(z)        lines[i].set_color(cmap(z[-1] * 2.5   0.5))    # 动态更新数据和标识    ax.set_xticklabels([dates[int(val) num].strftime('%m/%y') for val in ax.get_xticks()[:-1]]   ['']  rotation=0  fontdict={'verticalalignment': 'top'  'horizontalalignment': 'center'})    ax.legend(loc='center right'  bbox_to_anchor=(1.1  0.46)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})        return linesdef init_lines_3D():    for line in lines:        line.set_array([])    return lines
    
3.创建3D动画
代码如下:
line_ani = animation.FuncAnimation(fig=fig                                     func=update_lines_3D                                     # frames=30                                    frames=indexes_rolling.shape[0]-261                                     init_func=init_lines_3D                                     fargs=(indexes_rolling.values  indexes_rolling.columns  indexes_rolling.index  cmap  lines  ax)                                    interval=75                                     blit=True)# 演示3D动画line_ani
    
演示结果如下图所示:

4.保存3D动画为GIF格式
progress_callback = lambda i  n: print('Saving frame {:.0%}'.format(i/n)) if int((i/n) * 100) % 10 == 0 else None# save the animationline_ani.save('./3D_animation.gif'  writer='imagemagick'  fps=14  dpi=80  codec='h264'  bitrate=2048  progress_callback=progress_callback)3D mesh 动画
- 创建3D mesh 动画的规格以及格式,即指定该动画图形的大小,颜色,图例等内容。
 
代码如下:
# 创建图形fig = plt.figure(figsize=(14.4  9))ax = fig.add_subplot(111  projection='3d')fig.patch.set_alpha(1)# 获取 cmap 的值cmap = get_cmap('RdYlGn')# 切分数据# current_slice = indexes_rolling.values[:261  :]current_slice = indexes_rolling.values[:int(261/2)  :]index_names = indexes_rolling.columnsindex_dates = indexes_rolling.index# 保存各ETF基金数据的线的列表lines = []for i in range(current_slice.shape[1]):    # 获取坐标值    x = np.array(np.arange(current_slice.shape[0]))    y = np.tile(i  current_slice.shape[0])    z = np.array(current_slice[:  i])    # 绘制不同颜色的点和线段    points = np.array([x  y  z]).T.reshape(-1  1  3)    segments = np.concatenate([points[:-1]  points[1:]]  axis=1)    # 指定连续值,映射数据点的颜色    norm = plt.Normalize(-0.19  0.19)    lc = Line3DCollection(segments  cmap=cmap  norm=norm  zorder=current_slice.shape[1]-i)    # 设定颜色值    lc.set_array(z)    lc.set_linewidth(2)    lc.set_color(cmap(z[-1] * 2.5   0.5))    lc.set_label(index_names[i])    lines.append(ax.add_collection(lc))# 保存 mesh 线的列表mesh_lines = []for j in range(current_slice.shape[0]):    if j % 1 == 0:                # 获取坐标值        x = np.tile(j  current_slice.shape[1])        y = np.arange(current_slice.shape[1])        z = np.array(current_slice[j  :])        # 绘制不同颜色的点和线段        points = np.array([x  y  z]).T.reshape(-1  1  3)        segments = np.concatenate([points[:-1]  points[1:]]  axis=1)        # 指定连续值,映射数据点的颜色        norm = plt.Normalize(-0.19  0.19)        lc = Line3DCollection(segments  cmap=cmap  norm=norm)        # 设定颜色值        lc.set_array(z)        lc.set_linewidth(2)        mesh_lines.append(ax.add_collection(lc))    # 添加 mesh 动画的背景网格ax.legend(loc='center right'  bbox_to_anchor=(1.1  0.46)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})ax.set_zlabel('Rolling Equity 1Y'  labelpad=10)ax.set_zlim(-0.39  0.39)ax.set_zticklabels([' '* 3   '{:.0%}'.format(val) for val in ax.get_zticks()]  fontdict={'verticalalignment': 'center'  'horizontalalignment': 'center'})ax.set_xlabel('Date'  labelpad=30)ax.set_xlim(0  current_slice.shape[0]-1)ax.set_xticklabels([index_dates[int(val)].strftime('%m/%y') for val in ax.get_xticks()[:-1]]   ['']  rotation=0  fontdict={'verticalalignment': 'top'  'horizontalalignment': 'center'})ax.set_yticks(np.arange(current_slice.shape[1]))ax.set_yticklabels([index_names[i]for i in range(current_slice.shape[1])]  rotation=-15  fontdict={'verticalalignment': 'center'  'horizontalalignment': 'left'})ax.w_xaxis.set_pane_color((0.05  0.05  0.65  1))ax.w_yaxis.set_pane_color((0.05  0.05  0.65  1))ax.w_zaxis.set_pane_color((0.05  0.05  0.65  1)) # (0.05  0.05  0.65  1)ax.view_init(25  -60)# ------------------------------------------------------------------x_scale=1.8y_scale=1z_scale=1scale=np.diag([x_scale  y_scale  z_scale  1.0])scale=scale*(1.0/scale.max())scale[3 3]=1.0def short_proj():    return np.dot(Axes3D.get_proj(ax)  scale)ax.get_proj=short_projfig.subplots_adjust(left=0  right=1  bottom=0  top=1)# ------------------------------------------------------------------# 输出图形plt.show()
    
输出结果如下图所示:

2.定义更新以上图形的函数
代码如下:
def update_mesh_lines_3D(num  data  columns  dates  cmap  lines  mesh_lines  ax):            # 切分数据    current_slice = data[num:int(261/2) num  :]         for i in range(current_slice.shape[1]):        # 获取坐标值        x = np.arange(current_slice.shape[0])        y = np.tile(i  current_slice.shape[0])        z = np.array(current_slice[:  i])        # 绘制不同颜色的点和线段        points = np.array([x  y  z]).T.reshape(-1  1  3)        segments = np.concatenate([points[:-1]  points[1:]]  axis=1)        # 指定连续值,映射数据点的颜色        norm = plt.Normalize(-0.19  0.19)                lines[i].set_segments(segments)        lines[i].set_array(z)        lines[i].set_color(cmap(z[-1] * 2.5   0.5))    # 通过计数检查当前的mesh线    counter = 0           for j in range(current_slice.shape[0]):        if j % 1 == 0:                                    # 获取坐标值            x = np.tile(j  current_slice.shape[1])            y = np.arange(current_slice.shape[1])            z = np.array(current_slice[j  :])            # 绘制不同颜色的点和线段            points = np.array([x  y  z]).T.reshape(-1  1  3)            segments = np.concatenate([points[:-1]  points[1:]]  axis=1)            # 设定 mesh 线的颜色值            norm = plt.Normalize(-0.22  0.22)                    mesh_lines[counter].set_segments(segments)            mesh_lines[counter].set_array(z)            counter  = 1            # 动态更新数据和标识    ax.set_xticklabels([dates[int(val) num].strftime('%m/%y') for val in ax.get_xticks()[:-1]]   ['']  rotation=0  fontdict={'verticalalignment': 'top'  'horizontalalignment': 'center'})    ax.legend(loc='center right'  bbox_to_anchor=(1.1  0.46)  fancybox=True  facecolor=(.95 .95 .95 1)  framealpha=1  shadow=False  frameon=True  ncol=1  columnspacing=0  prop={'family': 'SimHei'})        return linesdef init_mesh_lines_3D():    for line in lines:        line.set_array([])    return lines
    
3.创建3D mesh 动画
代码如下:
line_ani = animation.FuncAnimation(fig=fig                                     func=update_mesh_lines_3D                                     # frames=30                                    frames=indexes_rolling.shape[0]-int(261/2)                                    init_func=init_mesh_lines_3D                                     fargs=(indexes_rolling.values  indexes_rolling.columns  indexes_rolling.index  cmap  lines  mesh_lines  ax)                                    interval=100                                     blit=True)# 演示动画line_ani
    
演示结果如下图所示:





