前言
一般用matplotlib和seaborn就可以做可视化,为什么偏要用pyecharts?
- 它是中国人做的!
- 更重要的,是它非常好用,可以作出非常多很酷的动图。比如大家刷疫情的时候,常看到的图
关于pyecharts教程,首推官方中文教程。如果诸位想要快速入门,不妨继续往下看。 - 安装:我用的pycharm,直接搜索pyecharts安装,当然,需要科学上网(付费VPN),如果没有连接外网,我的经验是经常下载失败~
- python版本:3.5及以上,建议大家直接安装最新版,能避免很多麻烦
准备工作
这篇博客是接着上一篇博客写的。在上一篇博客(新型冠状病毒数据抓取及整理详细流程)里,我们通过抓取腾讯新闻的数据,得到疫情数据,并将我们将所需数据存入三个DataFrame中
- 中国疫情历史数据:chinaDayData
- 中国各省份城市的当天疫情数据:china_info
- 其他发生疫情的国家整体疫情数据:foreigns
(以上数据会放进资源里,大佬们如果没时间看上一篇博客,可以直接下载数据进行操作。)
为了调取数据方便,我们将得到的数据保存成csv文件。注意,由于城市和省份信息里有中文,所以这里无论保存还是读取,都需要指明编码方式encoding=‘gbk’。
# 保存数据
chinaDayData.to_csv(r'F:\开课吧\RS基础课\2019_CoV_chinaDayData.csv', encoding='gbk', index=None);
china_info.to_csv(r'F:\开课吧\RS基础课\2019_CoV_china_info.csv', encoding='gbk', index=None);
foreigns.to_csv(r'F:\开课吧\RS基础课\2019_CoV_foreigns.csv', encoding='gbk', index=None);
# 读取数据
chinaDayData = pd.read_csv(r'F:\开课吧\RS基础课\2019_CoV_chinaDayData.csv', encoding='gbk');
china_info = pd.read_csv(r'F:\开课吧\RS基础课\2019_CoV_china_info.csv', encoding='gbk');
foreigns = pd.read_csv(r'F:\开课吧\RS基础课\2019_CoV_foreigns.csv', encoding='gbk');
(以上数据会放进资源里,大佬们如果没时间看上一篇博客,可以直接下载数据进行操作。)
用pyecharts可视化
通过查阅pyecharts教程,你会发现很多很有趣的图,比如 仪表盘,水球图,旭日图和词云图。想象能够将分析结果通过这些图表示出来,有没有觉得很酷?
哈哈,废话不多说,直接说我们要用到的图(点击可跳转到官方教程的相关页面):
# 导入pyecharts第三方库
from pyecharts.charts import *
from pyecharts import options as opts
饼图
- 目标:展示死亡人数、治愈人数与待治愈人数的比例。
- 说明:有些大佬用 死亡人数、治愈人数与确认人数 来做饼图,这是令人困惑的。因为确认人数里面应该包括死亡人数与治愈人数,所以与死亡人数、治愈人数并列的,应该是待治愈人数。其中,
- 数据:在chinaDayData中,我们记录了每一天的全国疫情数据。这里,我们选择最近一天的数据作为饼图数据。
# 创建 待治愈人数 列
chinaDayData['to_be_healed'] = chinaDayData['confirm'] - chinaDayData['dead'] - chinaDayData['heal'];
# 将最近一天的数据作为饼图数据
pie_data = chinaDayData.loc[len(chinaDayData)-1, ['to_be_healed', 'suspect', 'dead', 'heal']];
pie_data.index = ['待治愈人数', '疑似人数', '死亡人数', '治愈人数']
print(pie_data);
待治愈人数 37693.0
疑似人数 21675.0
死亡人数 1017.0
治愈人数 3998.0
Name: 28, dtype: float64在这里插入代码片
接下来,我们来生成饼图。
# 饼图
my_pie = (
Pie()
# 加载数据
.add("", [list(z) for z in zip(pie_data.index, pie_data.values)])
# 标题
.set_global_opts(title_opts=opts.TitleOpts(title= '全国疫情人数比例(%)'))
# 标签格式
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}"))
);
# 生成的饼图被保存在一个my_pie.html文件里面
my_pie.render(r'F:\开课吧\RS基础课\my_pie.html');
点开本地文档my_pie.html,可以看到
饼图的标签格式formatter="{b}: {d}"看上去有点奇怪。这里,做一点说明:{a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)。
折线
- 目标:观察 确诊人数、疑似人数、死亡人数、治愈人数 关于时间的变化趋势;
- 数据:chinaDayData
查看数据类型:
print(chinaDayData.info());
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 29 entries, 0 to 28
Data columns (total 9 columns):
date 29 non-null float64
confirm 29 non-null int64
suspect 29 non-null int64
dead 29 non-null int64
heal 29 non-null int64
deadRate 29 non-null float64
healRate 29 non-null float64
add 29 non-null int64
to_be_healed 29 non-null int64
dtypes: float64(3), int64(6)
memory usage: 2.2 KB
None
可以看到,在chinaDayData中,‘date’列数据类型是float64,这就意味着我们需要将其转化成str,方便作图。
chinaDayData['date'] = chinaDayData['date'].map(str);
print(list(chinaDayData.date));
['1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22', '1.23', '1.24', '1.25', '1.26', '1.27', '1.28', '1.29', '1.30', '1.31', '2.01', '2.02', '2.03', '2.04', '2.05', '2.06', '2.07', '2.08', '2.09', '2.10']
经过上面数据处理,现在已经可以开始作图了。
# 作出 关于确诊人数和疑似人数 的折线图
my_line1 = (
Line()
# x轴
.add_xaxis(list(chinaDayData['date']))
# y轴
.add_yaxis('确诊人数', list(chinaDayData.confirm))
.add_yaxis('疑似人数', list(chinaDayData.suspect))
# 标题
.set_global_opts(title_opts=opts.TitleOpts(title="全国确诊人数与疑似人数关于时间变化趋势"))
)
# 作出关于 死亡人数、治愈人数与新增人数 的折线图
my_line2 = (
Line()
# x轴
.add_xaxis(list(chinaDayData['date']))
# y轴
.add_yaxis('死亡人数', list(chinaDayData.dead))
.add_yaxis('治愈人数', list(chinaDayData.heal))
.add_yaxis('新增人数', list(chinaDayData['add']))
# 标题
.set_global_opts(title_opts=opts.TitleOpts(title="全国死亡人数、治愈人数\n与新增人数关于时间变化趋势"))
)
# 两个折线图各自保存进html文件中
my_line1.render(r'F:\开课吧\RS基础课\my_line1.html');
my_line2.render(r'F:\开课吧\RS基础课\my_line2.html');
分别打开本地文档的my_line1.html和my_line2.html,可以看到折线图:
地理图
- 目标:分别在世界地图和中国地图上观察疫情分布情况
- 数据:中国的疫情分布用china_info,世界的疫情分布用foreigns
首先根据中国国内数据,作出四川省的疫情分布状况。
- 注意,在做之前,必须先将城市名称规整化。这是由于pyecharts中地图内置的城市名称可能与数据中的城市名称不同,这将导致做出的地图没有任何数据显示。
# 按照四川省的各个市来计算确认人数
# 这里将城市中文名称规整化
def city_name(city):
if city == '阿坝':
city = '阿坝藏族羌族自治州';
elif city == '凉山':
city = '凉山彝族自治州';
elif city == '甘孜':
city = '甘孜藏族自治州';
else:
city = city + '市';
return city;
# 提取china_info中的四川省数据,并选取其中的city和confirm列。
sichuanMap_data = china_info[china_info['province']=='四川'];
sichuanMap_data.drop(['province', 'healRate(%)', 'deadRate(%)'], axis=1, inplace=True);
sichuanMap_data.index = range(len(sichuanMap_data));
sichuanMap_data['city'] = sichuanMap_data['city'].map(city_name);
#print(sichuanMap_data);
# 作图
sichuan_map = (
Map()
.add('', [list(z) for z in zip(sichuanMap_data.city, sichuanMap_data.confirm)], '四川')
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
# 标题
title_opts=opts.TitleOpts(title="四川地图疫情分布图"),
tooltip_opts=opts.TooltipOpts(formatter='{b}: {c}'),
# 视觉效果
visualmap_opts=opts.VisualMapOpts(is_piecewise=True,
pieces=[
{'min': 51, 'label': '>50', "color": "#ff585e"},
{'min': 21, 'max': 50, 'label': '21-50', "color": "#ffb248"},
{'min': 11, 'max': 20, 'label': '11-20', "color": "#ffb248"},
{'min': 1, 'max': 10, 'label': '1-10', "color": "#fff2d1"}
]),
)
)
# 存储进html文件
sichuan_map.render(r'F:\开课吧\RS基础课\sichuan_map.html')
其次,根据中国国内数据,作出各省的疫情分布状况。
# 按照省份来计算确认人数
chinaMap_data = china_info[['province', 'confirm', 'heal', 'dead']].groupby('province').sum().sort_values(by='confirm', ascending=False);
#print(chinaMap_data);
china_map = (
Map()
.add('', [list(z) for z in zip(chinaMap_data.index, chinaMap_data.confirm)], 'china')
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
# 标题
title_opts=opts.TitleOpts(title="中国地图疫情分布图"),
tooltip_opts=opts.TooltipOpts(formatter='{b}: {c}'),
# 视觉效果
visualmap_opts=opts.VisualMapOpts(is_piecewise=True,
pieces=[
{'min': 20001, 'label': '>20000', "color": "#893448"},
{'min': 1000, 'max': 20000, 'label': '1000-20000', "color": "#ff585e"},
{'min': 500, 'max': 999, 'label': '500-999', "color": "#ffb248"},
{'min': 100, 'max': 499, 'label': '100-499', "color": "#ffb248"},
{'min': 1, 'max': 99, 'label': '1-99', "color": "#fff2d1"}
]),
)
)
china_map.render(r'F:\开课吧\RS基础课\china_map.html')
得到图像如下:
最后,我们根据国际数据,作出世界范围内疫情分布情况。
- 注意,这里我们同样需要将中文国名转化成英文名,这是由于pyecharts中的国名是英语,所以如果数据是中文,则会导致图表没有数据显示。
根据我的博客《从360图书馆抓取全球国家的中文名与英文名》,可以作出中文国名与英文对应的字典,我们记为dict_countries.
dict_countries = {'中国': 'China', '蒙古': 'Mongolia', '朝鲜': 'Dem. Rep. Korea', '韩国': 'Korea', '日本': 'Japan', '菲律宾': 'Philippines', '越南': 'Vietnam', '老挝': 'Laos', '柬埔寨': 'Cambodia', '缅甸': 'Myanmar', '泰国': 'Thailand', '马来西亚': 'Malaysia', '文莱': 'Brunei Darussalam', '新加坡': 'Singapore', '印度尼西亚': 'Indonesia', '尼泊尔': 'Nepal', '不丹': 'Bhutan', '孟加拉国': 'Bengal', '印度': 'India', '巴基斯坦': 'Pakistan', '斯里兰卡': 'Sri Lanka', '马尔代夫': 'Maldives', '哈萨克斯坦': 'Kazakhstan', '吉尔吉斯斯坦': 'Kyrgyzstan', '塔吉克斯坦': 'Tajikistan', '乌兹别克斯坦': 'Uzbekistan', '土库曼斯坦': 'Turkmenistan', '阿富汗': 'Afghanistan', '伊拉克': 'Iraq', '伊朗': 'Iran', '叙利亚': 'Syria', '约旦': 'Jordan', '黎巴嫩': 'Lebanon', '以色列': 'Israel', '巴勒斯坦': 'Palestine', '沙特阿拉伯': 'Saudi Arabia', '巴林': 'Bahrain', '卡塔尔': 'Qatar', '科威特': 'Kuwait', '阿拉伯联合酋长国阿联酋': 'United Arab Emirates', '阿曼': 'Oman', '也门': 'Yemen', '格鲁吉亚': 'Georgia', '亚美尼亚': 'Armenia', '阿塞拜疆': 'Azerbaijan', '土耳其': 'Turkey', '塞浦路斯': 'Cyprus', '芬兰': 'Finland', '瑞典': 'Sweden', '挪威': 'Norway', '冰岛': 'Iceland', '丹麦法罗群岛丹': 'Danmark Faroe Islands', '爱沙尼亚': 'Estonia', '拉脱维亚': 'Latvia', '立陶宛': 'Lithuania', '白俄罗斯': 'Belarus', '俄罗斯': 'Russia', '乌克兰': 'Ukraine', '摩尔多瓦': 'Moldova', '波兰': 'Poland', '捷克': 'Czech', '斯洛伐克': 'Slovakia', '匈牙利': 'Hungary', '德国': 'Germany', '奥地利': 'Austria', '瑞士': 'Switzerland', '列支敦士登()': 'Liechtenstein L I E', '英国': 'Britain', '爱尔兰': 'Ireland', '荷兰': 'Holand', '比利时': 'Belgium', '卢森堡': 'Luxemburg', '法国': 'France', '摩纳哥': 'Monaco', '罗马尼亚': 'Romania', '保加利亚': 'Bulgaria', '塞尔维亚': 'Serbia', '马其顿': 'Macedonia', '阿尔巴尼亚': 'Albania', '希腊': 'Greece', '斯洛文尼亚': 'Slovenia', '克罗地亚': 'Croatia', '波斯尼亚和墨塞哥维那(波黑)。': 'Bosnia Herzegovina', '意大利': 'Italy', '梵蒂冈': 'Vatican', '圣马力诺': 'San Marino', '马耳他': 'Malta', '西班牙': 'Spain', '葡萄牙': 'Portugal', '安道尔': 'Andorra', '埃及': 'Egypt', '利比亚': 'Libya', '苏丹': 'Sudan', '突尼斯': 'Tunis', '阿尔及利亚': 'Algeria', '摩洛哥': 'Morocco', '亚速尔群岛()葡': 'Azores Portugal', '马德拉群岛葡': 'M A D E I R A I S L A N D S', '埃塞俄比亚': 'Ethiopia', '厄立特里亚': 'Eritrea', '索马里': 'Somalia', '吉布提': 'Djibouti', '肯尼亚': 'Kenya', '坦桑尼亚': 'Tanzania', '乌干达': 'Uganda', '卢旺达': 'Rwanda', '布隆迪': 'Burundi', '塞舌尔': 'Seychelles', '乍得': 'Chad', '中非': 'Central Africa', '喀麦隆': 'Cameroon', '赤道几内亚': 'Equatorial Guinea', '加蓬': 'Gabon', '刚果共和国即:刚果布': 'Republicof Congo', '刚果民主共和国即:刚果金': 'Democratic Republicof Congo', '圣多美及普林西比': 'Sao Tomeand Principe', '毛里塔尼亚': 'Mauritania', '西撒哈拉注:未独立,详细请看:': 'Western Sahara', '塞内加尔': 'Senegal', '冈比亚': 'Gambian', '马里': 'Mali', '布基纳法索': 'Burkina Faso', '几内亚': 'Guinea', '几内亚比绍-': 'Guinea Bissau', '佛得角-': 'Cape Verde', '塞拉利昂': 'Sierra Leone', '利比里亚': 'Liberia', "科特迪瓦'": 'Coted Ivoire', '加纳': 'Ghana', '多哥': 'Togo', '贝宁': 'Benin', '尼日尔': 'Niger', '加那利群岛西': 'Canary Islands', '赞比亚': 'Zambia', '安哥拉': 'Angola', '津巴布韦': 'Zimbabwe', '马拉维': 'Malawi', '莫桑比克': 'Mozambique', '博茨瓦纳': 'Botswana', '纳米比亚': 'Namibia', '南非': 'South Africa', '斯威士兰': 'Swaziland', '莱索托': 'Lesotho', '马达加斯加': 'Madagascan', '科摩罗': 'Comorin', '毛里求斯': 'Mauritius', '留尼旺法': 'Reunion', '圣赫勒拿英': 'Saint Helena', '澳大利亚': 'Australia', '新西兰': 'New Zealand', '巴布亚新几内亚': 'Guinea', '所罗门群岛': 'Archipelago', '瓦努阿图': 'Vanuatu', '密克罗尼西亚': 'Micronesia', '马绍尔群岛': 'Marshall Islands', '帕劳': 'Palau', '瑙鲁': 'Nauru', '基里巴斯': 'Kiribati', '图瓦卢': 'Tuvalu T V', '萨摩亚': 'Samoa', '斐济群岛': 'Fiji Islands', '汤加': 'Tonga', '库克群岛新': 'Cook Islands', '关岛美': 'Guam', '新喀里多尼亚法': 'New Caledonia', '法属波利尼西亚': 'French Polynesia', '皮特凯恩岛英': 'Pitcairn Island', '瓦利斯与富图纳/法': 'Wallis Futuna', '纽埃新': 'Niue', '托克劳新': 'Tokelau', '美属萨摩亚': 'American Samoa', '北马里亚纳美': 'Mariana', '加拿大': 'Canada', '美国': 'America', '墨西哥': 'Mexico', '格陵兰丹': 'Greenland', '危地马拉': 'Guatemala', '伯利兹': 'Belize', '萨尔瓦多': 'Salvador', '洪都拉斯': 'Honduras', '尼加拉瓜': 'Nicaragua', '哥斯达黎加(另)': 'Costarica Costa Rica', '巴拿马': 'Panama', '巴哈马': 'Bahamas', '古巴': 'Cuba', '牙买加': 'Jamaica', '海地': 'Haiti', '多米尼加共和国': 'Dominican Republic', '安提瓜和巴布达': 'Antiguaand Barbuda', '圣基茨和尼维斯': 'Saint Kittsand Nevis', '多米尼克': 'Dominica', '圣卢西亚': 'Saint Lucia', '圣文森特和格林纳丁斯': 'Saint Vincentandthe Grenadines', '格林纳达': 'Grenada', '巴巴多斯': 'Barbados', '特立尼达和多巴哥': 'Trinidadand Tobago', '波多黎各美': 'Porto Rico', '英属维尔京群岛': 'British Virgin Islands', '美属维尔京群岛': 'Virgin Islandsofthe United States', '安圭拉英': 'Anguilla', '蒙特塞拉特英': 'Montserrat', '瓜德罗普法': 'Guadeloupe', '马提尼克法': 'Martinique', '荷属安的列斯': 'Netherlands Antilles', '阿鲁巴荷': 'Aruba', '特克斯和凯科斯群岛英': 'Turks And Caicos Islands', '开曼群岛英': 'Cayman Islands', '百慕大英': 'Bermuda', '哥伦比亚': 'Colombia', '委内瑞拉': 'Venezuela', '圭亚那': 'Guyana', '法属圭亚那': 'French Guiana', '苏里南': 'Suriname', '厄瓜多尔': 'Ecuador', '秘鲁': 'Peru', '玻利维亚': 'Bolivia', '智利': 'Chile', '阿根廷': 'Argentina', '乌拉圭': 'Uruguay', '巴拉圭': 'Paraguay'}
# 中英国名转换函数
def country_name(country):
if country in dict_countries:
return dict_countries[country];
# 从foreigns中选取 country和confirm 两列
world_data = foreigns[['country', 'confirm']];
# 国名转换
world_data['country'] = world_data['country'].map(country_name);
# 加上中国数据
china_world_data = china_info['confirm'].sum();
world_data = world_data.append({'country': 'China', 'confirm': china_world_data}, ignore_index=True);
print(world_data);
world_map = (
Map()
.add('', [list(z) for z in zip(world_data.country, world_data.confirm)], 'world')
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
# 标题
title_opts=opts.TitleOpts(title="世界地图疫情分布图"),
tooltip_opts=opts.TooltipOpts(formatter='{b}: {c}'),
# 视觉效果
visualmap_opts=opts.VisualMapOpts(is_piecewise=True,
pieces=[
{'min': 201, 'label': '>200', "color": "#893448"},
{'min': 51, 'max': 200, 'label': '51-200', "color": "#ff585e"},
{'min': 21, 'max': 50, 'label': '21-50', "color": "#ffb248" },
{'min': 11, 'max': 20, 'label': '11-20', "color": "#ffb248"},
{'min': 1, 'max': 10,'label': '1-10', "color" : "#fff2d1" }
]),
)
)
# 将世界疫情分布图存储进world_map.html
world_map.render(r'F:\开课吧\RS基础课\world_map.html');
得到图片为