数据可视化-疫情数据条形动态图

年初至今,新冠疫情给人们的正常生活带来了不小的改变,随着国内疫情形式逐渐好转,也再一次让我们看到了国家的伟大!向在此次抗击疫情中勇敢奉献的所有英雄致敬!

武大学生用python做出了樱花绽放,我在这里想记录一下从1.20-3.28国内疫情数据的变化。

数据准备

数据我是从丁香医生网站(感谢!)上获取的,丁香医生网站上的数据有几个优势:

  1. json格式;
  2. 各省的数据可以单独获取(不过现在没那么方便了,网页版查看各省数据详情会直接跳到下载丁香医生APP的广告页上,解决的方法是从主界面上获取数据,不过需要自己去判断哪个编号对应的是哪个省);
  3. 数据是从1月到现在的,这一点要好于其它网站,其他网站一般都是本天内的数据

获取到各省、直辖市、自治区、特别行政区的json数据后,我打算将其存至数据库中,数据库结构如下:
1
这里要用到pymysql这个库,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import json
import pymysql
# 数据可视化
# 建立数据库连接
db=pymysql.connect(
host="***",# 改为自己的数据库所在主机
user="***",# 改为自己的数据库用户名
password="***",# 改为自己的数据库密码
database="***")# 改为自己的数据库名称
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
filePath='***' # 改为自己的json数据所在文件夹
#省份对应字典
provinceDic={}
pIdF=open("***")# 为方便操作为各省附上了一个代码,这里改为自己的代码文件的位置
codeLine=pIdF.readline()
while codeLine:
codeLine=codeLine.strip('\n')
codeLineArray=codeLine.split( )
provinceDic[int(codeLineArray[0])]=codeLineArray[1]
codeLine=pIdF.readline()
pIdF.close()
# print(provinceDic)
insertValue=[]
dataCount=1
for i in range(1,35):
fP=filePath+str(i)+'.json'
f=open(fP,encoding='utf-8')
dic=json.load(f)
dataSize=len(dic['data'])
#print(dataSize)
#print(dic['data'][0]['confirmedCount'])
for j in range(0,dataSize):
tupleData = ()
tupleData += (
dataCount,i, dic['data'][j]['confirmedCount'], dic['data'][j]['confirmedIncr'],
dic['data'][j]['curedCount'],
dic['data'][j]['curedIncr'], dic['data'][j]['currentConfirmedCount'],
dic['data'][j]['currentConfirmedIncr'],
dic['data'][j]['dateId'], dic['data'][j]['deadCount'], dic['data'][j]['deadIncr'],
dic['data'][j]['suspectedCount'], dic['data'][j]['suspectedCountIncr'],provinceDic[i])
insertValue.append(tupleData)
dataCount+=1
# 构造插入的sql语句
print(insertValue)
sql = "INSERT INTO CHINAPROVINCEDATA (id,provinceId,confirmedCount,confirmedIncr,curedCount,curedIncr,currentConfirmedCount,currentConfirmedIncr,dateId,deadCount,deadIncr,suspectedCount,suspectedCountIncr,provinceName) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
try:
cursor.executemany(sql,insertValue)
db.commit()
except:
print("Error!")
db.rollback()
# 关闭数据库连接
db.close()

然后利用navciat导出为csv文件
如下图所示:
2

开始绘图

数据准备好后,就可以开始绘制动态条形图了
参考博客为:40行python制作超酷炫动态排序图
绘制条形图,要为各省、直辖市、自治区和特别行政区用不同的条形进行代表,不同的条形应该具有不同的颜色,这里根据十六进制颜色表示的特征,随机构造34种颜色,并于各省、直辖市、自治区和特别行政区相对应,并写入文件,以供绘图时读取,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import random
provinceList=['北京','上海','天津','重庆','香港','澳门','台湾','安徽','福建','甘肃','广东','广西','贵州','海南','河北','河南','黑龙江','湖北','湖南','吉林','江苏','江西','辽宁','内蒙古','宁夏','青海','山东','山西','陕西','四川','西藏','新疆','云南','浙江']
hexArray=['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
def randomColor():
file=open("***",'w')# ***改为自己要存取的文件路径
for i in range(0,34):
color=""
for j in range(0,6):
color+=hexArray[random.randint(0,14)]
color=provinceList[i]+" "+"#"+color
file.writelines(color)
file.write('\n')
print(color)
randomColor()

下面开始绘图,参考文章有些部分已经不太适合现在的库版本了,所以也是调了一些地方,代码如下(解释包含其中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from IPython.display import HTML
dateArray=[20200120,20200121,20200122,20200123,20200124,20200125,20200126,20200127,20200128,20200129
,20200130,20200131,20200201,20200202,20200203,20200204,20200205,20200206,20200207,20200208,20200209
,20200210,20200211,20200212,20200213,20200214,20200215,20200216,20200217,20200218,20200219,20200220
,20200221,20200222,20200223,20200224,20200225,20200226,20200227,20200228,20200229,20200301,20200302,
20200303,20200304,20200305,20200306,20200307,20200308,20200309,20200310,20200311,20200312,20200313
,20200314,20200315,20200316,20200317,20200318,20200319,20200320,20200321,20200322,20200323,20200324
,20200325,20200326,20200327,20200328
] # 存取时间区段,因为时间按这种格式并不是连续的,所以要存取下来
df=pd.read_csv('***',usecols=['provinceId','confirmedCount','dateId','provinceName']) # ***改为自己的疫情数据csv文件路径,在这里我们选用四项数据
plt.rcParams['font.sans-serif']=['SimHei'] # 用来正常显示中文标签,否则会出现中文乱码现象
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
fig,ax=plt.subplots(figsize=(15,8))
current_date=20200225
colorDict={}# 记录省份与颜色的对应关系
colorFile=open("***")# ***改为自己的省份颜色对照文件路径
colorLine=colorFile.readline()
while colorLine:
colorLine=colorLine.strip('\n')
colorLineArray=colorLine.split( )
colorDict[colorLineArray[0]]=colorLineArray[1]
colorLine=colorFile.readline()
colorFile.close()
def drawData(date):
dff = (df[df['dateId'] == date].sort_values(by='confirmedCount', ascending=True))# 按累计确诊人数升序排序,如果不想全部显示的话,可以改为df[].tail(20)
ax.clear()
ax.barh(dff['provinceName'], dff['confirmedCount'],color=[colorDict[c] for c in dff['provinceName']], align='center')
dx=dff['confirmedCount'].max()/200
for i,(confirmedCount,provinceName) in enumerate(zip(dff['confirmedCount'],dff['provinceName'])):
ax.text(confirmedCount-dx,i,provinceName,size=10,weight=600,ha='right',va='bottom')# 左侧显示省、直辖市、自治区和特别行政区的名称
ax.text(confirmedCount+dx,i,f'{confirmedCount:,.0f}',size=10,ha='left',va='center')# 右侧显示确诊人数
ax.text(1,0.4,date,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.set_yticks([])#取消y坐标轴
ax.margins(0,0.01)
ax.grid(which='major',axis='x',linestyle='-')
ax.set_axisbelow(True)
ax.text(0,1.12,'中国各地新冠肺炎确诊人数变化(01.20-03.28)',transform=ax.transAxes,size=18,weight=600,ha='left')
plt.box(False)
#plt.show()
drawData(current_date)
animator=animation.FuncAnimation(fig,drawData,frames=dateArray[0:],interval=800)# interval为每帧时间间隔,以ms为单位
HTML(animator.to_jshtml())
#plt.show()
animator.save("***")# ***改为自己要存取的gif文件的路径

效果如下(加载比较慢):
3