查看原文
其他

代码不到40行的超燃动态排序图

大邓 大邓和他的Python 2022-07-09

出处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 下载了主要国家(地区)年度航空客运量数据

  1. import pandas as pd

  2. import warnings

  3. warnings.filterwarnings('ignore')


  4. df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])

  5. df.head()

咱们先只看2001年排名前10个国家

  1. df2 = df[['地区', '2001年']].sort_values(by='2001年', ascending=False).head(10)

  2. df2.sort_values(by='2001年', ascending=True, inplace=True)

  3. df2

基础图

先看看最基础的样子,有点简陋

  1. %matplotlib inline

  2. import matplotlib.pyplot as plt

  3. import matplotlib.ticker as ticker

  4. import matplotlib.animation as animation

  5. from IPython.display import HTML


  6. #显示中文(可能还会显示不了,请自行百度解决中文问题)

  7. plt.rcParams['font.sans-serif']=['SimHei']


  8. fig, ax = plt.subplots(figsize=(15, 8))

  9. ax.barh(df2['地区'], df2['2001年'])

颜色标签

我们给城市条形图配上颜色,这里原作者使用了7种颜色的rgb码。

我的新数据有47个国家,所以7种颜色重复使用了好几次。

注意:城市和颜色都是长度47

  1. colors = ['#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  2. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  3. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  4. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  5. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  6. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff', '#f7bb5f', '#eafb50',

  7. '#adb0ff', '#ffb3ff', '#90d595', '#e48381', '#aafbff']


  8. #给每个国家随机分配颜色

  9. countrycolors = dict()

  10. countrys = set(df['地区'])

  11. for color, country in zip(colors, countrys):

  12. countrycolors[country] = color


  13. countrycolors

Run

  1. {'巴勒斯坦': '#adb0ff',

  2. '伊拉克': '#ffb3ff',

  3. '越南': '#90d595',

  4. '土库曼斯坦': '#e48381',

  5. '阿曼': '#aafbff',

  6. .....

  7. '韩国': '#ffb3ff',

  8. '老挝': '#90d595',

  9. '尼泊尔': '#e48381',

  10. '印度': '#aafbff'}

排名前10的国家

  1. fig, ax = plt.subplots(figsize=(15, 8))


  2. #排名前10的国家

  3. ax.barh(df2['地区'], df2['2001年'], color=[countrycolors[c] for c in df2['地区']])

  4. for i, (value, country) in enumerate(zip(df2['2001年'], df2['地区'])):

  5. ax.text(value, i, country, size=14, weight=600, ha='right', va='bottom')

  6. ax.text(value, i, f'{value:,.0f}', size=14, ha='left', va='center')

  7. ax.text(1, 0.45, '2001年', transform=ax.transAxes, size=46, ha='right')

细节修饰

在上面我们实现了2001年各国航空客运量(人数)排名前10的可视化,现在我们将其封装进draw_barchart函数中。

  1. fig, ax = plt.subplots(figsize=(15, 8))


  2. def draw_barchart(year):

  3. #整理数据

  4. year = str(year)+'年'

  5. df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])

  6. df2 = df[['地区', year]].sort_values(by=year, ascending=False).head(7)

  7. df2.sort_values(by=year, ascending=True, inplace=True)


  8. #横向条形图

  9. ax.clear()

  10. ax.barh(df2['地区'], df2[year], color=[countrycolors[country] for country in df2['地区']])

  11. dx = df[year].max()/200


  12. for i, (value, country) in enumerate(zip(df2[year], df2['地区'])):

  13. ax.text(value-dx, i, country, size=14, weight=600, ha='right', va='bottom')

  14. ax.text(value+dx, i, f'{value:,.0f}', size=14, ha='left', va='center')



  15. #细节修饰

  16. ax.text(1, 0.45, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)

  17. ax.text(0, 1.06, '各国航空客运量(人次)', transform=ax.transAxes, size=12, color='#777777')


  18. ax.xaxis.set_ticks_position('top')

  19. ax.tick_params(axis='x', colors='#777777', labelsize=12)

  20. ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))

  21. ax.xaxis.set_ticks_position('top')

  22. ax.tick_params(axis='x', colors='#777777', labelsize=12)



  23. ax.margins(0, 0.01)

  24. ax.grid(which='major', axis='x', linestyle='-')

  25. ax.set_axisbelow(True)

  26. ax.text(0.3, 1.05, '1970~2015各国航空客运量(人次)',

  27. transform=ax.transAxes, size=24, weight=600, ha='left')


  28. plt.box(False)



  29. draw_barchart(2015)

