代码不到40行的超燃动态排序图
出处https://colab.research.google.com/github/pratapvardhan/notebooks/blob/master/barchart-race-matplotlib.ipynb
需要使用vpn,我已经将该文件放到项目中,大家可在文末获得下载方式
这种图在国外叫做 Bar Chart Race, 通过这个图可以察公司沉浮,观国家兴衰。
我使用了统计局网站提供的各国航空客运量数据,这这个数据中没有中国出现,遗憾啊!
读取航空客运量数据
在国家统计局 http://data.stats.gov.cn/easyquery.htm?cn=C01 下载了主要国家(地区)年度航空客运量数据
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])
df.head()
咱们先只看2001年排名前10个国家
df2 = df[['地区', '2001年']].sort_values(by='2001年', ascending=False).head(10)
df2.sort_values(by='2001年', ascending=True, inplace=True)
df2
基础图
先看看最基础的样子,有点简陋
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from IPython.display import HTML
#显示中文(可能还会显示不了,请自行百度解决中文问题)
plt.rcParams['font.sans-serif']=['SimHei']
fig, ax = plt.subplots(figsize=(15, 8))
ax.barh(df2['地区'], df2['2001年'])
颜色标签
我们给城市条形图配上颜色,这里原作者使用了7种颜色的rgb码。
我的新数据有47个国家,所以7种颜色重复使用了好几次。
注意:城市和颜色都是长度47
colors = ['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',
'#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff']
#给每个国家随机分配颜色
countrycolors = dict()
countrys = set(df['地区'])
for color, country in zip(colors, countrys):
countrycolors[country] = color
countrycolors
Run
{'巴勒斯坦': '#adb0ff',
'伊拉克': '#ffb3ff',
'越南': '#90d595',
'土库曼斯坦': '#e48381',
'阿曼': '#aafbff',
.....
'韩国': '#ffb3ff',
'老挝': '#90d595',
'尼泊尔': '#e48381',
'印度': '#aafbff'}
排名前10的国家
fig, ax = plt.subplots(figsize=(15, 8))
#排名前10的国家
ax.barh(df2['地区'], df2['2001年'], color=[countrycolors[c] for c in df2['地区']])
for i, (value, country) in enumerate(zip(df2['2001年'], df2['地区'])):
ax.text(value, i, country, size=14, weight=600, ha='right', va='bottom')
ax.text(value, i, f'{value:,.0f}', size=14, ha='left', va='center')
ax.text(1, 0.45, '2001年', transform=ax.transAxes, size=46, ha='right')
细节修饰
在上面我们实现了2001年各国航空客运量(人数)排名前10的可视化,现在我们将其封装进draw_barchart函数中。
fig, ax = plt.subplots(figsize=(15, 8))
def draw_barchart(year):
#整理数据
year = str(year)+'年'
df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])
df2 = df[['地区', year]].sort_values(by=year, ascending=False).head(7)
df2.sort_values(by=year, ascending=True, inplace=True)
#横向条形图
ax.clear()
ax.barh(df2['地区'], df2[year], color=[countrycolors[country] for country in df2['地区']])
dx = df[year].max()/200
for i, (value, country) in enumerate(zip(df2[year], df2['地区'])):
ax.text(value-dx, i, country, size=14, weight=600, ha='right', va='bottom')
ax.text(value+dx, i, f'{value:,.0f}', size=14, ha='left', va='center')
#细节修饰
ax.text(1, 0.45, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)
ax.text(0, 1.06, '各国航空客运量(人次)', transform=ax.transAxes, size=12, color='#777777')
ax.xaxis.set_ticks_position('top')
ax.tick_params(axis='x', colors='#777777', labelsize=12)
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.margins(0, 0.01)
ax.grid(which='major', axis='x', linestyle='-')
ax.set_axisbelow(True)
ax.text(0.3, 1.05, '1970~2015各国航空客运量(人次)',
transform=ax.transAxes, size=24, weight=600, ha='left')
plt.box(False)
draw_barchart(2015)
爆燃动画
刚刚我们已经封装好了draw_barchart(year)函数,现在我们只需要简单的调用matplotlib中的animation模块,就可以顺着时间方向,渲染成动画效果。
可惜数据中没有祖国的身影,动画的爆燃性大打折扣。
import matplotlib.animation as animation
from IPython.display import HTML
fig, ax = plt.subplots(figsize=(15, 8))
animator = animation.FuncAnimation(fig, draw_barchart, frames=range(1970, 2016))
HTML(animator.to_jshtml())
动态排名图可以输出为视频文件,会视频剪辑的还可以加上自己喜欢的bgm,让整个效果更加爆燃。不过在输出视频前,需要先安装好ffmpeg,这里只稍微说一下安装步骤:
命令行安装homebrew
命令行输入 brew install ffmpeg 上述安装步骤有疑问请自行百度
animator.to_html5_video()
animator.save('countryflys.mp4')
这是大邓视频剪辑出的效果
全部代码
不到40行代码的超然动态排序图
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from IPython.display import HTML
#显示中文(可能还会显示不了,请自行百度解决中文问题)
plt.rcParams['font.sans-serif']=['SimHei']
def draw_barchart(year):
#整理数据
year = str(year)+'年'
df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])
df2 = df[['地区', year]].sort_values(by=year, ascending=False).head(7)
df2.sort_values(by=year, ascending=True, inplace=True)
#横向条形图
ax.clear()
ax.barh(df2['地区'], df2[year], color=[countrycolors[country] for country in df2['地区']])
dx = df[year].max()/200
for i, (value, country) in enumerate(zip(df2[year], df2['地区'])):
ax.text(value-dx, i, country, size=14, weight=600, ha='right', va='bottom')
ax.text(value+dx, i, f'{value:,.0f}', size=14, ha='left', va='center')
#细节修饰
ax.text(1, 0.45, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)
ax.text(0, 1.06, '各国航空客运量(人次)', transform=ax.transAxes, size=12, color='#777777')
ax.xaxis.set_ticks_position('top')
ax.tick_params(axis='x', colors='#777777', labelsize=12)
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.margins(0, 0.01)
ax.grid(which='major', axis='x', linestyle='-')
ax.set_axisbelow(True)
ax.text(0.3, 1.05, '1970~2015各国航空客运量(人次)',
transform=ax.transAxes, size=24, weight=600, ha='left')
plt.box(False)
fig, ax = plt.subplots(figsize=(15, 8))
animator = animation.FuncAnimation(fig, draw_barchart, frames=range(1970, 2016))
HTML(animator.to_jshtml())
近期文章
顺利开班 | python爬虫分析2019年杭州国庆工作坊顺利开班
课件获取方式,请在公众号后台回复关键词“动态排序图”,如果觉得有用,欢迎转发支持