之前写过一篇关于Python 制作 动态排序图的教程,里面利用的是 Matplotlib 中的 animation 函数,文章内容可参考动态排序图的详细制作教程,动态排序图的最终部分效果如下:
save_bar1.gif今天文章将用另外一种Python 软件包 Pyecharts,来实现类似效果,效果如下:
save_bar.gif在整个动态图的绘制过程,主要用到了 Pyecharts 的 Timeline 高级组件,该组件与 Matplotlib 中 animatation 函数原理相同,
把数据以时间作为唯一变量,在不同时间点下其它数据条目是不一样的,一个时间点可以绘制一张可视化图表,把全部的可视化图表一帧一帧连接起来,通过帧与帧之间的数据差值变化,最终形成动态图效果
而 Timeline 组件和 anaimation 函数在这里承担的角色就是 帧与帧之间可视化图表的拼接,以上原理介绍完了,接下来就来介绍一下具体怎么使用 Timeline
Timeline 组件使用
1,安装 Pyecharts
使用之前,请确保你已经安装好 Pyecharts ,安装方式直接利用pip 工具即可,命令如下:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n13" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">pip install pyechartske</pre>
2,创建 Timeline 对象类
先创建一个 Timeline 对象,相当于一个容器,把后面绘制的每一帧可视化报表图放在里面,然后根据放入先后顺序合成一个类似动态图的视频
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n16" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"># 导入所需要的库函数
from pyecharts import options as opts
from pyecharts.charts import Bar,Timeline
from pyecharts.faker import Faker
import random
t1 = Timeline()# 创建 Timeline对象</pre>
3,循环绘制每一帧图表,放入 Timeline
利用 for 或 while 循环语句,遵守 Pyecharts 语句创建每一帧时间对应的可视化图表,然后加入了前面创建的 Timeline() 组件中,这里图表以直方图 Bar 为例
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">for i in range(1969,2020):
attr1 = random.shuffle(list(attr))
bar = (
Bar()
.add_xaxis(random.sample(attr, len(attr)))
.add_yaxis('Data',Faker.values(),label_opts = opts.LabelOpts(position = 'right'),
)
.set_series_opts(label_opts = opts.LabelOpts(is_show = True,position = 'right'))
.reversal_axis()
.set_global_opts(title_opts = opts.TitleOpts("{}".format(i),
pos_left = '50%',
),
legend_opts = opts.LegendOpts(pos_right = '10%'))
)
t1.add(bar,'{}年'.format(i))</pre>
代码解读,这里以1969-2020 作为时间段,对每一个时间节点也就是某一年创建对应的 Bar 图表,最后以t1.add(instance,str)
函数把对应时间点创建的图表加入 Timeline
组件中,为了后面更好的展示动态效果,这里把对 Bar 的坐标轴做了逆置操作( reversal_axis()
),每一帧的效果预览如下:
4,美渲染化图表, html 文件
另外,在 Timeline() 中 提供了函数add_schema()
用于美化组件样式,例如 时间轴方向、符号、颜色、每一帧停留时间、播放键位置、是否现实 timeline 组件、组件位置
等属性,函数使用介绍如下
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n24" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">def add_schema(
坐标轴类型。可选:
'value': 数值轴,适用于连续数据。
'category': 类目轴,适用于离散的类目数据,为该类型时必须通过 data 设置类目数据。
'time': 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,
例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
'log' 对数轴。适用于对数数据。
axis_type: str = "category",
时间轴的类型。可选:
'horizontal': 水平
'vertical': 垂直
orient: str = "horizontal",
timeline 标记的图形。
ECharts 提供的标记类型包括 'circle', 'rect', 'roundRect', 'triangle', 'diamond',
'pin', 'arrow', 'none'
可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
symbol: Optional[str] = None,
timeline 标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,
例如 [20, 10] 表示标记宽为 20,高为 10。
symbol_size: Optional[Numeric] = None,
表示播放的速度(跳动的间隔),单位毫秒(ms)。
play_interval: Optional[Numeric] = None,
表示播放按钮的位置。可选值:'left'、'right'。
control_position: str = "left",
是否自动播放。
is_auto_play: bool = False,
是否循环播放。
is_loop_play: bool = True,
是否反向播放。
is_rewind_play: bool = False,
是否显示 timeline 组件。如果设置为 false,不会显示,但是功能还存在。
is_timeline_show: bool = True,
是否反向放置 timeline,反向则首位颠倒过来
is_inverse: bool = False,
Timeline 组件离容器左侧的距离。
left 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比,
也可以是 'left', 'center', 'right'。
如果 left 的值为'left', 'center', 'right',组件会根据相应的位置自动对齐
pos_left: Optional[str] = None,
timeline 组件离容器右侧的距离。
right 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比。
pos_right: Optional[str] = None,
Timeline 组件离容器上侧的距离。
left 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比,
也可以是 'top', 'middle', 'bottom'。
如果 left 的值为 'top', 'middle', 'bottom',组件会根据相应的位置自动对齐
pos_top: Optional[str] = None,
timeline 组件离容器下侧的距离。
bottom 的值可以是像 20 这样的具体像素值,可以是像 '20%' 这样相对于容器高宽的百分比。
pos_bottom: Optional[str] = "-5px",
时间轴区域的宽度, 影响垂直的时候时间轴的轴标签和轴之间的距离
width: Optional[str] = None,
时间轴区域的高度
height: Optional[str] = None,
时间轴的坐标轴线配置,参考 series_options.LineStyleOpts
linestyle_opts: Union[opts.LineStyleOpts, dict, None] = None,
时间轴的轴标签配置,参考 series_options.LabelOpts
label_opts: Optional[opts.LabelOpts] = None,
时间轴的图形样式,参考 series_options.ItemStyleOpts
itemstyle_opts: Union[opts.ItemStyleOpts, dict, None] = None,
)</pre>
美化完图表之后,利用渲染命令把图表到处至本地 html 文件 t1.render( html路径)
,最终效果如下(Ps :请不要在意图表中数据的真实性,这里只是为了介绍 Timeline() 的使用方法,里面数据都是随机生成得到的)
完整代码部分
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n28" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">from pyecharts import options as opts
from pyecharts.charts import Bar,Timeline
from pyecharts.faker import Faker
import random
attr = Faker.choose()
t1 = Timeline()# 创建 Timeline对象
for i in range(1969,2020):
attr1 = random.shuffle(list(attr))
bar = (
Bar()
.add_xaxis(random.sample(attr, len(attr)))
.add_yaxis('Data',Faker.values(),label_opts = opts.LabelOpts(position = 'right'),
)
.set_series_opts(label_opts = opts.LabelOpts(is_show = True,position = 'right'))
.reversal_axis()
.set_global_opts(title_opts = opts.TitleOpts("{}".format(i),
pos_left = '50%',
),
legend_opts = opts.LegendOpts(pos_right = '10%'))
)
t1.add(bar,'{}年'.format(i))
t1.add_schema(
symbol = 'arrow',# 设置标记时间;
orient = 'vertical',
symbol_size = 2,# 标记大小;
play_interval = 900,# 播放时间间隔;
control_position = 'right',# 控制位置;
linestyle_opts = opts.LineStyleOpts(width = 5,
type_ = 'dashed',
color = 'rgb(255,0,0,0.5)'),
label_opts = opts.LabelOpts(color = 'rgb(0,0,255,0.5)',
font_size = 15,
font_style = 'italic',
font_weight = 'bold',
font_family ='Time New Roman',
position = 'left',
interval = 20,
)
)
t1.render("D:/timeline_bar.html")</pre>
Timeline 组件扩展
以上通过制作 动态排序图来介绍了 Timeline 组件,本案例中图表主体类型为 Bar ,但在实际应用可以根据视觉效果、业务需求等不同应用场景把 Bar 替换为 其他图表类型,只需要把上面代码部分中的 for 循环主体代码替换即可,
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n32" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">for i in range(1969,2020):
attr1 = random.shuffle(list(attr))
instance = ...你的图表类型
t1.add(instance,'{}年'.format(i))</pre>
换一种图表类型,可能会不一样的视觉效果,例如桑葚图:
imag11252.gif圆环饼图,都有不错的动态效果,都可借助 Timeline 组件来实现
imag112521.gif好了,以上就是本篇文章的所有内容,最后感谢大家阅读!
网友评论