爆燃动画

刚刚我们已经封装好了draw_barchart(year)函数,现在我们只需要简单的调用matplotlib中的animation模块,就可以顺着时间方向,渲染成动画效果。

可惜数据中没有祖国的身影,动画的爆燃性大打折扣。

  1. import matplotlib.animation as animation

  2. from IPython.display import HTML


  3. fig, ax = plt.subplots(figsize=(15, 8))

  4. animator = animation.FuncAnimation(fig, draw_barchart, frames=range(1970, 2016))

  5. HTML(animator.to_jshtml())

动态排名图可以输出为视频文件,会视频剪辑的还可以加上自己喜欢的bgm,让整个效果更加爆燃。不过在输出视频前,需要先安装好ffmpeg,这里只稍微说一下安装步骤:

  1. 命令行安装homebrew

  2. 命令行输入 brew install ffmpeg 上述安装步骤有疑问请自行百度

  1. animator.to_html5_video()

  2. animator.save('countryflys.mp4')

这是大邓视频剪辑出的效果

全部代码

不到40行代码的超然动态排序图

  1. %matplotlib inline

  2. import pandas as pd

  3. import matplotlib.pyplot as plt

  4. import matplotlib.ticker as ticker

  5. import matplotlib.animation as animation

  6. from IPython.display import HTML

  7. #显示中文(可能还会显示不了,请自行百度解决中文问题)

  8. plt.rcParams['font.sans-serif']=['SimHei']


  9. def draw_barchart(year):

  10. #整理数据

  11. year = str(year)+'年'

  12. df = pd.read_excel('国际数据主要国家(地区)年度数据.xls', skiprows=[0, 1, 2])

  13. df2 = df[['地区', year]].sort_values(by=year, ascending=False).head(7)

  14. df2.sort_values(by=year, ascending=True, inplace=True)

  15. #横向条形图

  16. ax.clear()

  17. ax.barh(df2['地区'], df2[year], color=[countrycolors[country] for country in df2['地区']])

  18. dx = df[year].max()/200

  19. for i, (value, country) in enumerate(zip(df2[year], df2['地区'])):

  20. ax.text(value-dx, i, country, size=14, weight=600, ha='right', va='bottom')

  21. ax.text(value+dx, i, f'{value:,.0f}', size=14, ha='left', va='center')

  22. #细节修饰

  23. ax.text(1, 0.45, year, transform=ax.transAxes, color='#777777', size=46, ha='right', weight=800)

  24. ax.text(0, 1.06, '各国航空客运量(人次)', transform=ax.transAxes, size=12, color='#777777')

  25. ax.xaxis.set_ticks_position('top')

  26. ax.tick_params(axis='x', colors='#777777', labelsize=12)

  27. ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))

  28. ax.xaxis.set_ticks_position('top')

  29. ax.tick_params(axis='x', colors='#777777', labelsize=12)

  30. ax.margins(0, 0.01)

  31. ax.grid(which='major', axis='x', linestyle='-')

  32. ax.set_axisbelow(True)

  33. ax.text(0.3, 1.05, '1970~2015各国航空客运量(人次)',

  34. transform=ax.transAxes, size=24, weight=600, ha='left')

  35. plt.box(False)


  36. fig, ax = plt.subplots(figsize=(15, 8))

  37. animator = animation.FuncAnimation(fig, draw_barchart, frames=range(1970, 2016))

  38. HTML(animator.to_jshtml())

近期文章


Python网络爬虫与文本数据分析

Python语法快速入门

Python爬虫快速入门

文本数据分析文章汇总(2016-至今)

当文本分析遇到乱码(ง'⌣')ง怎么办?

Loughran&McDonald金融文本情感分析库

使用分析师报告中含有的情感信息预测上市公司股价变动

当pandas遇上数据类型问题

如何理解pandas中的transform函数

利用mlxtend进行数据关联分析

计算社会经济学

初学Python常见异常错误

一行pandas代码生成哑变量

顺利开班 | python爬虫分析2019年杭州国庆工作坊顺利开班


课件获取方式,请在公众号后台回复关键词“动态排序图”,如果觉得有用,欢迎转发支持




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存