Matplotlib数据动态可视化

1.效果预览

我们从国家统计局 下载最近30年全国各地区生产总值(实际上是1993年-2019年),使用matplotlib绘制动态可视化图,效果如下:

在这里插入图片描述

# 需要引入的库
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from IPython.display import HTML

2.数据获取

直接从国家统计局-国家数据(http://data.stats.gov.cn/)下载原始数据即可,数据长这样:

image-20200809175547945

3.数据预处理

原始数据的行索引是地区,列索引是年份,我们后续作图需要的数据结构偏向于窄表(当然宽表其实也可以做到,这里我个人习惯用窄表处理)。

为了实现宽表变窄表,用到pandas里的melt方法。

import pandas as pd
# 读取下载后的数据
df = pd.read_excel(r'F:\微信公众号\matplotlib动态图\各地区生产总值.xlsx')
df.head()

# 使用melt方法进行处理
data = df.melt(id_vars='地区',value_vars=range(1993,2020),var_name='年份',value_name='生产总值(亿)')
data.head()

4.matplotlib动态可视化

matplotlib动态图用到的是animation.FuncAnimation方法,其实动态就是N张图一张一张按照一定频率刷新,我们也有其他方法实现,这里不展开。

在我们的效果展示中,可以看到 类型是条形图,数值高低排序,每个条形图颜色不一样,我们来一步一步看看如何做出最终效果~

4.1.朴实无华的条形图

barh是条形图,就是横着的柱状图,以下我们先取2019年的年度数据展示前10地区

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
# 以下代码解决显示中文问题
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘制 2019年 各地区生产总值(前10)
currentYear = 2019
ddata = (data[data['年份']==currentYear]
        .sort_values(by='生产总值(亿)',ascending = True)
        .tail(10))
fix, ax = plt.subplots(figsize=(15,8))
ax.barh(ddata['地区'], ddata['生产总值(亿)'])

我们看到上面这张图平平无奇,朴实无华的配色,没有多一分的元素(标题、数据标签等等),接下来我们先把条形图美化一下

4.2.有点还行的条形图

通过自定义条形图配色,再附上一些text说明。

关于配色,直接从网上(https://www.beejson.com/word/rgb.html)找 16进制配色表,然后取31个即可(咱们一共有31个地区数据不含港澳台)。然后将31个地区与31个颜色进行组合成字典备用!

构造地区-颜色字典

# 我直接从网上批量复制了 30多个颜色值,然后随机抽取31个和31个地区配对
a = ['#FFFFCC 	#FFCC00 	#CC9909 	#663300 	#FF6600 	#663333 	#CC6666 	#FF6666 	#FF0000 	#FFFF99 	#FFCC66 	#FF9900 	#FF9966 	#CC3300 	#996666 	#FFCCCC 	#660000 	#FF3300 	#FF6666 	#FFCC33 	#CC6600 	#FF6633 	#996633 	#CC9999 	#FF3333 	#990000 	#CC9966 	#FFFF33 	#CC9933 	#993300 	#FF9933 	#330000 	#993333 	#CC3333 	#CC0000 	#FFCC99 	#FFFF00 	#996600']
b =' '.join(a)
c = b.split(' \t')

import random
# 随机不放回抽取31个
color = random.sample(c,31)
# 获取原数据中地区列表
province = list(data['地区'].unique())
# 组合成 地区-颜色值 字典
colors = dict(zip(province,color))

绘制有颜的条形图

fig, ax = plt.subplots(figsize=(15,8))
ax.barh(ddata['地区'], ddata['生产总值(亿)'],color = [colors[x] for x in ddata['地区']])
# 在每个条形图末端显示 归属地区 及 生产总值(亿)
for i, (num, pro) in enumerate(zip(ddata['生产总值(亿)'], ddata['地区'])):
    ax.text(num,i, pro, ha = 'right')
    ax.text(num,i, f':{num}亿', ha = 'left')
# 在右侧中部偏下显示当前年份
ax.text(1, 0.4, currentYear, transform= ax.transAxes, size=40, ha='right')
Text(1, 0.4, '2019')

有人就要说了,上面这个图也没啥好看的,除了增加了单独的配色以及数据显示外。。讲的太对了,字体还丑、颜色搭配也是难看,当然这些都是可以自己配置的
因为后续 我们会换个plt.xkcd()手绘卡通风格的形式,但是卡通风格的形式需要特别处理中文字体显示问题,这里先介绍下来自好朋友 ‘小明哥’ 的帮助,如下代码(设置字体为我系统里的微软雅黑,字号16)

# 字体管理
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname=r"C:\Windows\Fonts\msyh.ttc",size=14)
# 再加入其他一些元素(如标题、刻度线、刻度放在最上方等)
fig, ax = plt.subplots(figsize=(15,8))
ax.barh(ddata['地区'], ddata['生产总值(亿)'],color = [colors[x] for x in ddata['地区']])

for i, (num, pro) in enumerate(zip(ddata['生产总值(亿)'], ddata['地区'])):
    ax.text(num,i, pro, ha = 'right',fontproperties=my_font)
    ax.text(num,i, f' :{num}亿', ha = 'left',fontproperties=my_font)

ax.text(1, 0.4, currentYear, transform= ax.transAxes,fontproperties=my_font, size=40, ha='right')

# x刻度设置在顶部
ax.xaxis.set_ticks_position('top')
# x刻度颜色设置为灰色,大小为12
ax.tick_params(axis= 'x',colors= '#777777',labelsize= 12)
# 去掉y刻度
ax.set_yticks([])
# 设置 xy轴内边距
ax.margins(0, 0.01)
# 显示网格(x轴向虚线)
ax.grid(which= 'major', axis= 'x',linestyle= '--')
# 网格线至于底部
ax.set_axisbelow(True)
# 在左上角显示 标题(不是用的title方法)
ax.text(0, 1.06,'全国各地区生产总值(1993-2019)',transform= ax.transAxes,weight =600,ha = 'left',fontproperties= my_font,size=24)
# 去掉边框
plt.box(False)

4.3.会动的条形图

既然动图是一张张图刷新而来,那我们把每年的数据都做一张图再定时刷新替换不就好了,这样当然是可以的。

所以,我们先看看animation.FuncAnimation(https://matplotlib.org/api/animation_api.html)吧

官网有个简单的例子:sin(x)的动态演示。这里不做介绍,源码清晰,我们直接现学现做~

先把上面作图代码封装成函数

这个函数只需要一个参数,year(年份)

fig, ax = plt.subplots(figsize=(12,16))
def drawBarh(year):
    ddata = (data[data['年份']==year]
        .sort_values(by='生产总值(亿)',ascending = True)
        .tail(31))
    ax.clear()
    
    ax.barh(ddata['地区'], ddata['生产总值(亿)'],color = [colors[x] for x in ddata['地区']])

    for i, (num, pro) in enumerate(zip(ddata['生产总值(亿)'], ddata['地区'])):
        ax.text(num,i, pro, ha = 'right',fontproperties=my_font)
        ax.text(num,i, f' :{num}亿', ha = 'left',fontproperties=my_font)

    ax.text(1, 0.4, year, transform= ax.transAxes,fontproperties=my_font, size=40, ha='right')

    # x刻度设置在顶部
    ax.xaxis.set_ticks_position('top')
    # x刻度颜色设置为灰色,大小为12
    ax.tick_params(axis= 'x',colors= '#777777',labelsize= 12)
    # 去掉y刻度
    ax.set_yticks([])
    # 设置 xy轴内边距
    ax.margins(0, 0.01)
    # 显示网格(x轴向虚线)
    ax.grid(which= 'major', axis= 'x',linestyle= '--')
    # 网格线至于底部
    ax.set_axisbelow(True)
    # 在左上角显示 标题(不是用的title方法)
    ax.text(0, 1.06,'全国各地区生产总值(1993-2019)',transform= ax.transAxes,weight =600,ha = 'left',fontproperties= my_font,size=24)
    # 去掉边框
    plt.box(False)

# 演示2019年数据
drawBarh(2019)

animation动图制作

再调用animation.FuncAnimation方法进行动图制作

fig ,ax =plt.subplots(figsize = (12,16))
# 手绘卡通风格
plt.xkcd()
animator = animation.FuncAnimation(fig,drawBarh,frames=range(1993,2020),interval=500)
HTML(animator.to_jshtml())
  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值