上一篇咱们对数据进行了从新布局,布局后的数据结构方便咱们进行柱状图可视化以及弹道分析。html
今天咱们来学习使用该数据集执着更酷炫的动态排名视频。python
先看效果:api
数据源就是咱们一直分析的COVID19 data 数据,能够去kaggle 下载。数组
导入咱们所需的库,相比于以前的文章,咱们本次分析会用到animation模块,重点是里面会提供FuncAnimation 类,帮助咱们实现动态图。bash
# coding: utf-8
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from datetime import datetime, timedelta
import numpy as np
复制代码
pandas 读取数据,这是每篇分析的第一步操做。 简单处理数据,采用groupby 函数将一些国家的各个省份信息合并成该国家的总和。 前一篇文章有详细介绍,此处再也不说明。数据结构
# read data
covid19_data_file = 'data/COVID_19_data.csv'
covid19_data_df = pd.read_csv(covid19_data_file)
# handle the countries data
df_country = covid19_data_df.groupby(
['ObservationDate', 'Country/Region']).sum()
df_country.reset_index(inplace=True)
复制代码
你们都知道,视频就是一堆堆图像(或者称为帧 frame)在时间轴上连续起来造成的。因此咱们的思路也很简单,制做一个画面,改变画面的内容,重复制做这个画面。ide
matplotlib 已经有这个类:FuncAnimation,它用来重复调用一个函数进行画图。咱们来研究一下它的主要参数,更详细的请参考官方文档。函数
class matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)[source]¶
复制代码
其中主要的参数:布局
为了调用这个函数,咱们须要准备好各个参数。post
fig, ax = plt.subplots(figsize=(15, 8))
start_date = datetime(2020, 1, 22)
end_date = datetime(2020, 5, 13)
dates_delta = (end_date - start_date).days
复制代码
先上代码,再作解释。
def mini_bar_chart_frame(
delta,
df=None,
start_date=None,
date_col=None,
cat_col=None,
observe_col=None,
top_k=10,
ax=None):
if start_date is None:
start_date = datetime(2020, 2, 22)
date_show = timedelta(days=delta) + start_date
date_str = date_show.strftime('%m/%d/%Y')
top_k_df = df[df[date_col].eq(date_str)].sort_values(
by=observe_col, ascending=False).head(top_k)
ax.clear()
# plot horizon bar
ax.barh(
top_k_df[cat_col],
top_k_df[observe_col],
log=False)
ax.invert_yaxis() # to make the biggest in the top
#dx = np.log(top_k_df[observe_col].max()) / 200
for i, (value, name) in enumerate(
zip(top_k_df[observe_col], top_k_df[cat_col])):
ax.text(
value - 20,
i,
name,
size=10,
weight=600,
ha='right',
va='center')
ax.text(
value + 0.1,
i,
f'{value:,.0f}',
size=10,
ha='left',
va='center')
ax.text(
1,
0.1,
date_str,
transform=ax.transAxes,
size=40,
ha='right',
weight=800)
ax.set_yticks([]) # we have label on the top of bar
复制代码
函数准备好了,下面咱们就将函数的对应的参数传递给FuncAnimation。
fargs = (df_country,
start_date,
'ObservationDate',
'Country/Region',
'Confirmed',
10,
ax)
animator = animation.FuncAnimation(
fig,
mini_bar_chart_frame,
frames=dates_delta,
fargs=fargs,
interval=1000,
repeat=False)
复制代码
咱们也可使用如下代码将其保存为本地mp4格式。
writer = animation.writers['ffmpeg']
writer = writer(fps=1)
animator.save('mini_covid_bar_race.mp4', writer=writer)
复制代码
咱们看一下上述代码的输出结果,这里我将视频转成gif以作演示。基本效果已经成型,应该算是很经典的动态排名了。
给柱状图添加颜色,应该很好处理。barh 函数带有color 参数,这里仅仅须要注意传入的颜色须要是类数组的格式。 小技巧:
color_dict = {'Mainland China': '#e63946',
'US': '#ff006e',
'Italy': '#02c39a',
'Span': '#f4a261',
'UK': '#3a86ff',
'Germany': '#370617',
'France': '#3a86ff',
'Japan': '#d8e2dc',
'Iran': '#fec89a',
'Russia': '#dc2f02'}
# barh 中的color 参数为:
# color=[
# color_dict.get(
# x,
# "#f8edeb") for x in top_k_df[cat_col]],
复制代码
这里我添加了一些文字来给视频作注释。好比3月15日,中国捐给西班牙50万个口罩。
之因此用英文,是由于最初这个视频是我放在facebook上给老外看的。
第二个缘由,是由于中文须要一些字体支持。
实现动态文字添加的思路很简单,就是ax.text 函数。实现方法相似于咱们的国家标签以及确诊数的标签。
timeline_event = {
'01/30/2020': 'WuHan declared lockdown.',
'01/31/2020': 'Italian suspended all flights from China',
'02/02/2020': 'Trump restricts on any foreigners from entering the U.S',
'03/13/2020': 'China sent medical supplies to Italy',
'03/15/2020': 'China donated 500,000 facemasks to Spain',
'03/19/2020': 'USA suspended visa services worldwide.',
'05/12/2020': 'America first(LOL).'
}
复制代码
xkcd 是啥? 只不过一个漫画名称而已,很差发音,也不是缩写。对于matplotlib 来讲,xkcd 就指的相似于漫画的的效果。通俗讲就是“线条抖啊抖啊抖~~~~” 代码很简单就一行:
with plt.xkcd():
把全部plt相关的代码放在这个with 里面
复制代码
除了添加颜色,动态文字以及“抖啊抖”的效果,咱们还作了一些细节处理,好比调整字体颜色,字号等小细节。
def xkcd_bar_chart_frame(
delta,
df=None,
start_date=None,
date_col=None,
cat_col=None,
observe_col=None,
top_k=10,
color_dict=None,
ax=None):
if start_date is None:
start_date = datetime(2020, 2, 22)
date_show = timedelta(days=delta) + start_date
date_str = date_show.strftime('%m/%d/%Y')
top_k_df = df[df[date_col].eq(date_str)].sort_values(
by=observe_col, ascending=False).head(top_k)
with plt.xkcd():
ax.clear()
# plot horizon bar
ax.barh(
top_k_df[cat_col],
top_k_df[observe_col],
color=[
color_dict.get(
x,
"#f8edeb") for x in top_k_df[cat_col]],
log=False,
left=1)
ax.invert_yaxis() # to make the biggest in the top
#dx = np.log(top_k_df[observe_col].max()) / 200
for i, (value, name) in enumerate(
zip(top_k_df[observe_col], top_k_df[cat_col])):
ax.text(
value - 20,
i,
name,
size=10,
weight=600,
ha='right',
va='center')
ax.text(
value + 0.1,
i,
f'{value:,.0f}',
size=10,
ha='left',
va='center')
ax.text(
1,
0.1,
date_str,
transform=ax.transAxes,
color='#f8edeb',
size=40,
ha='right',
weight=800)
ax.text(
0.5,
1.1,
'Covid-19',
transform=ax.transAxes,
size=14,
color='#f8edeb')
ax.text(
0.2,
0.05,
timeline_event.get(date_str, ''),
transform=ax.transAxes,
size=20,
color='#06d6a0')
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)
plt.box(False)
复制代码
从新调用这个新的func来制做动画。
fargs = (df_country,
start_date,
'ObservationDate',
'Country/Region',
'Confirmed',
10,
color_dict,
ax)
animator = animation.FuncAnimation(
fig,
xkcd_bar_chart_frame,
frames=dates_delta,
fargs=fargs,
interval=1000,
repeat=False)
复制代码
最后咱们来看一下咱们更新后的动画效果。ps. 眼看着中国从top10中消失,眼看着America First。
保存为MP4格式须要电脑安装ffmep 编码/解码器,安装好的ffmpeg_path须要添加到matplotlibrc 参数下。
# add ffmpeg path to matplotlibrc
plt.rcParams['animation.ffmpeg_path'] = r'your_path\ffmpeg-20200323-ba698a2-win64-static\ffmpeg-20200323-ba698a2-win64-static\bin\ffmpeg.exe'
复制代码
本文中咱们继续使用covid19的数据来进行可视化分析。咱们采用python 制做了酷炫的动态排名。 定义的函数能够套用在其余数据集中用于制做动态排名。 经过本文咱们能够学会:
据说Youtuber 使用Bar race 制做视频,月入50万。