超火动态排序疫情变化图,这次我们用 Plotly来绘制
超火动态排序疫情变化图,
这次我们用 Plotly来绘制
数据来源
准备工作
Mac 系统
Anaconda(Python 3.7)
Jupyter Notebook
import akshare as ak
import pandas as pd
import plotly
import plotly.graph_objs as go
from plotly.offline import iplot, init_notebook_mode,plot
import plotly.express as px
from datetime import datetime
# 在PyCharm、VS Code等IDE中运行时,
# 需要注释下面这行代码
init_notebook_mode()
print(f'pandas version: {pd.__version__}')
print(f'akshare version: {ak.__version__}')
print(f'plotly version: {plotly.__version__}')
# pandas version: 1.0.1
# akshare version: 0.4.27
# plotly version: 4.5.0
# 从 akshare 获取数据
# df_all_history = ak.epidemic_history()
# 从csv文件获取数据,这个数据文件的数据截止到3月10日
df_all_history = pd.read_csv('epidemic_all_20200316.csv',index_col=0)
df_all_history
['date']
),一列是字符串格式的日期 ( ['dates']
)。这样设置的原因,是因为我们后续分别需要用到这两种格式的日期。# 将数据复制一份
df_all = df_all_history
# 将字符串格式的日期转换为 日期格式
df_all['date'] = pd.to_datetime(df_all['date'])
# 将时间格式转为字符串格式的日期,以 YYYY-mm-dd 的形式保存
df_all['dates'] = df_all['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
# 添加现存确诊列
df_all['current'] = df_all['confirmed'] - df_all['cured'] - df_all['dead']
print(df_all.info())
# df_all
全球概况
# 国内总计数量
df_china_total = df_all.query("country=='中国' and province==''")
df_china_total = df_china_total.sort_values('date',ascending=False)
# df_china_total
# ---------
# 国外,按国家统计
df_oversea = df_all.query("country!='中国'")
df_oversea.fillna(value="", inplace=True)
# df_oversea
# ---------
# 全球统计
df_global = df_china_total.append(df_oversea)
# df_global
# 全球最近的概况
# 按日期进行排序
df_global_date = df_global.sort_values('date',ascending=False)
# 获取最新的日期
latest_day = df_global_date['dates'].values[0]
# query 函数中,变量需要加 @ ,
df_global_latest = df_global_date.query('dates==@latest_day')
# 按累计确诊数量排序
df_global_latest = df_global_latest.sort_values('confirmed',ascending=False)
df_global_latest
海外疫情情况
# 现有数据演示从 2020年2月10日开始
df_oversea_recent = df_oversea.set_index('date')
df_oversea_recent = df_oversea_recent['2020-02-10':]
# df_oversea_recent
epidemic_buchong.xlsx
这个文件里。# 由于部分国家,数据不是从2020年2月10日开始的,所以要补充数据,数值为 0
# 数据在 excel 表格中进行补充,这里进行读取
df_oversea_buchong = pd.read_excel('epidemic_buchong.xlsx')
df_oversea_buchong['dates'] = df_oversea_buchong['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
df_oversea_buchong.set_index('date', inplace=True)
df_oversea_buchong.fillna(value="", inplace=True)
print(df_oversea_buchong.info())
# df_oversea_buchong
# 合并补充数据
df_oversea_recent_new = df_oversea_recent.append(df_oversea_buchong)
df_oversea_recent_new.sort_index(inplace=True)
# df_oversea_recent_new
动态排名的柱状图
# 准备国家列表和 国家的颜色列表
countries = list(df_oversea_recent_new['country'].unique())
countries_count = len(countries) # 国家数量
# 为每一个国家定义颜色
color_1 = [px.colors.qualitative.Alphabet[i] for i in range(26)]
color_2 = [px.colors.qualitative.Light24[i] for i in range(24)]
color_3 = [px.colors.qualitative.Dark24[i] for i in range(24)]
color_list = (color_1 + color_2 + color_3)*3 # 颜色数量,比国家数量大
color_list = color_list[:countries_count] # 颜色数量跟国家数量一致
print(f'国家数量:{countries_count}')
print(f'国家颜色数量:{len(color_list)}')
# 海外单个国家死亡人数的最高值
max_dead = df_oversea_recent_new['dead'].max()
# 海外单个国家累计确诊人数的最高值
max_confirmed = df_oversea_recent_new['confirmed'].max()
print(f'海外单个国家累计确诊人数的最高值为{max_confirmed}')
print(f'海外单个国家死亡人数的最高值为{max_dead}')
df = df_oversea_recent_new
# df 添加颜色列,每个国家给定一种颜色
for country,color in zip(countries, color_list):
df.loc[df['country']==country, 'color'] = color
# 保存数据到 csv文件
# df.to_csv(f'epidemic_all_{today}_update.csv')
# df
动态排名可视化
nlargest
功能来实现的。key:value
的形式保存每天的 疫情数据,其中疫情数据是以 DataFrame 的形式保存于 value 中。dates_list = list(df['dates'].unique())
dict_keys = [str(i) for i in range(len(dates_list))]
n_frame={}
for date, d in zip(dates_list, dict_keys):
dataframe=df[df['dates']==date]
# 排名前20的国家
dataframe=dataframe.nlargest(n=20,columns=['confirmed'])
dataframe=dataframe.sort_values(by=['dates','confirmed'])
n_frame[d]=dataframe
# print (n_frame)
#-------------------------------------------
fig = go.Figure(
data=[
go.Bar(
x=n_frame['0']['confirmed'], y=n_frame['0']['country'],orientation='h',
text=n_frame['0']['confirmed'], texttemplate='%{text:.3s}',
textfont={'size':12}, textposition='inside', insidetextanchor='middle',
width=0.9, marker={'color':n_frame['0']['color']})
],
layout=go.Layout(
xaxis=dict(range=[0, max_confirmed*1.1], autorange=False, title=dict(text='confirmed',
font=dict(size=12))),
yaxis=dict(range=[-0.5, 20.5], autorange=False,tickfont=dict(size=14)),
title=dict(text='Confirmed numbers per Country: 2020-02-10',font=dict(size=28),x=0.5,xanchor='center'),
# 添加按钮
updatemenus=[dict(
type="buttons",
buttons=[dict(label="Play",
method="animate",
# https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
args=[None,
{"frame": {"duration": 1000, "redraw": True},
"transition": {"duration":250,
"easing": "linear"}}]
)]
)]
),
frames=[
go.Frame(
data=[
go.Bar(x=value['confirmed'], y=value['country'],
orientation='h',text=value['confirmed'],
marker={'color':value['color']})
],
layout=go.Layout(
xaxis=dict(range=[0, max_confirmed*1.1], autorange=False),
yaxis=dict(range=[-0.5, 20.5], autorange=False,tickfont=dict(size=10)),
title=dict(text='Confirmed numbers per Country: '+str(value['dates'].values[0]),
font=dict(size=28))
)
)
for key, value in n_frame.items()
]
)
#-------------------------------------------
fig.show()
go.Frame
中的数据进行更新来实现的。上面的 duration
可以来控制按钮点击后变化的速度。在文末,Lemonbit 给大家提供了本文完整的PDF版内容(含代码)以及数据文件。
x轴
固定不动时,动态化演示的效果不是太理想,我们希望 x轴
上的数据也能动态变化,这样效果会更理想。要使 x轴
上的数据也能动态变化,实现文章开始图中的效果,核心是定义 x轴
的范围时,实现动态变化, x轴
的核心代码如下:
可试读77%