近非常流行动态条形图,在各个APP都有百万播放量,我参考很多优秀的人文章,最终实现动态条形图的生成;生成的效果如图:

MPAndroidChart多条动态曲线_matplotlib

         我也是一名某科大大数据专业的在校大学生,也会遇到很多形形色色的问题,所以每一步都做的很踏实,结果很清楚。后续也会出一些很实用的代码以很直观的方式展示出来,有好的方法大家 也可以一起讨论讨论。

 1.使用的库

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker 
import matplotlib.animation as animation
from IPython.display import HTML
import gif

2.初步做一个简单的条形图

1.读取文件

df = pd.read_excel('江苏省2018~2021年人均gdp对比图.xlsx')
df.head(5)

MPAndroidChart多条动态曲线_python_02

 2.对数据进行分组

current_year = 2018
dff = (df[df['year'].eq(current_year)]
       .sort_values(by='人均GDP', ascending=False)
       .head(13))

以下是2018年江苏省13市的人均GDP数据

MPAndroidChart多条动态曲线_matplotlib_03

 3.展示条形图

plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
fig, ax = plt.subplots(figsize=(15, 8))
ax.barh(dff['city'], dff['人均GDP'])
plt

MPAndroidChart多条动态曲线_matplotlib_04

 3.动态条形图制作

1.读取excel文件数据,提出城市

df = pd.read_excel('江苏省2018~2021年人均gdp对比图.xlsx')
city_list = list(set(df.city))

MPAndroidChart多条动态曲线_开发语言_05

 

 2.导入random函数,randomcolor用于生成颜色代码

# randomcolor生成颜色代码原理,
# 【1-9/A-F】15个数字随机组合成6位字符串前面再加上一个“#”号键
import random
def randomcolor():
    colorlist = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    color =''
    for i in range(6):
        color += random.choice(colorlist)
    return '#'+ color

 3.构造一个city_color字典

city_color = {}
for city in city_list:
    city_color[city] = randomcolor()

MPAndroidChart多条动态曲线_matplotlib_06

4.定义一个画条形图的函数:

def draw_barchart(current_year):
    dff = df[df['year'].eq(current_year)].sort_values(by='人均GDP',ascending = True)

    ax.clear()
    ax.barh(dff['city'],dff['人均GDP'],color = [city_color[x] for x in dff['city']]) #ax.bar是一般的条形图,barh是水平的条形图,h是horizontal的意思
    dx = dff['人均GDP'].max()/200
    for i ,(value,name) in enumerate(zip(dff['人均GDP'], dff['city'])):
            ax.text(value+dx,i ,f'{value:,.0f}',size = 14,ha = 'left',va ='center')
    ax.text(1,0.4,current_year,transform = ax.transAxes,color ='#777777',size = 16,ha ='right',weight=800) 
    ax.text(0,1.06,'人',transform = ax.transAxes,size=12,color='#777777')

        #set_major_formatter表示刻度尺格式;
    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([]) #set_yticks([])表示不显示y轴的取值
        #margins表示自动缩放余额;
    ax.margins(0,0.01)
        # 设置后面的网格
    ax.grid(which='major',axis='x',linestyle='-')
        #刻度线和网格线是在图标上方还是下方,True为下方
    ax.set_axisbelow(True)
    ax.text(0,1.15,'2018-2021年江苏省13市GDP排名',
            transform=ax.transAxes,size=24,weight=600,ha='left',va='top')
    ax.text(1,0,'by 小yang',transform = ax.transAxes,color ='#777777',ha = 'right',
               bbox = dict(facecolor='white',alpha = 0.8,edgecolor='white'))
        #取消图表周围的方框显示
    plt.box(False)
    #plt.savefig('{}.jpg'.format(current_year))保存图片,用在gif图

 5.画出条形图

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] #设置汉字字体
fig, ax = plt.subplots(figsize=(15, 8))#设置画布大小
animator = animation.FuncAnimation(fig, draw_barchart, frames=range(2018, 2022),interval=700) #interval越大速度越慢

6.以HTML的形式展示出来

HTML(animator.to_jshtml())
#如果要保存html,用一下代码

'''with open("2018-2021年江苏省13市GDP排名.html", "w") as f:
    print(animator.to_jshtml(), file=f)'''

以下使用HTML(animator.to_jshtml())跑出来的数据,下面的按钮点击就可以实现动态变化。

MPAndroidChart多条动态曲线_开发语言_07

 7.制作gif图

1.根据网上代码制作

animator.save('test.gif',writer='imagemagick')

虽然已gif格式出来了,但是图片出现了重叠的现象。对于一张图数据变化简单,这个方法并不能满足我们的需求

MPAndroidChart多条动态曲线_数据分析_08

 2.利用图片生成gif

通过观察发现如果想实现理想状态,需要对每一张图前再加一张空白的页面。就可以实现目标,会的可以在评论区说一说。我根据第4步画条形图的函数中,将每张图片保存。

