You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
19 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 25图表库想要生成动态图表用Echarts就够了
你好,我是尹会生。
在上一讲中我们学习了怎么使用Seaborn来生成图片格式的图表。事实上图片格式的图表也被称作静态图表它能通过数据来更直观地展示结果。
不过很多时候,我们不仅要通过图片直观地展示数据,还要让图片容纳更多种类、更丰富的数据信息。这个时候,静态图表能展示的结果就十分有限了。比如你希望能给领导和同事在会议上演示数据的分析结果时,需要通过一张图来容纳更多的数据。
别担心,这时候我们可以**采用动态图表的方法,来增强图片的表现力**。因为动态图表展示的结果,相当于静态图表和数据这两者的混合,所以容纳的内容信息也就更丰富。
举个例子,我希望用一张图片来展示全国新冠确诊病例的分布。如果采用动态图,我就可以把鼠标移动到我需要查看的省份上面,显示该地区的确诊人数等相关信息。
就像下面这张截图一样。这张分布图不但基于颜色深浅显示了确诊人数的变化,还能通过鼠标悬停来显示具体的数据。使用起来是不是很方便?
![](https://static001.geekbang.org/resource/image/60/01/6063f764e3493cb69b2922b1988dcf01.png?wh=803*603)
这张动态图表是使用HTML网页文件格式来展示的。同时它也采用了Python的库pyecharts进行了绘制其中的图形、数据都可以基于你的需要进行调整。最重要的是绘制这样一张图片操作起来和seaborn生成静态图表一样简单。
那接下来,我就为你具体讲解一下**怎么****使用pyecharts来****绘制疫情实时地图**,并以此为例,让你掌握**怎么通过****pyecharts来****绘制其他的动态图**。
要想**使用pyecharts绘制动态图必须要先对它进行安装再为pyecharts加载数据最后才能进行绘制动态图**。所以我们参考静态图表的学习方法我来先带你从安装开始学习pyecharts。
## 安装使用pip安装pyecharts
pyecharts库和它的安装包同名因此你依旧可以使用pip命令进行安装。不过在这一步我们需要验证pyecharts库是否被成功安装。这是非常重要的一步。
因为和之前安装的软件包最大的不同是pyecharts库的依赖包非常多。这里我要对依赖包的概念多做些补充。
依赖包是指软件为了支持某些功能而这一功能刚好有其他的第三方库已经实现了那么该软件就不必再次编写该功能。但是你在使用pyecharts库时它所依赖的库也必须被安装在你的电脑上面你才能正常使用它。
这就像你操作Excel在你的脚本使用了“xlwt”库而其他人使用你的脚本必须也在他的电脑上安装这个库是相同的道理。因此当你对pyecharts进行安装的时候会有很多被依赖的安装包一起被安装在你的电脑上。不过不用担心依赖包并不影响pyecharts库的安装。
由于安装pyecharts的过程pip命令需要同时安装很多依赖包你大概率还会在安装过程看到“Requirement already satisfied”这样的提示这个提示是指你安装的库已经被安装在你的计算机中有可能是你之前使用pip命令安装的这些被依赖的包也有可能是因为其他库的依赖它们被安装到了你的计算机中但是这些提示都不影响pyecharts库的安装。这些提示也并非安装错误你可以直接忽略该提示即可。
不过依赖包过多虽然不影响安装但是会带来一个主要的问题。那就是在安装的终端界面会显示很多提示信息如果提示信息超过一个屏幕的长度会把安装成功或失败的安装结果覆盖掉导致你很难确认pyecharts是否安装成功因此我们需要一种可以确认pyecharts乃至任何一个第三方库是否被成功安装在当前计算机的方法。
想要验证pyecharts库是否被成功安装可以在命令行执行下面这个命令来帮助你验证
```
SHELL$ pip3 freeze | grep pyecharts
pyecharts==1.9.0
```
在这条命令中,有三个地方需要你格外注意:
* 命令中的“freeze”用于查看pip命令在当前计算机安装的所有软件包都有哪些
* “|”叫做管道符,用于连接左右两条命令,并把左边命令的执行结果作为右边命令的输出;
* 通过grep命令过滤只包含“pyecharts”的一行。如果你不使用grep命令“pip3 freeze”会将当前计算机中所有的第三方库及其版本显示在终端上如果第三方库非常多很难手动确认pyecharts是否被成功安装了。
这就是查看某一个库是否被成功安装在当前计算机,以及查看被安装版本的命令,我经常使用这一命令来确认依赖关系较多的库是否被成功安装。
不过你肯定会有疑问了,查看库是否安装这一做法是为了避免有些库存在不兼容,导致安装失败。那为什么还要查看安装的版本呢?
主要是考虑到版本兼容问题。我以pyecharts举例pyecharts是Python和Echarts的结合体Echarts是由百度开源的交互式可视化图表工具基于JavaScript脚本实现。因此Python提供的接口更新和Echarts工具更新都会导致使用pyecharts的函数不同。而pyecharts 分为 v0.5.X 和 v1 两个大版本且v0.5.X 和 v1 不兼容v1 又是一个全新的版本这两个版本支持的Python最低版本也不同。简而言之
* v0.5.X 版本的pyecharts能支持Python2.7、Python3.4及以上版本;
* v1 版本的pyecharts能支持Python3.6及以上版本。
如果基于公司规定你必须使用默认的Python3.4版本的话可以使用如下命令安装0.5版本的pyecharts
```
pip install pyecharts==0.5
```
解决完pyecharts的版本兼容问题后相信你的pyecharts的正常运行肯定不在话下了那接下来我就带你学习怎么给pyecharts加载数据。
## 数据为pyecharts加载数据
在给pyecharts加载数据前我们还要确认**数据的格式和数据来源**。这样做是为了把从网站中得到的数据转换为符合pyecharts绘图的数据。
* 数据格式用于传入数据前要把来源数据转换成被pyecharts支持的格式
* 数据来源,决定数据的准确性和详细程度。
例如网站中的数据包含了省、市、区的确诊人数以及成功被治愈的人数而我们只需要每个省被确诊的人数。因此数据格式和来源都需要经过你的精心处理才能被pyecharts展示给使用者。
### 确认数据的格式和来源
pyecharts的**数据格式**要基于不同的图形类型使用不同的格式。但是一般情况下是多行多列组成的类似Excel表格的格式这种格式在Python中一般使用**嵌套元组**的形式进行保存。
以绘制疫情地图数据为例我们需要每个省的名称以及现有确诊人数那么我们可以把省的名称和人数放在一个元组中并把多个省的数据再组成一个更大的元组作为pyecharts的源数据。
这种并列数据你可能第一时间想到的不是元组而是列表但是我要告诉你的是列表的查询效率要远远低于元组。为了让你的图形在展示数据时能够更加流畅我更建议你使用元组具体方法是在把列表作为源数据使用前使用“tuple()”函数把列表类型转换为元组。
确定数据格式之后,我们还需要一个**数据来源**,为了确保数据的准确性和实时性,我们得从腾讯新闻的网站引入外部数据,[数据地址](https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5)的链接我先贴出来,接下来我再给你讲解一下怎么得到数据地址。
为了得到数据的地址,我分析了网站加载数据的过程,找到了数据接口的地址。这个分析方法你学会以后,也可以应用到其他需要抓取网页数据的工作中。我把抓取的步骤分成四步,分别是开启浏览器调试、请求网页、确认接口和确认返回数据。
先看第一步,**开启浏览器调试**。这一步骤是为了在请求过程中,能记录网页都请求了哪些数据接口。
以Chrome浏览器为例使用快捷键F12可以打开调试模式把选项卡调整至“Network”调整后就进入接口的监听状态了。
第二步,**请求网页**。以腾讯疫情实时网页为例,可以在地址栏输入“[https://news.qq.com/zt2020/page/feiyan.htm#/](https://news.qq.com/zt2020/page/feiyan.htm#/)”,输入后,调试界面会显示该网页都请求了哪些地址。我把调试页面放在下方供你参考。
![](https://static001.geekbang.org/resource/image/c7/44/c7349yyae70d9bcf369e95644fe4f344.png?wh=1895*1127)
截图的左侧就是请求的所有数据接口的地址从最开始请求的地址向下找除了JS、JPG等网页图片和样式数据外其他的请求接口就是我们要重点查看的接口。
第三步,**确认接****。**由于网页中包含了多次从“getOnsInfo”接口取得数据所以要逐个查看接口的返回数据。你可以通过鼠标点击接口的链接然后再点击“Response”按钮最后根据返回接口的返回内容查看是否为“疫情实时数据”。
第四部,**确认返回数据**。当你从接口初步确认了该数据是“疫情实时数据”后,可以把该地址复制到浏览器中,进行访问。访问的具体办法就是通过模拟网页请求接口,这样就可以得到以下数据了。我将数据放在截图中,供你参考。
![](https://static001.geekbang.org/resource/image/99/e5/99040018387067600f77ae5d603e4fe5.png?wh=1069*498)
截图中的数据,可以通过查找省份和数据来确认数据的正确性。如果数据不正确,你需要回到第二步,再重新找下一个接口。
### 调整数据格式
当你确认了数据格式和数据源之后接下来就需要把数据源的格式转换为pyecharts需要的嵌套元组格式。
首先我先来分析通过网页直接请求数据接口之后的格式请求后你会看到网页上面的格式类似于Python的多个字典嵌套在一起这种格式被称作JSON格式。在Python中你可以通过“json”库去解析这种格式并把它转换为Python中的字典。解析的方法如下
```
import requests
import json
url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5'
data = requests.get(url)
alldata = json.loads(data.json()['data']
```
在这段代码中我使用了requests.get()方法获取了接口的内容并使用json.loads()方法把接口的数据转换成了字典。由于所有的数据都在下标为“data”的字典中通过“字典\[data\]”取得字典值的用法把所有数据存放到alldata变量中。
接下来要把alldata变量中的字典转换为嵌套元组形式这个转换过程需要遍历字典来取得省份名称和对应的确诊人数。不过为了保存多个省份我们还需要使用一个新的列表来存储多个省份的数据。最后再把列表转换为元组作为pyecharts的绘图数据使用。我们依次来看一下
```
chinadata = []
for province in alldata['areaTree'][0]['children']:
provincedata = (
province['name'],
province['total']['nowConfirm']
)
chinadata.append(provincedata)
```
在代码的第2行我使用了for循环从alldata字典的多层嵌套结构中取出省份和该省份的确诊、累计、新增等人数信息。
在代码的第3行我使用了一个新的元组provincedata变量只保存每次遍历时得到的省份和确诊人数。
在代码的第7行我把每次遍历生成的元组增加到chinadata列表中。这个列表就是最终处理好的数据内容可以把chinadata数据直接作为pyecharts的源数据来进行绘图。
这段代码比较简单,不过我还是有两个小的使用建议提供给你。
第一个是我在代码的第3行定义了一个provincedata的元组从代码的正确执行角度来说这个变量可以不用定义完全可以把元组直接写入到chinadata.append() 函数的参数中。
但是从方便阅读代码的角度来看这样书写代码不利于理解因为append()函数的参数中包含了较为复杂的类型。因此我建议你在某个函数的参数中,如果传入了多种数据类型时,不妨增加一个临时变量。
另一个小建议是在数据量较多的时候应当尽量把列表转换为元组加快查询效率。例如我在代码的第7行先使用了列表对象用来存储变化的数据然后通过for循环迭代alldata变量修改chinadata列表。最后直到chindata不再需要改变内容时我立即使用了tuple()把chinadata列表强制转换为了元组那么后续的查询操作就都可以使用元组了。
通过对数据的抓取、分析和处理源数据的格式和内容就准备完成了。接下来我需要将源数据加载到pyecharts中并指定图形的类型和样式。
## 绘图使用pyecharts绘制动态图表
当你准备好数据源并处理格式之后,就可以进行绘图了,主要有三个步骤,分别是**确定图表类型**、**加载数据和设置图表样式**。那我们先来看看怎么确定图表类型。
和我们学习seaborn类似你可以参考图例也可以参考分类来学习pyecharts支持的动态图表。与seaborn不同的是pyecharts的官方文档没有图例不过不要忘了pyecharts是基于Echarts编写的因此图例可以参考[Echarts的官方网站](https://echarts.apache.org/examples/en/index.html)。
Echarts的图表指定函数和pyecharts相同找到你需要的图例函数之后就可以拿到pyecharts中直接使用。
那针对老手的图表分类和API可以[参考](https://gallery.pyecharts.org/#/README)[这个地址](https://gallery.pyecharts.org/#/README)。以最常用的图表,折线图为例,你可以打开[地址](https://gallery.pyecharts.org/#/Line/temperature_change_line_chart),其中会包括图表的完整调用代码、测试数据和图例,通过参考示例可以让你掌握更多类型的图表。折线图的截图如下:
![](https://static001.geekbang.org/resource/image/b0/06/b018bf7f0d7b34bfdce2c89fd8c8a006.png?wh=917*626)![](https://static001.geekbang.org/resource/image/06/65/06926268b01a96be2aaedaa2720d2d65.png?wh=981*861)
再让我们回到疫情地图的案例中由于我们需要绘制中国地图因此直接使用pyecharts库的Map()类,它是绘制动态地图的类。它的[官方网站](https://gallery.pyecharts.org/#/Map/map_base)链接我贴在这里。
通过参考官方网站的案例代码我们可知在将Map()类实例化之后进行绘图时调用了add()、set\_global\_opts()和render()三个方法,它们分别是增加数据、设置样式和渲染。我们来依次学习一下。
* add()方法用来为图表增加图表名称、加载数据、指定地图的区域其中加载数据的参数我使用了tuple()函数,可以直接把列表转换为元组,这样在查找效率上会比列表更高。
* set\_global\_opts()方法用来指定图表的样式和格式这里我做了两个格式的调整操作它们是图表的标题和图表的颜色。图表的标题部分我将“数据最后更新时间”作为图表的标题是通过字典“alldata\[lastUpdateTime\]”实现的。图表的颜色是通过pieces参数实现的根据不同省份确诊人数在什么数量范围显示该省份的颜色深浅。颜色越深表示当前周期采集到的确诊人数越多。
* render()方法用来指定图表保存的网页路径和名称。这里需要注意的是add()和set\_global\_opts()方法如果出现错误并不会马上报错只有在调用render()方法时才会出现错误。所以一旦出现错误你应该从导入数据的格式、add()和set\_global\_opts()方法参数中检查。
执行render()方法之后动态图就会以网页的形式保存至“covid19\_map.html”文件中你可以在浏览器里查看并通过鼠标移动展示不同省份确诊人数的具体信息。
最后我把pyecharts绘制图形的完整代码贴在下方供你参考你可以直接将代码复制到自己的计算机执行。
```
import requests
import json
from pyecharts.charts import Map
from pyecharts import options as opts
url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5'
data = requests.get(url)
alldata = json.loads(data.json()['data'])
chinadata = []
for province in alldata['areaTree'][0]['children']:
provincedata = (
province['name'],
province['total']['nowConfirm']
)
chinadata.append(provincedata)
map_chart = Map()
map_chart.add(
"全国确诊病例分布图",
tuple(chinadata),
"china",
is_map_symbol_show=False
)
map_chart.set_global_opts(
title_opts=opts.TitleOpts(
title=f"全国疫情地图( {alldata['lastUpdateTime']} )"),
visualmap_opts=opts.VisualMapOpts(
is_piecewise=True,
pieces=[
{"min": 1, "max": 9, "label": "1-9人", "color": "#FFE6BE"},
{"min": 10, "max": 99, "label": "10-99人", "color": "#FFB769"},
{"min": 100, "max": 499, "label": "100-499人", "color": "#FF8F66"},
{"min": 500, "max": 999, "label": "500-999人", "color": "#ED514E"},
{"min": 1000, "max": 9999, "label": "1000-9999人", "color": "#CA0D11"},
{"min": 10000, "max": 100000, "label": "10000人以上", "color": "#A52A2A"}
]))
map_chart.render('covid19_map.html')
```
## 小结
今天的主要内容就这么多,我来为你最后总结一下本讲的主要内容。
在本讲中我通过pyecharts展示了疫情实时信息的动态图表并为你介绍了图表的制作方法。对比静态图表动态图表的制作方法要复杂但是一张图能容纳的信息也要比静态图表多你需要根据自己的工作场景合理的选择图表种类。
同时你还会发现图表的绘制难点在数据格式的处理上通过网络采集数据往往要经过从JSON格式到字典再到元组的嵌套图表绘制过程可以重复利于的部分就是图表的创建过程包括数据添加、样式设置和渲染。掌握这些通用的使用原则可让让你从熟练的操作中加快自动办公的效率。
而你掌握的图表越丰富,在进行工作汇报和演示时,能够通过图形表达的信息就越清晰。这是我建议你能够掌握更多图表类型的原因。
## 思考题
今天的思考题是个开放的问题在你使用pyecharts绘制的图表需要每天更新时如何自动删除上一个生成的文件那有没有办法让网页自动更新呢
欢迎你把思考和想法分享在留言区,我们一起交流讨论。如果今天的内容对你展示工作成果有帮助,也欢迎你把课程分享给你的同事和朋友,我们一起做职场上的效率人。