使用Python+Matplotlib制作时序动态图

 更新时间:2023年07月25日 08:52:03   作者:老夫爱编程  
时序图是一个二维图,横轴表示对象,纵轴表示时间,消息在各对象之间横向传递,依照时间顺序纵向排列,可以直观的描述并发进程,所以本文就使用Python和Matplotlib制作一个简单的时许动态图,感兴趣的跟着小编一起来看看吧

一、项目效果及说明

最终的效果如下图所示

有几点说明:

1.  图中所展示的是从2000年到2021年全国人口最多的5个省市的人口数量、顺序位次以及变化情况;

2.  图中数据来源于“国家统计局”网站上的公开资料,但是,在最终使用的时候,并没有进行数据的核对;因为,仅仅是为了展示Python+Matplotlib在制作动态图的使用,而不是进行人口或者某个地区的研究;总之,本展示图,不针对任何地区,也不构成任何学术研究结论;

3.  图表中的颜色是系统随机选取的,后面的程序中有详细的说明;颜色不构成任何指射或者含义,仅仅是为了区分不同的数据;

4.  图表中仅仅展示了人口最多的5个省市区,如有需要,还可以更多,都可以在程序中设置。

5.  此文只是为了记录自己的学习过程,与同好交流,仅此而已。

二、项目环境说明

这个程序是在Jupyter Notebook下调试运行的,使用的Anaconda建立的虚拟环境,具体版本如下:

Python:3.9.16

Pandas:1.5.3

Matplotlib:3.7.1

Ipython:8.13.2

Jupyter Notebook:6.5.4

三、项目思路

利用Matplotlib制作动态图,我自己知道的思路有两个:

第一个,就是利用Matplotlib画出每一帧图片,保存成为“.png”或者是“jpg”格式,然后再使用imageio包,把这些文件按照顺序生成一个“GIF”文件,也会产生动画的效果;

第二个,就是利用Matplotlib中的Animation函数直接生成“GIF”格式的动画文件。

因为没有看过源码,所以,仅从自己的感受来看,第一个方法需要产生大量的中间文件,而且生成出来的动画,总有跳帧的感觉,变化不是十分平滑,也许是我制作水平的问题,也欢迎有高手指教。我测试过以后,决定使用第二个办法。这个办法不仅是Matplotlib“内生”的函数,而且还支持包括“MP4”在内的多种格式,还没有中间文件的产生。

Matplotlib的Animation函数还有很多的子类和功能,这次使用的只是其中之一。函数签名具体大致如下:

FuncAnimation(fig,func,frames,init_func,interval,blit)

其参数为:

① fig为绘制动图的画布名称;

② func为自定义动画函数,在本文中这个函数是draw_barchart(),在程序中会有详细的功能说明;

③ frames为动画长度,一次循环包含的帧数,在函数运行时,其值会传递给函数func中定义的形参,本文的函数只定义了一个形参“year”,其具体含义,程序中会有说明;

④ init_func为自定义开始帧,即初始化函数,可省略;

⑤ interval为更新频率,以ms计算;

四、程序及相关说明

from IPython.display import HTML
import pandas as pd
import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker 
import matplotlib.animation as animation
import seaborn as sns
import matplotlib.pyplot as plt
import random

以上是程序中用到所有库,都是必须的。

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

这两句之所以要特别拿出来说,是因为我曾经“踩坑”;如果没有这两个设置,那么,Matplotlib在生成图像以后,标签上的中文就会成为乱码。需要说明的是,第一个设置在这里直接使用了“赋值”,也可以把两个列表(list)加起来,但是,必须要让“['SimHei']”在整个列表的最前面,否则,还是没有效果。

result = prepare_data()

这个是我自己加载数据的模块,无非就是“pd.read_csv”来读取一个数据文件,因为,和本文的主旨无关,就不详细说明了。把结果列出来(见下图),并做适当说明,是因为,后文的程序中和数据被“读出来”以后的存储结果相关。

数据的“columns”的名字(name)是“地区”,“index”的名字(name)是“年份”,这个顺序只是“统计年鉴”上的顺序,并没有进行处理。后文的排序,每次都是根据“index”来进行“行排序”的。

