LarryDpk
发布于 2022-11-25 / 264 阅读
0

用Python做了一个广东疫情新增病例动态视频

1 简介

最近广东疫情实在是太严重了,特别是广州。作为南大门,人口流动太大,又毗邻港澳,防疫任务太重。从11月以来,就发展极其迅猛。疫情也给大家的生活带来了诸多不便,我有许多同事和朋友都居家隔离了。

时代的尘埃落在个体身上,都是灾难。

为了对疫情了解更多,我用Python写了个小程序,来生成一个新增病例的变化视频,且记录一下这个无聊的过程吧。

2 数据准备

为了获得准确的第一手数据,我是关注了健康广东这个公众号,每天早上可以看到最新的数据。同时在广东省卫健委的网站也可以获取。

接着会把数据记录在Excel表格里,方面查看。11月以来数据如下:

注:新增 = 新增确诊 + 新增无症状

日期广东确诊广州确诊广东无症状广州无症状广东新增广州新增
11月1日239190458289697479
11月2日10673298253404326
11月3日6950356323425373
11月4日187142470430657572
11月5日160111669635829746
11月6日133661330125914631325
11月7日1851221882181320671935
11月8日1981142330226325282377
11月9日197912611254628082637
11月10日2001252507243027072555
11月11日2892252461235827502583
11月12日3232592996292133193180
11月13日2471893541346437883653
11月14日2191893941387641604065
11月15日1731475047497752205124
11月16日1951586215613864106296
11月17日3072758576848688838761
11月18日3212559110898994319244
11月19日3552698535844488908713
11月20日2812008381823486628434
11月21日3842968101788584858181
11月22日3472538241795785888210
11月23日3532357951773583047970
11月24日5494287505719280547620
11月25日3952577584726779797524

3 读取数据

因为要用Python展示,即做数据可视化(数据可视化的工具很多,不一定要用Python),所以需要用Python读取Excel中的数据。我使用的是库pyexcel。代码如下:

def load_data():
    records = p.get_records(file_name="covid-19.xlsx")
    print(records)
    data_x = []
    data_y1 = []
    data_y2 = []
    for record in records[1:]:
        dt = excel_to_datatime(record['-1'])
        data_x.append(dt)
        data_y1.append(record['-6'])
        data_y2.append(record['-7'])
    return data_x, data_y1, data_y2

其中covid-19.xlsx就是Excel文件名。而-1, -6, -7分别是对应的日期,和最后两列,Debug的时候定位的,暂时没空深究。

3.1 Excel日期的问题

Excel日期是用一个数字来表示的,所以需要把这个数值转化成Python的日期类型,具体代码如下:

def excel_to_datatime(excel_date):
    dt = datetime.fromordinal(datetime(1900, 1, 1).toordinal() + excel_date - 2)
    return dt

同时为了格式化输出日期,新增了个函数,没啥特别的:

def datetime_to_str(dt, pattern):
    return pattern.format(dt.month, dt.day)

4 Python数据可视化

Python做数据可视化的库可太多了,我选择的是matplotlib,一方面是因为它用的多,资料也多;另一方面是我大学用过Matlab,两者很像,省去一些学习时间成本。

为了简便,打算就画个曲线变化图就行了,所以横轴为日期,纵轴为新增数。画个简单的图代码如下:

# plot
fig, ax = plt.subplots(figsize=(4, 3), dpi=120)
ax.plot(data_x, data_y1, linewidth=2.0, color='red')
ax.plot(data_x, data_y2, linewidth=2.0, color='blue')
plt.show()

红色是广东新增,蓝色是广州新增:

把数据标在曲线上:

for i, v in enumerate(data_y1):
    ax.text(data_x[i], v + 300, v, ha='center', color='red', fontsize=8)

for i, v in enumerate(data_y2):
    ax.text(data_x[i], v - 300, v, ha='center', color='blue', fontsize=8)

可以看到,3000到6000,再到8000的变化是极快的:

后面还有许多细节优化,就不一一讲解了。

5 转化视频

首先要明白,视频的本质还是图片,只是把图片放快了而已。所以,可以画图,就有办法做视频。好在matplotlib也提供了制作动画的函数,直接调用即可。需要调用的是animation.FuncAnimation这个方法。我们要提供初始化函数,还有如何制作每一帧画面的函数,就可以制作视频了。

初始化就直接给个空就行:

def init():
    line1.set_data([], [])
    line2.set_data([], [])
    return line1, line2, text1, text2, text_gd, text_gz, text_date

每一帧的函数如下:

def animate(i):
    print('Processing {} for {}'.format(i, data_x[i]))
    x = range(i + 2)
    x = x[1:]
    line1.set_data(x, data_y1[:i + 1])
    line2.set_data(x, data_y2[:i + 1])
    text1 = ax.text(i + 1, data_y1[i] + 150, data_y1[i], ha='center', color='red', fontsize=8)
    text2 = ax.text(i + 1, data_y2[i] - 150, data_y2[i], ha='center', color='blue', fontsize=8)
    text_gd.set_text('广东新增:' + str(data_y1[i]))
    text_gz.set_text('广州新增:' + str(data_y2[i]))
    text_date.set_text(datetime_to_str(data_x[i], '2022年{}月{}日'))
    plt.scatter(x, data_y1[:i + 1], color='bisque')
    plt.scatter(x, data_y2[:i + 1], color='cyan')
    return line1, line2, text1, text2, text_gd, text_gz, text_date

核心是的两条曲线:line1, line2,每次动态的改变它的数据,就会重画;

text1, text2是新增数,标在曲线上的;

scatter函数是标点,显眼一点;

text_gd, text_gz, text_date在左上角动态显示变化的日期和数据。

图片大体效果如下:

最后,我们要将一帧一帧整合成视频,使用以下函数:

plt.rcParams['animation.ffmpeg_path'] = '/Users/larry/Software/ffmpeg/ffmpeg'
anim.save('covid-19-Guangdong.mp4', fps=1, extra_args=['-vcodec', 'libx264'])

注意:这里需要用到软件ffmpeg,要指定你所安装的位置。这个软件可以直接从这里下载:https://evermeet.cx/ffmpeg/

最终视频效果如下:

6 最后

愿大家健康快乐!

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples/tree/master/python/src/main/python/covid-19-Guangdong


References:

How to Animate Line Plots Using Matplotlib in Python

https://medium.com/intel-student-ambassadors/live-graph-simulation-using-python-matplotlib-and-pandas-30ea4e50f883

https://towardsdatascience.com/animations-with-matplotlib-d96375c5442c

Excel Date:

https://www.geeksforgeeks.org/python-convert-excel-serial-date-to-datetime/

https://www.geeksforgeeks.org/how-to-convert-a-python-datetime-datetime-to-excel-serial-date-number/

https://stackoverflow.com/questions/31359150/convert-date-from-excel-in-number-format-to-date-format-python

Example and Turorial:

Top 50 matplotlib Visualizations – The Master Plots (with full python code)

Matplotlib Animation Tutorial

Colors:

https://matplotlib.org/stable/gallery/color/named_colors.html