和数据打交道的人都听过一句话,叫做“文不如表,表不如图”,在信息传递上,图有着表和文字所没有的优势。这里的图,指的就是将数据通过图的形式展现出来,即我们常说的数据可视化。
当前,我们正处于大数据时代,数据量呈现井喷之势,如何从海量数据中获取有用的信息是摆在所有数据人面前的问题。其中,数据可视化就是很有效的一种手段,数据可视化之后能够直观展现蕴藏其中的趋势规律等。
很长一段时间以来,人们都在使用静态的图来展现数据,例如这种:
或者这种:
以上的图也可以展现数据中包含的信息,但是,如果我们想要了解随着时间的变动,数据在各个时间点的表现,静态图在表现力上就明显不如动态图。
而且,有时候我们希望能够多个图形同时展现在一块画布上,形成一块动态的数据可视化看板,这篇文章,就和大家探讨一下,如何用python制作这样的可视化看板
本文主要应用pyecharts来制作动态图像,pyecharts更多用法请参照官方文档:https://pyecharts.org/
导入需要的python模块
Pyecharts是一款能在Python下实现数据动态可视化分析的模块插件,基于百度开源的Echarts数据可视化库。
所以,运用pycharts绘图,第一步要先下载它。
可以在命令行工具中运行这一行代码:pip install pycharts
下载成功后,还要通过import关键字导入它才能调用。
调用pyecharts库中函数的方式与常用的可视化库matplotlib或者seaborn相比,略有不同,不是一句一行一个函数的形式,而是在函数运行结果的基础上进行链式调用。
另外,pyecharts中有专门的配置项,图中的标题、坐标轴等的配置需要调用配置项,例如下图全职配置项负责的组件配置:
所以,我们在用pyecharts绘图时,除了要导入相关的绘图函数,还要导入配置项,如下代码,即导入配置项及相关的绘图函数等。
import pyecharts.options as opts # 配置对象 from pyecharts.globals import ThemeType # 主题对象 from pyecharts.charts import Timeline, Grid, Bar, Map, Pie, Line # 导入各种图表接口
图中展现的所有内容都来自与数据,所以,绘图的前提得有数据,我们先来生成数据。
这里用到的是各省在不同年份的GDP数据
生成数据
from data import * # 导入数据(字典形式) 导入data 等
time_list = [str(d) + "年" for d in range(1993, 2019)] # 生成时间列表 print(time_list)
['1993年', '1994年', '1995年', '1996年', '1997年', '1998年', '1999年', '2000年', '2001年', '2002年', '2003年', '2004年', '2005年', '2006年', '2007年', '2008年', '2009年', '2010年', '2011年', '2012年', '2013年', '2014年', '2015年', '2016年', '2017年', '2018年']
#根据历年来各个省份GDP最大 最小值 设置的数值区间,用于设置地图视觉对象的设置 maxNum = 97300 minNum = 30
定义绘图函数
我们想要把多个图展现在一块看板中,pyecharts中并没有这样的一个函数可以满足需求,所以得自定义一个函数,包含我们所需要的所有图形。
假设,我们需要在看板中同时展现各省份在地图位置上数据的变化、折线图的趋势变化、条形图的对比变化、饼图的结构变化,那么,就需要在自定义的函数中,包含上述绘制上述图形的函数。
另外,还需要多一个函数,用来进行看板的布局,把不同的图放置在指定位置,避免图形发生重叠等影响可视化效果的情况。
下边即是自定义函数的全部代码
# 定义函数 根据年份不同绘制不同的图形 def get_year_chart(year: str): # map_data 某年的各个省份GDP数据 map_data = [ [[x["name"], x["value"]] for x in d["data"]] for d in data if d["time"] == year][0] min_data, max_data = (minNum, maxNum) # 用于动态标记折线图各个点 data_mark: List = [] i = 0 for x in time_list: if x == year: data_mark.append(total_num[i]) else: data_mark.append("") i = i + 1 # 添加地图 map_chart = ( Map() .add( series_name="", # 图系名称 data_pair=map_data, # 绘图数据 zoom=1, # 缩放 center=[119.5, 34.5], is_map_symbol_show=False, itemstyle_opts={ "normal": {"areaColor": "#323c48", "borderColor": "#404a59"}, "emphasis": { "label": {"show": Timeline}, "areaColor": "rgba(255,255,255, 0.5)", }, }, ) .set_global_opts( # 图像标题对象配置 title_opts=opts.TitleOpts( title="" + str(year) + "全国各地区GPD数据(单位:亿) 数据来源:国家统计局", subtitle="", pos_left="center", pos_top="top", title_textstyle_opts=opts.TextStyleOpts( # 设置标题的文本属性 font_size=25, color="rgba(255,255,255, 0.9)" # rgb + 透明度 ), ), # 视觉映射配置项 visualmap_opts=opts.VisualMapOpts( is_calculable=True, #是否显示拖拽用的手柄(手柄能拖拽调整选中范围) dimension=0, pos_left="30", # 距离容器左侧距离 pos_top='top', # 自动top 对其 range_text=["High", "Low"], # 上下的文本内容 range_color=["#4885A9","#FBD0E5", "#E18786"], # 过度颜色设置 textstyle_opts=opts.TextStyleOpts(color="#ddd"), # 字体颜色设置 min_=min_data, # 最小值 max_=max_data, # 最大值 ), ) ) # 添加线图 line_chart = ( Line() .add_xaxis(time_list) # x轴的数据 .add_yaxis("", total_num) # y轴的数据 .add_yaxis( # 标记的数据,用于标记当前年份的全国GDP总量 "", data_mark, markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]),#设置标记类型 ) .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 不显示标签项 .set_global_opts( title_opts=opts.TitleOpts( title="全国GDP总量变化1993-2018年(单位:万亿)", pos_left="72%", pos_top="5%" ) ) ) # 条形图 bar_x_data = [x[0] for x in map_data] bar_y_data = [{"name": x[0], "value": x[1][0]} for x in map_data] bar = ( Bar() .add_xaxis(xaxis_data=bar_x_data) # 添加x轴数据 .add_yaxis( # 添加y轴数据 series_name="", y_axis=bar_y_data, label_opts=opts.LabelOpts( # 标签项配置 is_show=True, position="right", formatter="{b} : {c}" # 展示格式 {b}表示类目 name ,{c}表示数值 value ), ) .reversal_axis() # 坐标轴翻转,横向为条形图 .set_global_opts( # 设置全局配置 xaxis_opts=opts.AxisOpts( # x轴 max_=maxNum, axislabel_opts=opts.LabelOpts(is_show=False) ), yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(is_show=False)), # y轴 tooltip_opts=opts.TooltipOpts(is_show=False), # 关闭工具项 visualmap_opts=opts.VisualMapOpts( is_calculable=True, dimension=0, # 映射到哪个维度上 x为0 y 为 1 pos_left="10", pos_top="top", range_text=["High", "Low"], range_color=["#4885A9", "#FBD0E5", "#E18786"], textstyle_opts=opts.TextStyleOpts(color="#ddd"), min_=min_data, max_=max_data, ), ) ) # 饼图 pie_data = [[x[0], x[1][0]] for x in map_data] pie = ( Pie() .add( series_name="", data_pair=pie_data, radius=["15%", "35%"], #内半径与外半径 默认设置成百分比,相对于容器高宽中较小的一项的一半 center=["80%", "80%"], # 饼图圆心设置,第一个是宽度相对于容器左侧,第二个是高度相对于容器顶部 itemstyle_opts=opts.ItemStyleOpts( border_width=2, border_color="rgba(66,170,189,0.3)" # 描边宽度与颜色 ), ) .set_global_opts( tooltip_opts=opts.TooltipOpts(is_show=True, formatter="{b}:{d}%"), legend_opts=opts.LegendOpts(is_show=False), ) ) # 将多张子图放置到一起,设置图片的位置 grid_chart = ( Grid() .add( bar, grid_opts=opts.GridOpts( pos_left="10", # 距离左侧的距离 像素 pos_right="45%", pos_top="50%", pos_bottom="5" ), ) .add( line_chart, grid_opts=opts.GridOpts( pos_left="65%", # 距离左侧的距离 pos_right="80", # 距离右侧的距离 像素 pos_top="10%", # 距离顶部的距离 pos_bottom="50%" # 距离底部的距离 ), ) .add(pie, grid_opts=opts.GridOpts(pos_left="65%", pos_top="60%")) .add(map_chart, grid_opts=opts.GridOpts()) # 使用默认配置 ) return grid_chart # 返回
函数定义完成后,这个函数还只能绘制静态图形,如果想要动态效果,还需要添加时间轴筛选器,时间在时间轴上变动,数据也会跟着边,可视化看板中的图就也会随着数据的变化而变化,展示出动态效果。
向图形添加时间轴删选器
# 动态图形添加时间轴 timeline = Timeline( init_opts=opts.InitOpts(width="1800px", height="900px", theme=ThemeType.DARK) ) # 遍历时间列表,绘制不同时间下的图形 for y in time_list: g = get_year_chart(year=y) timeline.add(g, time_point=str(y)) # 将图形添加到时间轴 # 动图整体设置 timeline.add_schema( orient="vertical", # 时间轴是v ertical垂直 还是 horizontal 水平 is_auto_play=True, # 是否自动播放动图 is_inverse=True, # 是否反向放置 play_interval=500, # 自动播放时每一帧图像之间的时间间隔 # pos_left="null", pos_right="5", pos_top="20", pos_bottom="20", width="60", label_opts=opts.LabelOpts(is_show=True, color="#FBD0E5"), ) timeline.render("china_gdp_from_1993_to_2018_color.html") # 渲染为html页面
上述代码中,把看板图渲染成了html页面,这个页面可以发送给别人通过浏览器打开。
如果使用的IDE是jupyter notebook的话,也可以直接在notebook中渲染,看板内嵌到ipynb文件中。
在notebook中渲染的代码如下:只需要加在所有代码的最后一行即可。
timeline.render_notebook()
最终的可视化效果见动图。