# 生成了一批颜色,给每个地区赋予了一个不同的颜色,以后,用到这个地区,就用这个颜色来渲染
# 为了防止颜色比较接近,在颜色生成以后,随机打乱了,效果好了一点
color = sns.husl_palette(len(result.columns),h=15/360, l=.65, s=1).as_hex() 
random.shuffle(color)
colors = dict(zip(result.columns.tolist(),color))

这个就是前文所说的“随机选择颜色”的内容,利用random.shuffle,打乱颜色列表(list),然后再做成了一个字典(dict),以后,每个省市区都有了固定的颜色,每次画图的时候,都来这个字典中读取颜色,然后再进行渲染。确保在每次生成动画中,每个数据的颜色保持不变。

def draw_barchart(year):
    # 这里年份,只是一个顺序号码
    # 一般是个浮点数,小数点后面代表的是:一个时点的图像需要几次变换到下一个时点,
    # 小数就是次数的倒数,用于计算每次,图像的位移量
    # 整数在这里代表的是,索引的顺序
    # 这个表示的是x坐标的大小,也就是显示出来的数据的个数
    N_Display=5
    # 这个取整是用来确认现在图像属于哪个时点的
    year1=int(year)
    # 加一表示,图像下一个时点的顺序号
    year2=year1+1
    # 这个就是上面的注释里说的小数的部分
    location_x=year-year1
    # 对不同的时点的数据进行排序,才能得到不同顺序下的“地区”也就是“省市”的名称
    result_sort1 = result.sort_values(by=result.index[year1], axis=1, ascending=False)
    result_sort2 = result.sort_values(by=result.index[year2], axis=1, ascending=False)
    # 截取前5个省份,并倒序,可以让人口最多的省份在上,而其他的则是依次递减
    area1 = list(reversed(list((result_sort1.columns)[:5])))
    area2 = list(reversed(list((result_sort2.columns)[:5])))
    # 这个列表表达式是为了计算出,本期排名榜中的各个成员,在下一期中的位置
    # 同时,计算出,相对现在位置的偏移量
    # 如果没有出现在下一期中,则设置为‘0'
    # 具体计算内容是:i, elem in enumerate(area1)表示当前某个位置的名称和在列表中的顺序
    # elem in area2 判断某个当前位置在下一个时点中是否存在,
    # 如果不存在,则设置为‘0',否则按照下面的公式计算
    # i +1 +(area2.index(elem)-i)*location_x 两个时点的位置之差,乘以偏移量,表示每帧动画移动的位置
    # i +1 +就是确定下一帧动画时,图像的位置,加一是因为坐标是从“1”开始的
    # 这个列表就是每一帧动画的x轴的坐标
    diff = [i +1 +(area2.index(elem)-i)*location_x if elem in area2 else 0 for i, elem in enumerate(area1)]
    # 取出要显示的“人口数”,第二时点的数据取出来也是没有用的,为了对称,就这么写了
    pop_num1 = list(reversed(list(result_sort1.iloc[year1, :5])))
    pop_num2 = list(reversed(list(result_sort2.iloc[year2, :5])))
    # 开始画图,颜色就是按照前面设置的字典来去的,这样,每一个元素的颜色会始终不变
    ax.clear()
    ax.barh(diff, pop_num1, color=[colors[x] for x in area1])
    # 给每一个柱状图的最右边加上名字和数字,包括设定大小等
    for i, (value, name, x) in enumerate(zip(pop_num1, area1, diff)):
        ax.text(value, x, name, size=16, ha='right')
        ax.text(value, x, value, size=16, ha='left')
    # 在画布右方添加年份
    ax.text(1, 0.1, result.index[year1], transform=ax.transAxes, size=46, ha='right')
    # 设置坐标轴的大小,确保在动态图的过程中,图像的外壳不动,好看一点
    ax.set_xlim(0,15000)
    ax.set_ylim(0.5,N_Display+0.5)
    ax.set_xticks(ticks=np.arange(0,14000,1000))
    ax.set_yticks(ticks=np.arange(N_Display,0,-1))
    ax.set_yticklabels(labels=np.arange(N_Display,0, -1))
    ax.margins(0, 0.01)
    ax.text(0.2, 1.01, '2000——2021年间人口最多的地区',
            transform=ax.transAxes, size=26, weight='light', ha='left')
    # 取消了边框
    plt.box(False)

