数据可视化专区 加入小组

2个成员 1个话题 创建时间:2022-09-23

Python实现数据动态可视化

发表于2022-09-23 1175次查看

Python实现数据动态可视化

 

和数据打交道的人都听过一句话,叫做“文不如表,表不如图”,在信息传递上,图有着表和文字所没有的优势。这里的图,指的就是将数据通过图的形式展现出来,即我们常说的数据可视化。

 

当前,我们正处于大数据时代,数据量呈现井喷之势,如何从海量数据中获取有用的信息是摆在所有数据人面前的问题。其中,数据可视化就是很有效的一种手段,数据可视化之后能够直观展现蕴藏其中的趋势规律等。

 

很长一段时间以来,人们都在使用静态的图来展现数据,例如这种:

或者这种:

 

以上的图也可以展现数据中包含的信息,但是,如果我们想要了解随着时间的变动,数据在各个时间点的表现,静态图在表现力上就明显不如动态图。

而且,有时候我们希望能够多个图形同时展现在一块画布上,形成一块动态的数据可视化看板,这篇文章,就和大家探讨一下,如何用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()

 

最终的可视化效果见动图。

 

发表回复
你还没有登录,请先 登录或 注册!
话题作者
数据分析师

新加组员