己亥末,庚子春,荆楚大疫,染者数万计。众惶恐,举国防,皆闭户。街无舟车,巷无人烟,时天下震动。然九州一心,青丝白发皆身先士卒,布衣商客皆争相解囊,政医兵者扛鼎逆行为之勇战矣,能者皆竭力之。月余,疫尽去,国泰民安。
在这里先向全国抗疫的国内外各行各业的人士致敬!
然后说题目项目
pyecharts 是一个用于生成 Echarts 图表的类库。
Echarts 是百度开源的一个数据可视化 JS 库,主要用于数据可视化。pyecharts 是一个用于生成 Echarts 图表的类库。实际上就是 Echarts 与 Python 的对接。
详情请看官方文档:https://pyecharts.org/#/zh-cn/intro
话不多说先上效果图:
接下来从头说:
1.数据抓取:
数据源:腾讯疫情实时追踪
首先对该网站F12,点击Network刷新页面,看看每个页面的Response:
找到了,是这个:https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=jQuery34102867663505226432_1581423137066&_=1581423137067
但是在刷新一下会发现callback后面的东西就变了,推测这是一个时间戳,把它去了用https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5试试:
嗯,也可以,就它了,这就是数据源。
先引入所需模块:
import json
import requests
import pandas as pd
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType, ChartType
from bs4 import BeautifulSoup
接下来抓取数据:
reponse = requests.get('https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5').json()
data = json.loads(reponse['data'])
'''
print(data.keys())
dict_keys(['lastUpdateTime', 'chinaTotal', 'chinaAdd', 'isShowAdd', 'chinaDayList', 'chinaDayAddList', 'dailyNewAddHistory', 'dailyDeadRateHistory', 'confirmAddRank', 'areaTree', 'articleList'])
判断大概就是截至时间,新增人数,死亡率治愈率等等,就是我们所需的
'''
数据处理:
# 国内
lastUpdateTime = data['lastUpdateTime']
'''
由于后面可视化要用到,但这字典的key都是英文,
为了方便观看,我就将其转化为中文了
'''
chinaTotal = data['chinaTotal']
chinaTotal['确诊'] = chinaTotal['confirm']
chinaTotal['疑似'] = chinaTotal['suspect']
chinaTotal['死亡'] = chinaTotal['dead']
chinaTotal['治愈'] = chinaTotal['heal']
del chinaTotal['confirm']
del chinaTotal['suspect']
del chinaTotal['dead']
del chinaTotal['heal']
sum = chinaTotal['确诊'] + chinaTotal['疑似'] + chinaTotal['死亡'] + chinaTotal['治愈']
'''
本来chinaAdd是用来统计新增人数的,但是不知道哪里出了点问题,新增疑似(suspect)是负的...
(网页上就是这样显示的,咱也不知道,(咱jio的是TX的问题)但咱也不敢问,
所以就用chinaDayAddList(每日新增数据列表)里的最后一项来代替了...
'''
chinaAdd = data['chinaAdd']
chinaAdd['新增确诊'] = data['chinaDayAddList'][-1]['confirm']
chinaAdd['新增疑似'] = data['chinaDayAddList'][-1]['suspect']
chinaAdd['新增死亡'] = data['chinaDayAddList'][-1]['dead']
chinaAdd['新增治愈'] = data['chinaDayAddList'][-1]['heal']
del chinaAdd['confirm']
del chinaAdd['suspect']
del chinaAdd['dead']
del chinaAdd['heal']
areaTree = data['areaTree']
china_data = areaTree[0]['children']
china_list = []
for x in range(len(china_data)):
province = china_data[x]['name']
province_list = china_data[x]['children']
for y in range(len(province_list)):
city = province_list[y]['name']
total = province_list[y]['total']
today = province_list[y]['today']
china_dict = {'province': province, 'city': city, 'total': total, 'today': today}
china_list.append(china_dict)
# 定义数据处理函数
def confirm(x):
confirm = eval(str(x))['confirm']
return confirm
def suspect(x):
suspect = eval(str(x))['suspect']
return suspect
def dead(x):
dead = eval(str(x))['dead']
return dead
def heal(x):
heal = eval(str(x))['heal']
return heal
china_data = pd.DataFrame(china_list)
china_data.head()
# 函数映射
china_data['confirm'] = china_data['total'].map(confirm)
china_data['suspect'] = china_data['total'].map(suspect)
china_data['dead'] = china_data['total'].map(dead)
china_data['heal'] = china_data['total'].map(heal)
china_data['addconfirm'] = china_data['today'].map(confirm)
china_data['addsuspect'] = china_data['today'].map(suspect)
china_data['adddead'] = china_data['today'].map(dead)
china_data['addheal'] = china_data['today'].map(heal)
china_data = china_data[
["province", "city", "confirm", "suspect", "dead", "heal", "addconfirm", "addsuspect", "adddead", "addheal"]]
china_data.head()
# 国际数据处理
global_data = pd.DataFrame(data['areaTree'])
global_data['confirm'] = global_data['total'].map(confirm)
global_data['suspect'] = global_data['total'].map(suspect)
global_data['dead'] = global_data['total'].map(dead)
global_data['heal'] = global_data['total'].map(heal)
global_data['addconfirm'] = global_data['today'].map(confirm)
global_data['addsuspect'] = global_data['today'].map(suspect)
global_data['adddead'] = global_data['today'].map(dead)
global_data['addheal'] = global_data['today'].map(heal)
world_name = pd.read_excel("世界各国中英文对照.xlsx")
global_data = pd.merge(global_data, world_name, left_on="name", right_on="中文", how="inner")
global_data = global_data[
["name", "英文", "confirm", "suspect", "dead", "heal", "addconfirm", "addsuspect", "adddead", "addheal"]]
global_data.head()
# 日数据处理
chinaDayList = pd.DataFrame(data['chinaDayList'])
chinaDayList = chinaDayList[['date', 'confirm', 'suspect', 'dead', 'heal']]
chinaDayList.head()
# 日新增数据处理
chinaDayAddList = pd.DataFrame(data['chinaDayAddList'])
chinaDayAddList = chinaDayAddList[['date', 'confirm', 'suspect', 'dead', 'heal']]
chinaDayAddList.head()
数据可视化:
# 左上角饼图
total_pie = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='500px', height='350px', bg_color="transparent"))
.add("", [list(z) for z in zip(['确 诊 ', '疑 似 ', '死 亡 ', '治 愈 '], chinaTotal.values())],
center=["50%", "60%"], radius=[75, 100], )
.add("", [list(z) for z in zip(chinaAdd.keys(), chinaAdd.values())], center=["50%", "60%"], radius=[0, 50])
.set_global_opts(title_opts=opts.TitleOpts(title="全国总量", pos_bottom=0,
title_textstyle_opts=opts.TextStyleOpts(color="#00FFFF")),
legend_opts=opts.LegendOpts(textstyle_opts=opts.TextStyleOpts(color="#FFFFFF")))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{c}")))
# 中间全球疫情地图
world_map = (
Map(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS))
.add("", [list(z) for z in zip(list(global_data["英文"]), list(global_data["confirm"]))], "world",
is_map_symbol_show=False)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False),
toolbox_opts=opts.ToolboxOpts(orient='vertical', pos_right="10%"))
.set_global_opts(visualmap_opts=opts.VisualMapOpts(is_piecewise=True, background_color="transparent",
textstyle_opts=opts.TextStyleOpts(color="#F5FFFA"),
pieces=[
{"min": 101, "label": '>100', "color": "#893448"},
{"min": 10, "max": 100, "label": '10-100',
"color": "#fb8146"},
{"min": 1, "max": 9, "label": '1-9',
"color": "#fff2d1"},
])))
# 右下角中国疫情地图绘制
area_data = china_data.groupby("province")["confirm"].sum().reset_index()
area_data.columns = ["province", "confirm"]
area_map = (
Map(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS))
.add("", [list(z) for z in zip(list(area_data["province"]), list(area_data["confirm"]))], "china",
is_map_symbol_show=False, label_opts=opts.LabelOpts(color="#fff"),
tooltip_opts=opts.TooltipOpts(is_show=True), zoom=1.2, center=[105, 30])
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(title_opts=opts.TitleOpts(title="中国疫情分布图", pos_top='5%',
title_textstyle_opts=opts.TextStyleOpts(color="#FF0000")),
visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pos_right=0, pos_bottom=0,
textstyle_opts=opts.TextStyleOpts(color="#F5FFFA"),
pieces=[
{"min": 1001, "label": '>1000', "color": "#893448"},
{"min": 500, "max": 1000, "label": '500-1000',
"color": "#ff585e"},
{"min": 101, "max": 499, "label": '101-499',
"color": "#fb8146"},
{"min": 10, "max": 100, "label": '10-100',
"color": "#ffb248"},
{"min": 0, "max": 9, "label": '0-9',
"color": "#fff2d1"}])))
# 左下角热图及城市分布
city_data = china_data.groupby('city')['confirm'].sum().reset_index()
city_data.columns = ["city", "confirm"]
'''
由于某些名字地图上无法定位,比如“外地来京”、
“外地来津”、“外地来沪”等,这种会报错,
所以要先清洗数据
'''
def is_city(item):
'''
判断一个城市能否在Geo地图上被找到
:param item: 城市名
:return: T/F
'''
lists_1 = []
lists_1.append(item)
lists_2 = [10]
geo = Geo()
geo.add_schema(maptype="china")
try:
geo.add("确诊城市", [list(z) for z in zip(lists_1, lists_2)])
return True
except TypeError as e:
return False
city_index = []
i = 0
for item in city_data['city']:
if is_city(item) == False:
city_index.append(i)
i += 1
for x in city_index:
del (city_data['city'][x])
del (city_data['confirm'][x])
city_index_ = []
i = 0
for item in city_data['confirm']:
if item > 1000:
city_index_.append(i)
i += 1
serious_city = [] # 严重城市
serious_submit = [] # 严重人数
for y in city_index_:
serious_city.append(list(city_data['city'])[y])
serious_submit.append(list(city_data['confirm'])[y])
# 找不到拉萨,所以我自己添加上去了
list_1 = ["拉萨"]
list_2 = [1]
area_heat_geo = (
Geo(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS, bg_color='transparent'))
.add_schema(maptype="china", zoom=1.2, center=[105, 30])
.add("确诊城市", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))], symbol_size=10)
.add("确诊城市", [list(z) for z in zip(list_1, list_2)], symbol_size=10) # 孤独拉萨
.add("确诊城市", [list(z) for z in zip(list(serious_city), list(serious_submit))], # 感染者超1000的城市
type_=ChartType.EFFECT_SCATTER, effect_opts=opts.EffectOpts(is_show=True, color="black",
symbol_size=30, scale=4, period=1))
.add("", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))],
type_=ChartType.HEATMAP)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(range_size=[0, 25, 50, 75, 100], max_=1000, orient='horizontal',
pos_bottom=0),
title_opts=opts.TitleOpts(title="中国疫情分布热图", pos_top='5%'),
legend_opts=opts.LegendOpts(pos_bottom='10%', pos_left=0)))
# 中间线型图和柱状图结合
line = (
Line(init_opts=opts.InitOpts(theme=ThemeType.CHALK, bg_color="transparent"))
.add_xaxis(list(chinaDayList["date"]))
.add_yaxis("累计确诊 ", list(chinaDayList["confirm"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计疑似 ", list(chinaDayList["suspect"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计死亡 ", list(chinaDayList["dead"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计治愈", list(chinaDayList["heal"]), is_smooth=True, yaxis_index=1)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_left='center')))
bar = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK, bg_color="transparent"))
.add_xaxis(list(chinaDayAddList["date"]))
.add_yaxis("单日确诊 ", list(chinaDayAddList["confirm"]))
.add_yaxis("单日疑似 ", list(chinaDayAddList["suspect"]))
.add_yaxis("单日死亡 ", list(chinaDayAddList["dead"]))
.add_yaxis("单日治愈", list(chinaDayAddList["heal"]))
.extend_axis(yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}")))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_left='center'),
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}")),
datazoom_opts=opts.DataZoomOpts())).overlap(line)
# 中间大标题
big_title = (
Pie()
.set_global_opts(
title_opts=opts.TitleOpts(title="2019-nCov",
title_textstyle_opts=opts.TextStyleOpts(font_size=40, color='#FFFFFF',
border_radius=True, border_color="white"),
pos_top=0)))
# 截至时间
times = (
Pie()
.set_global_opts(
title_opts=opts.TitleOpts(subtitle=("截至 " + lastUpdateTime),
subtitle_textstyle_opts=opts.TextStyleOpts(font_size=13, color='#FFFFFF'),
pos_top=0))
)
# 右上角那一堆
# (本来想用Grid排版,但是始终达不到自己想要的效果,就用笨办法啦)
confirms = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="确诊", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
confirms_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['确诊']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增: " + str(chinaAdd['新增确诊'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#00FFFF",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#00BFFF")
)))
suspects = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="疑似", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
suspects_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['疑似']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增疑似'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#FF00FF",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#EE82EE")
)))
deads = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="死亡", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
deads_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['死亡']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增死亡'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#FF0000",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#F08080")
)))
heals = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="治愈", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
heals_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['治愈']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增治愈'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#00FF00",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#98FB98")
)))
confirm_liquid = (
Liquid()
.add("确诊比例", [chinaTotal['确诊'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#00FFFF",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
suspect_liquid = (
Liquid()
.add("疑似比例", [chinaTotal['疑似'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#FF00FF",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
dead_liquid = (
Liquid()
.add("死亡比例", [chinaTotal['死亡'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#FF0000",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
heal_liquid = (
Liquid()
.add("治愈比例", [chinaTotal['治愈'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#00FF00",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
wc = (
WordCloud()
.add("", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))],
word_gap=0, word_size_range=[10, 30]))
用Page()将上面的一堆添加到一个页面:
'''
方法一:
先用注释掉的两行,打开页面
拖动各个模块到你想要的位置
然后点击左上方的save config保存配置文件
(./chart_config.json)
然后再用另外两行生成你想要的页面
'''
# page = (Page(page_title="2019-nCov",layout=Page.DraggablePageLayout)
page = (Page(page_title="2019-nCov")
.add(world_map)
.add(total_pie)
.add(area_map)
.add(area_heat_geo)
.add(bar)
.add(big_title)
.add(times)
.add(confirms)
.add(confirms_people)
.add(suspects)
.add(suspects_people)
.add(deads)
.add(deads_people)
.add(heals)
.add(heals_people)
.add(confirm_liquid)
.add(suspect_liquid)
.add(dead_liquid)
.add(heal_liquid)
.add(wc)
# ).render("render.html")
).save_resize_html("render.html", cfg_file="chart_config.json", dest="2019-nCoV 数据一览.html")
但是这种方法我试了,不行,(但是官方文档里介绍了这种方法:http://pyecharts.org/#/zh-cn/composite_charts?id=page%ef%bc%9a%e9%a1%ba%e5%ba%8f%e5%a4%9a%e5%9b%be)你们可以试试…所以我用的是下面这种方法:
'''
方法二:
直接修改.html文件
'''
with open("2019-nCov 数据一览.html", "r+", encoding='utf-8') as html:
html_bf = BeautifulSoup(html, 'lxml')
divs = html_bf.select('.chart-container')
divs[0][
"style"] = "width:605px;height:274px;position:absolute;top:36px;left:333px;border-style:solid;border-color:#444444;border-width:0px;"
divs[1][
'style'] = "width:411px;height:303px;position:absolute;top:5px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
divs[2][
"style"] = "width:309px;height:405px;position:absolute;top:313px;left:961px;border-style:solid;border-color:#444444;border-width:0px;"
divs[3][
"style"] = "width:305px;height:405px;position:absolute;top:310px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
divs[4][
"style"] = "width:646px;height:304px;position:absolute;top:312px;left:312px;border-style:solid;border-color:#444444;border-width:0px;"
divs[5][
"style"] = "width:250px;height:55px;position:absolute;top:2px;left:440px;border-style:solid;border-color:#444444;border-width:0px;"
divs[6][
"style"] = "width:200px;height:30px;position:absolute;top:11px;left:675px;border-style:solid;border-color:#444444;border-width:0px;"
divs[7][
'style'] = "width:60px;height:75px;position:absolute;top:5px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;border-radius:25px 0px 0px 0px"
divs[8][
"style"] = "width:130px;height:75px;position:absolute;top:5px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[9][
"style"] = "width:60px;height:75px;position:absolute;top:80px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[10][
"style"] = "width:130px;height:75px;position:absolute;top:80px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[11][
"style"] = "width:60px;height:75px;position:absolute;top:155px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[12][
"style"] = "width:130px;height:75px;position:absolute;top:155px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[13][
"style"] = "width:60px;height:75px;position:absolute;top:230px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[14][
"style"] = "width:130px;height:75px;position:absolute;top:230px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;border-radius:0px 0px 25px 0px"
divs[15][
"style"] = "width:160px;height:160px;position:absolute;top:-35px;left:920px;border-style:solid;border-color:#444444;border-width:0px;"
divs[16][
"style"] = "width:160px;height:160px;position:absolute;top:40px;left:865px;border-style:solid;border-color:#444444;border-width:0px;"
divs[17][
"style"] = "width:160px;height:160px;position:absolute;top:115px;left:920px;border-style:solid;border-color:#444444;border-width:0px;"
divs[18][
"style"] = "width:160px;height:160px;position:absolute;top:188px;left:865px;border-style:solid;border-color:#444444;border-width:0px;"
divs[19][
"style"] = "width:1280px;height:120px;position:absolute;top:600px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
body = html_bf.find("body")
body["style"] = "background-color:#333333;"
html_new = str(html_bf)
html.seek(0, 0)
html.truncate()
html.write(html_new)
html.close()
注意,这里的div标签排序方式与你上面page里的添加顺序一致,同时覆盖顺序也一致(最后添加的在最上层)。
然后在项目文件夹里选择 2019-nCov 数据一览.html 选择浏览器打开就好啦!
最后贴出完整代码(复制可用的那种):
(前提是下载世界各国中英文对照.xlsx并和该程序放在同一文件夹里)(链接在后面)
import json
import requests
import pandas as pd
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType, ChartType
from bs4 import BeautifulSoup
# 抓取数据
reponse = requests.get('https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5').json()
data = json.loads(reponse['data'])
# 国内
lastUpdateTime = data['lastUpdateTime']
chinaTotal = data['chinaTotal']
chinaTotal['确诊'] = chinaTotal['confirm']
chinaTotal['疑似'] = chinaTotal['suspect']
chinaTotal['死亡'] = chinaTotal['dead']
chinaTotal['治愈'] = chinaTotal['heal']
del chinaTotal['confirm']
del chinaTotal['suspect']
del chinaTotal['dead']
del chinaTotal['heal']
sum = chinaTotal['确诊'] + chinaTotal['疑似'] + chinaTotal['死亡'] + chinaTotal['治愈']
chinaAdd = data['chinaAdd']
chinaAdd['新增确诊'] = data['chinaDayAddList'][-1]['confirm']
chinaAdd['新增疑似'] = data['chinaDayAddList'][-1]['suspect']
chinaAdd['新增死亡'] = data['chinaDayAddList'][-1]['dead']
chinaAdd['新增治愈'] = data['chinaDayAddList'][-1]['heal']
del chinaAdd['confirm']
del chinaAdd['suspect']
del chinaAdd['dead']
del chinaAdd['heal']
areaTree = data['areaTree']
china_data = areaTree[0]['children']
china_list = []
for x in range(len(china_data)):
province = china_data[x]['name']
province_list = china_data[x]['children']
for y in range(len(province_list)):
city = province_list[y]['name']
total = province_list[y]['total']
today = province_list[y]['today']
china_dict = {'province': province, 'city': city, 'total': total, 'today': today}
china_list.append(china_dict)
# 定义数据处理函数
def confirm(x):
confirm = eval(str(x))['confirm']
return confirm
def suspect(x):
suspect = eval(str(x))['suspect']
return suspect
def dead(x):
dead = eval(str(x))['dead']
return dead
def heal(x):
heal = eval(str(x))['heal']
return heal
china_data = pd.DataFrame(china_list)
china_data.head()
# 函数映射
china_data['confirm'] = china_data['total'].map(confirm)
china_data['suspect'] = china_data['total'].map(suspect)
china_data['dead'] = china_data['total'].map(dead)
china_data['heal'] = china_data['total'].map(heal)
china_data['addconfirm'] = china_data['today'].map(confirm)
china_data['addsuspect'] = china_data['today'].map(suspect)
china_data['adddead'] = china_data['today'].map(dead)
china_data['addheal'] = china_data['today'].map(heal)
china_data = china_data[
["province", "city", "confirm", "suspect", "dead", "heal", "addconfirm", "addsuspect", "adddead", "addheal"]]
china_data.head()
# 国际数据处理
global_data = pd.DataFrame(data['areaTree'])
global_data['confirm'] = global_data['total'].map(confirm)
global_data['suspect'] = global_data['total'].map(suspect)
global_data['dead'] = global_data['total'].map(dead)
global_data['heal'] = global_data['total'].map(heal)
global_data['addconfirm'] = global_data['today'].map(confirm)
global_data['addsuspect'] = global_data['today'].map(suspect)
global_data['adddead'] = global_data['today'].map(dead)
global_data['addheal'] = global_data['today'].map(heal)
world_name = pd.read_excel("世界各国中英文对照.xlsx")
global_data = pd.merge(global_data, world_name, left_on="name", right_on="中文", how="inner")
global_data = global_data[
["name", "英文", "confirm", "suspect", "dead", "heal", "addconfirm", "addsuspect", "adddead", "addheal"]]
global_data.head()
# 日数据处理
chinaDayList = pd.DataFrame(data['chinaDayList'])
chinaDayList = chinaDayList[['date', 'confirm', 'suspect', 'dead', 'heal']]
chinaDayList.head()
# 日新增数据处理
chinaDayAddList = pd.DataFrame(data['chinaDayAddList'])
chinaDayAddList = chinaDayAddList[['date', 'confirm', 'suspect', 'dead', 'heal']]
chinaDayAddList.head()
# 数据可视化
# 饼图
total_pie = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='500px', height='350px', bg_color="transparent"))
.add("", [list(z) for z in zip(['确 诊 ', '疑 似 ', '死 亡 ', '治 愈 '], chinaTotal.values())],
center=["50%", "60%"], radius=[75, 100], )
.add("", [list(z) for z in zip(chinaAdd.keys(), chinaAdd.values())], center=["50%", "60%"], radius=[0, 50])
.set_global_opts(title_opts=opts.TitleOpts(title="全国总量", pos_bottom=0,
title_textstyle_opts=opts.TextStyleOpts(color="#00FFFF")),
legend_opts=opts.LegendOpts(textstyle_opts=opts.TextStyleOpts(color="#FFFFFF")))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{c}")))
# 全球疫情地图
world_map = (
Map(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS))
.add("", [list(z) for z in zip(list(global_data["英文"]), list(global_data["confirm"]))], "world",
is_map_symbol_show=False)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False),
toolbox_opts=opts.ToolboxOpts(orient='vertical', pos_right="10%"))
.set_global_opts(visualmap_opts=opts.VisualMapOpts(is_piecewise=True, background_color="transparent",
textstyle_opts=opts.TextStyleOpts(color="#F5FFFA"),
pieces=[
{"min": 101, "label": '>100', "color": "#893448"},
{"min": 10, "max": 100, "label": '10-100',
"color": "#fb8146"},
{"min": 1, "max": 9, "label": '1-9',
"color": "#fff2d1"},
])))
# 中国疫情地图绘制
# 数据处理
area_data = china_data.groupby("province")["confirm"].sum().reset_index()
area_data.columns = ["province", "confirm"]
area_map = (
Map(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS))
.add("", [list(z) for z in zip(list(area_data["province"]), list(area_data["confirm"]))], "china",
is_map_symbol_show=False, label_opts=opts.LabelOpts(color="#fff"),
tooltip_opts=opts.TooltipOpts(is_show=True), zoom=1.2, center=[105, 30])
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(title_opts=opts.TitleOpts(title="中国疫情分布图", pos_top='5%',
title_textstyle_opts=opts.TextStyleOpts(color="#FF0000")),
visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pos_right=0, pos_bottom=0,
textstyle_opts=opts.TextStyleOpts(color="#F5FFFA"),
pieces=[
{"min": 1001, "label": '>1000', "color": "#893448"},
{"min": 500, "max": 1000, "label": '500-1000',
"color": "#ff585e"},
{"min": 101, "max": 499, "label": '101-499',
"color": "#fb8146"},
{"min": 10, "max": 100, "label": '10-100',
"color": "#ffb248"},
{"min": 0, "max": 9, "label": '0-9',
"color": "#fff2d1"}])))
city_data = china_data.groupby('city')['confirm'].sum().reset_index()
city_data.columns = ["city", "confirm"]
def is_city(item):
'''
判断一个城市能否在Geo地图上被找到
:param item: 城市名
:return: T/F
'''
lists_1 = []
lists_1.append(item)
lists_2 = [10]
geo = Geo()
geo.add_schema(maptype="china")
try:
geo.add("确诊城市", [list(z) for z in zip(lists_1, lists_2)])
return True
except TypeError as e:
return False
city_index = []
i = 0
for item in city_data['city']:
if is_city(item) == False:
city_index.append(i)
i += 1
for x in city_index:
del (city_data['city'][x])
del (city_data['confirm'][x])
city_index_ = []
i = 0
for item in city_data['confirm']:
if item > 1000:
city_index_.append(i)
i += 1
serious_city = [] # 严重城市
serious_submit = [] # 严重人数
for y in city_index_:
serious_city.append(list(city_data['city'])[y])
serious_submit.append(list(city_data['confirm'])[y])
list_1 = ["拉萨"]
list_2 = [1]
area_heat_geo = (
Geo(init_opts=opts.InitOpts(theme=ThemeType.WESTEROS, bg_color='transparent'))
.add_schema(maptype="china", zoom=1.2, center=[105, 30])
.add("确诊城市", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))], symbol_size=10)
.add("确诊城市", [list(z) for z in zip(list_1, list_2)], symbol_size=10) # 孤独拉萨
.add("确诊城市", [list(z) for z in zip(list(serious_city), list(serious_submit))], # 感染者超1000的城市
type_=ChartType.EFFECT_SCATTER, effect_opts=opts.EffectOpts(is_show=True, color="black",
symbol_size=30, scale=4, period=1))
.add("", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))],
type_=ChartType.HEATMAP)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(range_size=[0, 25, 50, 75, 100], max_=1000, orient='horizontal',
pos_bottom=0),
title_opts=opts.TitleOpts(title="中国疫情分布热图", pos_top='5%'),
legend_opts=opts.LegendOpts(pos_bottom='10%', pos_left=0)))
# 每日数据趋势
line = (
Line(init_opts=opts.InitOpts(theme=ThemeType.CHALK, bg_color="transparent"))
.add_xaxis(list(chinaDayList["date"]))
.add_yaxis("累计确诊 ", list(chinaDayList["confirm"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计疑似 ", list(chinaDayList["suspect"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计死亡 ", list(chinaDayList["dead"]), is_smooth=True, yaxis_index=1)
.add_yaxis("累计治愈", list(chinaDayList["heal"]), is_smooth=True, yaxis_index=1)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_left='center')))
bar = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK, bg_color="transparent"))
.add_xaxis(list(chinaDayAddList["date"]))
.add_yaxis("单日确诊 ", list(chinaDayAddList["confirm"]))
.add_yaxis("单日疑似 ", list(chinaDayAddList["suspect"]))
.add_yaxis("单日死亡 ", list(chinaDayAddList["dead"]))
.add_yaxis("单日治愈", list(chinaDayAddList["heal"]))
.extend_axis(yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}")))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_left='center'),
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}")),
datazoom_opts=opts.DataZoomOpts())).overlap(line)
big_title = (
Pie()
.set_global_opts(
title_opts=opts.TitleOpts(title="2019-nCov",
title_textstyle_opts=opts.TextStyleOpts(font_size=40, color='#FFFFFF',
border_radius=True, border_color="white"),
pos_top=0)))
times = (
Pie()
.set_global_opts(
title_opts=opts.TitleOpts(subtitle=("截至 " + lastUpdateTime),
subtitle_textstyle_opts=opts.TextStyleOpts(font_size=13, color='#FFFFFF'),
pos_top=0))
)
confirms = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="确诊", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
confirms_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['确诊']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增: " + str(chinaAdd['新增确诊'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#00FFFF",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#00BFFF")
)))
suspects = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="疑似", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
suspects_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['疑似']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增疑似'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#FF00FF",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#EE82EE")
)))
deads = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="死亡", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
deads_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['死亡']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增死亡'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#FF0000",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#F08080")
)))
heals = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title="治愈", pos_left='center', pos_top='center',
title_textstyle_opts=opts.TextStyleOpts(color='#FFFFFF'))))
heals_people = (Pie().
set_global_opts(title_opts=opts.TitleOpts(title=(str(chinaTotal['治愈']) + " "),
pos_top='15%', pos_left='center',
subtitle=(" 新增 :" + str(chinaAdd['新增治愈'])),
item_gap=1,
title_textstyle_opts=opts.TextStyleOpts(color="#00FF00",
font_size=30),
subtitle_textstyle_opts=opts.TextStyleOpts(color="#98FB98")
)))
confirm_liquid = (
Liquid()
.add("确诊比例", [chinaTotal['确诊'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#00FFFF",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
suspect_liquid = (
Liquid()
.add("疑似比例", [chinaTotal['疑似'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#FF00FF",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
dead_liquid = (
Liquid()
.add("死亡比例", [chinaTotal['死亡'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#FF0000",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
heal_liquid = (
Liquid()
.add("治愈比例", [chinaTotal['治愈'] / sum], tooltip_opts=opts.TooltipOpts(),
label_opts=opts.LabelOpts(color="#00FF00",
font_size=15,
formatter=JsCode(
"""function (param) {
return (Math.floor(param.value * 10000) / 100) + '%';
}"""
),
position="inside",
),
)
)
wc = (
WordCloud()
.add("", [list(z) for z in zip(list(city_data["city"]), list(city_data["confirm"]))],
word_gap=0, word_size_range=[10, 30]))
# 图片汇总
# page = (Page(page_title="2019-nCov",layout=Page.DraggablePageLayout)
page = (Page(page_title="2019-nCov")
.add(world_map)
.add(total_pie)
.add(area_map)
.add(area_heat_geo)
.add(bar)
.add(big_title)
.add(times)
.add(confirms)
.add(confirms_people)
.add(suspects)
.add(suspects_people)
.add(deads)
.add(deads_people)
.add(heals)
.add(heals_people)
.add(confirm_liquid)
.add(suspect_liquid)
.add(dead_liquid)
.add(heal_liquid)
.add(wc)
).render("2019-nCoV 数据一览.html")
with open("2019-nCov 数据一览.html", "r+", encoding='utf-8') as html:
html_bf = BeautifulSoup(html, 'lxml')
divs = html_bf.select('.chart-container')
divs[0][
"style"] = "width:605px;height:274px;position:absolute;top:36px;left:333px;border-style:solid;border-color:#444444;border-width:0px;"
divs[1][
'style'] = "width:411px;height:303px;position:absolute;top:5px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
divs[2][
"style"] = "width:309px;height:405px;position:absolute;top:313px;left:961px;border-style:solid;border-color:#444444;border-width:0px;"
divs[3][
"style"] = "width:305px;height:405px;position:absolute;top:310px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
divs[4][
"style"] = "width:646px;height:304px;position:absolute;top:312px;left:312px;border-style:solid;border-color:#444444;border-width:0px;"
divs[5][
"style"] = "width:250px;height:55px;position:absolute;top:2px;left:440px;border-style:solid;border-color:#444444;border-width:0px;"
divs[6][
"style"] = "width:200px;height:30px;position:absolute;top:11px;left:675px;border-style:solid;border-color:#444444;border-width:0px;"
divs[7][
'style'] = "width:60px;height:75px;position:absolute;top:5px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;border-radius:25px 0px 0px 0px"
divs[8][
"style"] = "width:130px;height:75px;position:absolute;top:5px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[9][
"style"] = "width:60px;height:75px;position:absolute;top:80px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[10][
"style"] = "width:130px;height:75px;position:absolute;top:80px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[11][
"style"] = "width:60px;height:75px;position:absolute;top:155px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[12][
"style"] = "width:130px;height:75px;position:absolute;top:155px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[13][
"style"] = "width:60px;height:75px;position:absolute;top:230px;left:1060px;border-style:solid;border-color:#DC143C;border-width:3px;"
divs[14][
"style"] = "width:130px;height:75px;position:absolute;top:230px;left:1120px;border-style:solid;border-color:#DC143C;border-width:3px;border-radius:0px 0px 25px 0px"
divs[15][
"style"] = "width:160px;height:160px;position:absolute;top:-35px;left:920px;border-style:solid;border-color:#444444;border-width:0px;"
divs[16][
"style"] = "width:160px;height:160px;position:absolute;top:40px;left:865px;border-style:solid;border-color:#444444;border-width:0px;"
divs[17][
"style"] = "width:160px;height:160px;position:absolute;top:115px;left:920px;border-style:solid;border-color:#444444;border-width:0px;"
divs[18][
"style"] = "width:160px;height:160px;position:absolute;top:188px;left:865px;border-style:solid;border-color:#444444;border-width:0px;"
divs[19][
"style"] = "width:1280px;height:120px;position:absolute;top:600px;left:0px;border-style:solid;border-color:#444444;border-width:0px;"
body = html_bf.find("body")
body["style"] = "background-color:#333333;"
html_new = str(html_bf)
html.seek(0, 0)
html.truncate()
html.write(html_new)
html.close()
然后程序里面用到的世界各国中英文对照.xlsx
链接:https://pan.baidu.com/s/1t4TjgEMPv8kzkvJY-h5ujA
提取码:8bvl
看看在我家“大屏”上的效果:
最后再次向全国抗疫的国内外各行各业的人士致敬!
武汉加油!
.
.
.
.
.
.
.
.
.
.
PS:
几天没看,今天又看了看,发现这个不能用了,因为TX页面改了,添加删除了一些东西(比如把确诊分为现存和累计等…),所以我就又改了改,把新增的那些数据补了上去,还有就是把正中央的那个柱状图折线图混合改成了轮播图,这样看着更清晰,再者就是改了个名(原来叫 2019-nCov 我写了那篇文章那天WHO定名 COVID-19 我也就没改… )
新的在这里:
pyecharts实现新冠肺炎疫情可视化并搭建BI数据大屏(Plus)
最新:基于Django+Pyecharts的COVID19新冠肺炎疫情监控面板
基于Django+Pyecharts的COVID19新冠肺炎疫情监控面板
代码地址:https://github.com/sleepyyoung/COVID19
欢迎Star~