最近在做一个数据可视化的任务,经过前期的调研,最终选择了PyEcharts。PyEcharts是百度可视化框架Echarts的Python版本,由于Python的“万能脚本”特性,PyEcharts沟通其他功能模块十分方便,支持“数据分析+数据展示”整套流程,但在炫酷方面,比不上原生的Echarts。Echarts基于JavaScript,动画效果与素材更多,它的社区里还有很多开源的可视化模板,在数据展示方面性能更强。如果你具有以下需求,PyEcharts是很不错的选择:
1)对可视化效果要求较高,Matplotlib所呈现的视效远远不够,而且需要“点击”、“拖拉”等交互效果。
2)同时具有数据分析的需求。Python在数据读取、科学计算方面也十分强劲,可直接完成数据分析,再通过PyEcharts可视化。
PyEcharts和其他的包一样,可直接通过pip安装,我是通过PyCharm配置的。需要特别说明的是,如果想使用PyEcharts绘制地图,需要下载相应的地图包,示例如下:
pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg
pip install echarts-china-counties-pypkg
pip install echarts-china-misc-pypkg
pip install echarts-united-kingdom-pypkg
可能是版本的原因,PyEcharts1.0与官网(pyecharts.org)的开发文档有些出入,本来想总结性的写出来,但是感觉有点抽象,还是直入主题,遇到了再讲吧。
用PyEcharts绘制地图需要先初始化一个Map对象,许多教程是这样做的:
map = Map("地图示例", width=1200, height=600)
“地图示例”是地图的标题,width与height是地图的长宽,这似乎不难理解。但运行时会报错:
TypeError: __init__() got an unexpected keyword argument 'width'
关于这个错误网上并没有相关资料,向开发者发邮件后也并没有回复,于是猜测width与height两个参数应该在目前版本中被移除了,于是我采用了官网中的另一种初始化方式:
map = (Map().add(data,'china').set_global_opts(title_opts=opts.TitleOpts(title="地图示例")))
首先用add()函数添加地图图表,然后用set_global_opts()函数传入标题参数。通过set_global_opts()还可以设置官网中除InitOpts的如下参数:
每个参数的功能点进去有详细解释,其中InitOpts()就是设置长宽这些参数的,然而PyEcharts1.0中没有这个函数了,也就是说现在无法设置图表的长宽,只能采用默认大小,这影响还蛮大的。如果是我理解错了,大家有别的办法,可以告诉我。
除此之外,添加一个地图就是用add(data,'china')方法了,'china'是地图类型,data是图表数据。具体而言,data是一个二元组的列表,比如:
data = [('北京',100),('湖北',200),('广东',300)……]
需要注明的是,每个省份只需要名字,不需要后面的行政称谓,如湖北不叫湖北省,内蒙古叫内蒙古,不叫内蒙古自治区。
地图创建完成后,通过render()方法可以将地图渲染为html或者图片,如:
map.render(path='./map.html')
以上就是用PyEcharts制作一个简单地图的流程,完整代码如下:
from pyecharts.charts import Map
from pyecharts import options as opts
from pyecharts.globals import ThemeType
value = [115.4,121.6,122,116,123.3,110.4,118.4,116.8,114.3,
113.2,111.8,116.8,113.4,113,121.3,118.7,119,117.6,113.8,
115.1,114.1,115.2,112.6,114.8,120.2,118.2,119.8,114.7,115.4,
114.6,112.7]
attr = ['甘肃','广东', '广西','贵州','海南',
'河南','湖北', '湖南','宁夏','青海',
'陕西','四川', '西藏','新疆','云南',
'重庆','北京', '天津','河北','山西','内蒙古',
'辽宁','吉林', '黑龙江','上海','江苏','浙江','安徽','福建'
,'江西','山东']
sequence = list(zip(attr,value))
def map_visualmap(sequence,year) -> Map:
c = (
Map()
.add(year,sequence, "china",)
.set_global_opts(
title_opts=opts.TitleOpts(title="地图"),
visualmap_opts=opts.VisualMapOpts(max_=130,min_=95),
)
)
return c
map = map_visualmap(sequence,'1993')
map.render(path='./test.html')
用PyEcharts制作一个随年份不断变化的地图也是可以的,这需要用到一个类似时间轴的的组件:Timeline。具体原理就是先创建一个时间轴,然后往里面添加制作好的不同年份地图,如果地图很多,写一个循环自动读取数据就行了。这就体现了PyEcharts的优越性,在JS里读取数据可不容易。
直接放完整代码:
from pyecharts.charts import Map
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Timeline
import xlrd
attr = ['甘肃','广东', '广西','贵州','海南',
'河南','湖北', '湖南','宁夏','青海',
'陕西','四川', '西藏','新疆','云南',
'重庆','北京', '天津','河北','山西','内蒙古',
'辽宁','吉林', '黑龙江','上海','江苏','浙江','安徽','福建'
,'江西','山东']
#读取Excel文件的函数
def read_excel(row_number):
# 打开文件
workbook = xlrd.open_workbook(r'C:\Users\Faker\Desktop\分省.xlsx')
# 根据sheet索引或者名称获取sheet内容
sheet2 = workbook.sheet_by_index(0)
# 获取整行和整列的值(数组)
rows = sheet2.row_values(row_number) # 获取第四行内容
return rows
def map_visualmap(sequence, year) -> Map:
c = (
Map()
.add(year, sequence, "china",)
.set_global_opts(
title_opts=opts.TitleOpts(title="分省汇总"),
visualmap_opts=opts.VisualMapOpts(max_=130,min_=95),
)
)
return c
#创建时间轴
timeline = Timeline()
for i in range(2,28):
#读取Excel中的value
row = read_excel(i)
row = row[2:]
#创建data序列
sequence_temp = list(zip(attr,row))
#创建地图的标题
year = 1991+i
#创建地图
map_temp = map_visualmap(sequence_temp,str(year))
#将地图加入时间轴
timeline.add(map_temp,str(year)).add_schema(play_interval=360)
timeline.render(path='./map.html')
年份较多,因此用一个for循环自动读取Excel表里的数据,还是比较简单的。add_schema()函数可以控制时间轴自动播放的速度,单位为ms,可视化效果如下:
Echarts设计的十分简洁,因此制作其他类型的柱图、饼图、雷达图等都大同小异,下面是以绘制饼图为例说明。创建一个饼图的代码如下:
def pie_rosetype_2(data) -> Pie:
c = (
Pie()
.add(
"城市居民",
data,
radius=["30%", "75%"],
center=["23%", "50%"],
rosetype="radius",
label_opts=opts.LabelOpts(),
)
return c
与地图相似,data都是一个二元组的列表,格式为[('标签',value)……]。radius与center是控制饼图大小与位置的参数,rosetype='radius'则表明这是一个类型为’radius‘的玫瑰图。
下面直接放一个带时间轴的双饼图代码:
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Timeline
import xlrd
attr_city= ['家庭设备','交通通信','文教娱乐','居住','食品','衣着','医疗保健','其他商品']
attr_rual = ['其他商品','居住','食品','文教娱乐','衣着','医疗保健','家庭设备','交通通讯']
def read_city_excel(row_number):
# 打开文件
workbook = xlrd.open_workbook(r'C:\Users\Faker\Desktop\饼图.xlsx')
# 根据sheet索引或者名称获取sheet内容
sheet2 = workbook.sheet_by_index(0)
# 获取整行和整列的值(数组)
rows = sheet2.row_values(row_number)
rows = rows[4:18:2]
return rows
def read_rural_excel(row_number):
# 打开文件
workbook = xlrd.open_workbook(r'C:\Users\Faker\Desktop\农村居民各项消费占比.xlsx')
# 根据sheet索引或者名称获取sheet内容
sheet2 = workbook.sheet_by_index(0)
# 获取整行和整列的值(数组)
rows = sheet2.row_values(row_number)
rows = rows[5:19:2]
return rows
#创建两个饼图的函数
def pie_rosetype_2(sequence1,sequence2) -> Pie:
c = (
Pie()
.add(
"城市居民",
sequence1,
radius=["30%", "75%"],
center=["23%", "50%"],
rosetype="radius",
label_opts=opts.LabelOpts(),
).add(
"农村居民",
sequence2,
radius=["30%", "75%"],
center=["75%", "50%"],
rosetype="radius",
label_opts=opts.LabelOpts()
).set_global_opts(title_opts=opts.TitleOpts(title="城市与农村居民各项消费占比"),
legend_opts=opts.LegendOpts(pos_left='30%'))
)
return c
timeline = Timeline()
for i in range(1,26):
row1= read_city_excel(i)
sequence1= list(zip(attr_city, row1))
row2=read_rural_excel(i)
sequence2 = list(zip(attr_rual,row2))
year = 1992 + i
map_temp = pie_rosetype_2(sequence1,sequence2)
timeline.add(map_temp, str(year)).add_schema(play_interval=360)
timeline.render(path=r'./pie.html')
数据同样是从excel中读取,只不过双饼图就是在原有的add()函数后另加一个add()函数,多饼图同理,下面是可视化效果展示:
讲完了两个常规图,下面说一个3D图。其实基本思路与2D图还是一样的,只是要注意输入的数据变成了一个三元组的列表,可以理解为散点的x,y,z坐标,例如[('1993','农村居民食物支出',30%),……]。直接上代码:
import xlrd
from pyecharts import options as opts
from pyecharts.charts import Scatter3D
attr = ['家庭设备','交通通信','文教娱乐','居住','食品','衣着','医疗保健','其他商品']
year = [1993:2017:1]
def read_city_excel(row_number):
# 打开文件
workbook = xlrd.open_workbook(r'C:\Users\Faker\Desktop\3D散点图.xlsx')
# 根据sheet索引或者名称获取sheet内容
sheet2 = workbook.sheet_by_index(0)
# 获取整行和整列的值(数组)
rows = sheet2.row_values(row_number)
rows = rows[4:18:2]
return rows
def read_rural_excel(row_number):
# 打开文件
workbook = xlrd.open_workbook(r'C:\Users\Faker\Desktop\3D散点图2.xlsx')
# 根据sheet索引或者名称获取sheet内容
sheet2 = workbook.sheet_by_index(0)
# 获取整行和整列的值(数组)
rows = sheet2.row_values(row_number)
rows = rows[5:19:2]
return rows
#创建散点数据列表
scatter_city = []
scatter_rural = []
for i in range(1,26):
row_city = read_city_excel(i)
row_rural = read_rural_excel(i)
for _ in range(len(attr)):
scatter_city.append([attr[_-1],1992+i,row_city[_-1]])
for _ in range(len(attr)):
scatter_rural.append([attr[_-1],1992+i,row_rural[_-1]])
#定义制作3D散点图的函数
def scatter3d_base() -> Scatter3D:
c = (
Scatter3D()
.add("城镇居民", scatter_city).add('农村居民',scatter_rural)
.set_global_opts(
title_opts=opts.TitleOpts("Scatter3D-基本示例"),xaxis_opts=opts.AxisOpts(is_show=True)
)
)
return c
scatter = scatter3d_base()
scatter.render(path='./3D_scatter.html')
如代码所示,在整张图中我创建了两个3D散点图,一个表示城市,一个表示农村,也是用的add().add()的方法,效果如下:
在这篇博客中,我介绍了PyEcharts绘制三种图表的方法,并对一些常用的参数及组件进行了说明。可以看出,PyEcharts的架构非常简洁,使用起来也十分方便,可视化效果也很不错。使用过程中,一定要以官方文档为主,一些官方文档未详细说明的地方,通过名称与函数架构,其实也可以推理出来。如果本文有说得不对的地方,欢迎大家批评指正。