最近有需要做交互式图表,这方面是早用R的时候是用shiny+plotly做的,后来转Python后,改用D3JS和ECHARTS做,对JS不熟悉,做起来非常吃力。这次找到 ECHARTS 的Python包 PyEcharts,上手很快,推荐下。
与Python下其它的可视化工具相比,PyEcharts的好处:
- 可以生成 html 网页,节省写 js 的时间。
2、自带动画效果,和比较丰富的可视化样式,常用的功能都有。
3、能支持pandas的数据,虽然支持的还不太好,但总比没有强。
4、做时间轴轮播图和地理图很方便。
官方手册中还有提到整合了 Flask 、Django等WEB框架,还没有用到。另外也有缺点,比如绘制函数曲线,多表组合方面有点不足,不过可能也是我吃得还不够深,总觉得还是ggplot2用着舒服,可惜python的ggplot不如R太多。
使用环境
Python 3.8.2
pyecharts 1.8.1
官网:查看API说明和示例
安装
pip install pyecharts
基本语法:折线图
from pyecharts.charts import Line # 导入图表类
from pyecharts.faker import Faker # 用来造假数据的,示例用
from pyecharts import options as opts # 导入配置方法
from pyecharts.globals import ThemeType # 导入主题样式,对我这个色弱太友好了
line = Line() # 创建折线图实例
line.add_xaxis(Faker.choose()) # 添加X轴,用Faker造的假数据做示例
line.add_yaxis('折线A', Faker.values()) # 添加y轴数据
line.add_yaxis('折线B', Faker.values()) # 添加第二条数据
line.render('test.html') # 渲染网页
在当前目录下找到 test.html ,用浏览器打开即可查看。(由于Faker生成的假数据不同,会有差异)
链式语法和使用主题样式:ThemeType
查看官方主题样式
line = (
Line(init_opts=opts.InitOpts(width='1120px', theme=ThemeType.DARK)) # 指定主题样式 DARK
.add_xaxis(Faker.choose())
.add_yaxis('', Faker.values())
.render('test.html')
)
组合图:Grid
除了 Grid外,还有 page 、tab、overlap等组合方式。grid可以理解为分层组合,类似ggplot的facet。page就把多张图按上下顺序放到同个网页,tab是在顶部放菜单,把多图按水平顺序组合,overlap是在同个坐标系中组合。无法共享坐标系的图,不能用Grid组合,比如漏斗图就不能。
再吹一波ggplot,做多图组合不要太舒服,啥事不管,指定个分组维度就好了。
from pyecharts.charts import Line, Bar, Grid # 导入 Bar 条形图, Grid 组合类
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.faker import Faker
# 先创建一张折线图, 示例用的不用细看
line = (Line().add_xaxis(Faker.choose()).add_yaxis('', Faker.values()).set_global_opts(title_opts=opts.TitleOpts(title='折线图', pos_left='10%')))
# 创建条形图
bar = (
Bar()
.add_xaxis(Faker.choose())
.add_yaxis('', Faker.values(),
label_opts=opts.LabelOpts( # 设置标签参数
position='right', # 数据标签放在条形右边,坐标系有小坑,是按照坐标翻转后来算的
formatter='{b} : {c}' # 指定标签的模板样式,b, c等参数意义可以参考官网。好怀念ggplot
)
)
.reversal_axis() # 翻转坐标系,柱图翻转变条形图。不能做极坐标变换,还是ggplot好
.set_global_opts(
# 设置标题,pos_top是设置标题位置, 按组合后的坐标算,有点麻烦
title_opts=opts.TitleOpts(title='条形图', pos_top='55%', pos_left='70%'), # 指定标题内容,
yaxis_opts=opts.AxisOpts(is_show=False)
)
)
# 创建组合图
grid = (
Grid(init_opts=opts.InitOpts(theme=ThemeType.DARK, , page_title='pyecharts示例')) # page_title设置网页标题
.add(line, grid_opts=opts.GridOpts()) # 添加折线图, 必须带 grid_opts
# 添加条形图, 用 pos_ 参数指定位置和控制大小
.add(bar, grid_opts=opts.GridOpts(pos_left='70%', pos_top='60%', pos_bottom='20%'))
)
grid.render('test.html')
地理图:Map
前面的比较无聊,这里是pyecharts好用的地方了,提供 Map 和 Geo两个API绘制地理图,有些细微差别,示例用 Map
注意事项,Map 接收的数据格式为嵌套list,省份的名字不能用 "广东省" 之类的。如:
[['广东', 39], ['北京', 80], ['上海', 33], ['江西', 130], ['湖南', 80], ['浙江', 86], ['江苏', 20]]
from pyecharts.charts import Bar, Map, Timeline
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.faker import Faker
# 做单个地图还好, 在使用 grid 做组合地图的时候, 有不少坑, 踩得我自己都忘记了
# 生成示例数据
data = [[prov, Faker.values()[ind]] for ind,prov in enumerate(Faker.provinces)]
# 设置可视化的配置项, 用于地图热力效果,坑最多就是这里了,多考虑坐标系共享的问题
visualOpts = opts.VisualMapOpts(
is_calculable=True, is_piecewise=False, pos_left='5%', pos_top='10%', # 配置可视化组件的位置,避免被其它图挡住
range_color=['white', 'red'], # 配置热力颜色效果, 坑, 和下面的文字设置是反着来的
range_text=['High', 'Low'], # 配置组的提示文字
)
# 生成地图
m = (
Map()
.add('', data, maptype='china') # 默认的 maptype 类型就是中国地图, 台湾永远都是祖国不可分割的一部份!
.set_global_opts(visualmap_opts=visualOpts) # 要出现热图地图的效果,必须开启 visualmap 项目
)
# 创建条形图
b = (Bar().add_xaxis([i[0] for i in data]).add_yaxis('', [i[1] for i in data]).reversal_axis().set_global_opts(visualmap_opts=visualOpts))
# 组合图形
grid = (
Grid(init_opts=opts.InitOpts(theme=ThemeType.DARK, page_title='pyecharts 示例'))
# 必须先add 条形图, 最后add 地图, 否则报错
.add(b, grid_opts=opts.GridOpts(pos_left='5%', pos_top='70%', pos_bottom='5%', pos_right='60%'))
.add(m, grid_opts=opts.GridOpts())
)
grid.render('test.html')
时间轴轮播:Timeline
可以很方便地做出按轴轮播的交互效果,虽然对数据分析的意义不大,但炫啊!
from pyecharts.charts import Bar, Map, Timeline
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.faker import Faker
# 创建方法, 用于生成每一步的图表
def _get_grid():
""" 把上个示例中的组合地图搬过来, 注意底部的距离需要调整 """
pass
# 创建时间轴,没啥好说的,一看就懂
tl = (
Timeline(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add(_get_grid(), time_point='第1步')
.add(_get_grid(), time_point='第2步')
.add(_get_grid(), time_point='第3步')
)
tl.render('test.html')