自我感觉,程序中的注释大约应该比较清楚了。这里就不再赘述了。放一张图,来表示一下函数的执行效果。

接下来,开始制作动画并保存

# 开始制作动画
# 这个才是整个图像的设置
fig, ax = plt.subplots(figsize=(8, 7))
plt.subplots_adjust(left=0.12, right=0.98, top=0.85, bottom=0.1)   
# 这个语句是产生动画的关键,第一个参数就是“画布”,第二个参数是画图的函数,
# 第三个产生参数的函数,这里产生的参数自动送到第二个参数中的函数,作为实参,
# 这里就是一连串的数字,表示数据的索引,以及几次移动到位的次数的倒数
# 在后面的参数是“间隔”的毫秒数
animator = animation.FuncAnimation(fig, draw_barchart, frames=np.arange(0, 21, 0.1),interval=20)
# 这个直接在网页上生成动画
# HTML(animator.to_jshtml()) 
# 这个是用一个文件名直接保存成动画,系统自动识别文件后缀,还可以是“MP4”格式的
animator.save('result.gif')

这个过程大约需要一点时间,然后就能在目录文件下发现保存完成的“GIF”图片了。

至此,时序动态图制作完成。

到此这篇关于使用Python+Matplotlib制作时序动态图的文章就介绍到这了,更多相关Python Matplotlib时序动态图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python 比较文本相似性的方法(difflib,Levenshtein)

    Python 比较文本相似性的方法(difflib,Levenshtein)

    今天小编就为大家分享一篇Python 比较文本相似性的方法(difflib,Levenshtein),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • python排序方法实例分析

    python排序方法实例分析

    这篇文章主要介绍了python排序方法,实例分析了Python实现默认排序、降序排序及按照key值排序的相关技巧,非常简单实用,需要的朋友可以参考下
    2015-04-04
  • 对pandas将dataframe中某列按照条件赋值的实例讲解

    对pandas将dataframe中某列按照条件赋值的实例讲解

    今天小编就为大家分享一篇对pandas将dataframe中某列按照条件赋值的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • Python cookbook(数据结构与算法)将序列分解为单独变量的方法

    Python cookbook(数据结构与算法)将序列分解为单独变量的方法

    这篇文章主要介绍了Python cookbook(数据结构与算法)将序列分解为单独变量的方法,结合实例形式分析了Python序列赋值实现的分解成单独变量功能相关操作技巧,需要的朋友可以参考下
    2018-02-02
  • 一个Python优雅的数据分块方法详解

    一个Python优雅的数据分块方法详解

    在做需求过程中有一个对大量数据分块处理的场景,具体来说就是几十万量级的数据,分批处理,每次处理100个。这时就需要一个分块功能的代码。本文为大家分享了一个Python中优雅的数据分块方法,需要的可以参考一下
    2022-05-05
  • 2023最新pytorch快速安装指南(超详细版)

    2023最新pytorch快速安装指南(超详细版)

    这篇文章主要给大家介绍了2023年最新pytorch快速安装指南的相关资料,PyTorch是一个开源的深度学习框架,提供了各种张量操作并通过自动求导可以自动进行梯度计算,方便构建各种动态神经网络,需要的朋友可以参考下
    2023-10-10
  • 一行Python代码过滤标点符号等特殊字符

    一行Python代码过滤标点符号等特殊字符

    这篇文章主要介绍了一行Python代码过滤标点符号等特殊字符的相关知识,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • Django restframework 框架认证、权限、限流用法示例

    Django restframework 框架认证、权限、限流用法示例

    这篇文章主要介绍了Django restframework 框架认证、权限、限流用法,结合实例形式详细分析了Djangorestframework 框架认证、权限、限流的具体使用方法及相关操作注意事项,需要的朋友可以参考下
    2019-12-12
  • Python tkinter控件样式详解

    Python tkinter控件样式详解

    tkinter对控件的诸多属性提供了可定制的功能,下面以最常用的按钮作为示例,集中展示其样式特点,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-09-09
  • 使用Python实现不同需求的排行榜功能

    使用Python实现不同需求的排行榜功能

    这篇文章主要为大家介绍了Python实现不同需求的排行榜功能,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01

最新评论