plt.savefig('{}.jpg'.format(current_year))保存图片,用在gif图

 接下来循环,获取2018~2021年江苏省人均GDP的图片

for i in range(2018,2022):
    fig, ax = plt.subplots(figsize=(15, 8))
    draw_barchart(i)

获取图片将他们放在 一个合适的文件夹中,接下来就是图片变成gif

#系统操作库

import os

# 图片处理库

from PIL import Image
# 初始化图片地址文件夹途径
 
image_path = 'image/'

# 获取文件列表

files = os.listdir(image_path)

# 定义第一个文件的全局路径

file_first_path = os.path.join(image_path, files[0])

# 获取Image对象

img = Image.open(file_first_path)

# 初始化文件对象数组

images = []

for image in files[1:]:

    # 获取当前图片全量路径

    img_path = os.path.join(image_path, image)

    # 将当前图片使用Image对象打开、然后加入到images数组

    images.append(Image.open(img_path))

# 保存并生成gif动图

img.save('2018-2021年江苏省13市GDP排名.gif', save_all=True, append_images=images, loop=0, duration=700)

这样就可以完美生成gif了 ,恭喜啊

MPAndroidChart多条动态曲线_ci_09

 4.总代码(gif的制作)

1.图片的制作                                                                                       有第二部分代码哦

import random
import matplotlib
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import random
import matplotlib.animation as animation
from IPython.core.display import HTML
import gif

df = pd.read_excel('江苏省2018~2021年人均gdp对比图.xlsx')
city_list = list(set(df.city))
def randomcolor():
    colorlist = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    color =''
    for i in range(6):
        color += random.choice(colorlist)
    return '#'+ color


# 构造一个name_color字典
city_color = {}
for city in city_list:
    city_color[city] = randomcolor()


#定义一个画条形图的函数:
def draw_barchart(current_year):
    dff = df[df['year'].eq(current_year)].sort_values(by='人均GDP',ascending = True)

    ax.clear()
    ax.barh(dff['city'],dff['人均GDP'],color = [city_color[x] for x in dff['city']]) #ax.bar是一般的条形图,barh是水平的条形图,h是horizontal的意思
    dx = dff['人均GDP'].max()/200
    for i ,(value,name) in enumerate(zip(dff['人均GDP'], dff['city'])):
            ax.text(value+dx,i ,f'{value:,.0f}',size = 14,ha = 'left',va ='center')
    ax.text(1,0.4,current_year,transform = ax.transAxes,color ='#777777',size = 16,ha ='right',weight=800) 
    ax.text(0,1.06,'人',transform = ax.transAxes,size=12,color='#777777')

        #set_major_formatter表示刻度尺格式;
    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([]) #set_yticks([])表示不显示y轴的取值
        #margins表示自动缩放余额;
    ax.margins(0,0.01)
        # 设置后面的网格
    ax.grid(which='major',axis='x',linestyle='-')
        #刻度线和网格线是在图标上方还是下方,True为下方
    ax.set_axisbelow(True)
    ax.text(0,1.15,'2018-2021年江苏省13市GDP排名',
            transform=ax.transAxes,size=24,weight=600,ha='left',va='top')
    ax.text(1,0,'by 小yang',transform = ax.transAxes,color ='#777777',ha = 'right',
               bbox = dict(facecolor='white',alpha = 0.8,edgecolor='white'))
        #取消图表周围的方框显示
    plt.box(False)
    plt.savefig('{}.jpg'.format(current_year))
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] #设置汉字字体
fig, ax = plt.subplots(figsize=(15, 8))#设置画布大小
animator = animation.FuncAnimation(fig, draw_barchart, frames=range(2018, 2022),interval=700) #interval越大速度越慢 
#保存到jshtml
#HTML(animator.to_jshtml())
#HTML(animator.to_jshtml())
'''with open("2018-2021年江苏省13市GDP排名.html", "w") as f:
    print(animator.to_jshtml(), file=f)'''
animator.save('test.gif',writer='imagemagick') 
# windows需要安装imagemagick软件,并配置到系统路径中

for i in range(2018,2022):
    fig, ax = plt.subplots(figsize=(15, 8))
    draw_barchart(i)

2.将图片找到位置保存,然后生成gif

#系统操作库

import os

# 图片处理库

from PIL import Image
# 初始化图片地址文件夹途径
 
image_path = 'image/'

# 获取文件列表

files = os.listdir(image_path)

# 定义第一个文件的全局路径

file_first_path = os.path.join(image_path, files[0])

# 获取Image对象

img = Image.open(file_first_path)

# 初始化文件对象数组

images = []

for image in files[1:]:

    # 获取当前图片全量路径

    img_path = os.path.join(image_path, image)

    # 将当前图片使用Image对象打开、然后加入到images数组

    images.append(Image.open(img_path))

# 保存并生成gif动图

img.save('2018-2021年江苏省13市GDP排名.gif', save_all=True, append_images=images, loop=0, duration=700)