整理 | 王强
在ApacheCon Asia 2021大会的“数据可视化论坛”上,特斯拉 BI 团队全栈开发工程师孟繁超(Makefile 君)发表了题为“ECharts 的乐趣:我们在特斯拉使用它的经验”的演讲。本文是这次演讲的内容总结。
大家好,我是孟繁超,在网上的昵称是 Makefile 君,目前在上海特斯拉 BI 团队担任全栈开发工程师。我平时主要负责相关业务报表的研发还有架构方面的工作。本次分享为大家带来我们在特斯拉中国使用Apache ECharts改善业务报表系统的一些经验。
我的分享分为两部分,第一部分是介绍我们报表系统是如何选型,以及如何决定使用 ECharts 作为主图表的经验;另外一部分是类似于一个 Workshop 形式,我们会提供一些非常简单的例子,让各位只要会基本的 Python 就可以很快上手做出一个动态的可视化图表。
下面我们正式开始分享。
背景
BI 团队会有非常多的报表需求,我们最开始的时候也是基于 Apache 旗下的另一个项目,也是非常有名的叫Superset,号称开源的 Tableau。不过我们当时做得比较早,是基于它 0.2X 版本分叉出来一种企业化定制的版本。
但我们发现它有一些问题,因为我们有定制,会导致它和主分支有一些偏移,并且在 0.3x 版本的时候有一些非常大的改动,我们很难无缝合并回主分支。同时我们在使用 Superset 时发现,虽然它早期的图表虽然非常多,但相对还是比较单一的,同时一些定制化的需求发现它确实无法满足。我们还遇到了一些问题,比如一些图表的渲染性能稍微差一些。
于是我们决定开发插件,却发现它的不同版本插件机制还不太相同。所以我们在很早的时候,内部就引入了一个 ECharts 的插件开发,同时我们自定了一套 Superset 控制面板,让我们非常多的支持工程师在不懂编程的情况下,也可以相对比较简单地去开发出自己想要的报表。
我们来看一下 Superset 早期接入的过程。我们实际上最初是要一个横向的柱状图,但我们在使用 ECharts 时候发现,通过简单的配置,实际上柱状图和线状图,还有堆叠特效都可以通过简单的配置来改变,所以我们就直接把 ECharts 的基本图表接入进去了。同时我们开发了定制面板,比如说通过下拉悬框进行一些配置,就可以改变 ECharts 的图形展现。
我们接入一两个月之后,中国区的服务器光使用 ECharts 柱状图就达到了四百多个,接入的反馈还是不错的。但是还是会有一些问题,实际上这也是很多 BI 工具都会面临的一些问题。
比如说一个报表可能会有多个 Chart,意味着它的资源开销、对后台数据库压力会非常大。另外我们开发新的一些图表接入 ECharts 或者其他的一些库会发现过于复杂,因为 Superset 0.2x 版本的插件机制还是比较复杂的,同时早期 Superset 的 Bug 也比较多,我们本身还有太多定制化需求,人力支持也有一些不足。所以在之后,从上层的角度来看我们做了这样一个模型:
我们把 Dashboard 分为三类,上面这类叫 lowcode dashboard,也就是不需要编程就可以实现的 Dashboard,开发周期大概是一到三天。中间叫 fastly built dashboard,让我们的支持工程师在只会 Python 这种语法友好的语言的情况下,就可以开发出自定义的图表。如果说这种还不能满足我们真正的需求,我们可能就要把它当成一个独立的 APP,用前后端分离的方式进行实现。
引入 Dash
我们做了定义之后发现我们的需求实际上是在中间层,我们需要从中有一些突破,所以我们后来在选型之后发现了这样一个工具,叫做 Dash。Dash 实际上就是一个用 Python 去开发动态化图表的工具,同时它提供了一个非常友好的接口,让我们只知道这些 ID 就可以完成事件的绑定。同时它作为一家商业公司还提供了一个企业版本,但我们主要用的还是它的开源版本,并且因为我们有自己的工程师,就会做一些改造。
使用 Dash 的好处就是它是一个纯 Python 开发框架,让我们的很多支持工程师可以相对快速的上手进行自定义报表创建。同时我们可以复用很多 Python 基础包提供的能力,这些包我们可以直接拿来用。另外我们发现图表中有很多不同数据展示的时候,因为我们是同一个数据源,这样用 Python 可以自定义数据源和不同 Dashboard 中间对应的 Chart,可以减轻对于数据库的压力。
在这个过程中,我们也把最新版本的 ECharts 引入了,获取了更多图表的整合,并且我们采取的措施没有对它进行过度的封装。我们就直接把 option 传入,只不过在 Python 中要使用的是符合标准的 Json 这样就可以。这样的话我们可以参考 ECharts 官方的惯例进行内部培训,让大家快速上手。
案例展示
以下是我们使用 Dash 以及 ECharts 能做的一些报表。首先是一个结合百度地图的报表。我们有很多物料从不同的地方运到工厂,它会记录这些距离。
从图表展现形式上我们可以看到,这样一个工具可以方便我们的支持工程师很快定位这些货车运货是否及时到达。我们可以看到货车实际上还分了几个不同的状态,绿色、黄色和红色,直观对应的是运货的延迟程度是否在我们能接受的范围内,同时导出功能也可以把数据按照我们想要的格式筛选下载下来。
上图是 A 股的交易量图表,方便我们简单的选股,后台用了一个叫 TuShare 的库去获取真实数据。
Dash 基础操作讲解
下面是一个用 Dash 和 ECharts 结合的 Gallery 教程,里面有一个完整例子。
以下是一个简单的安装操作:
下面这部分类似于一个 Workshop 的形式。我们会讲一下 Dash 和 ECharts 的基础,提供一两个例子,让大家快速上手。
Dash 的使用分为以下四个方面:数据获取、页面布局、图例使用和信号传递。我们把这四个方面都掌握了之后就可以很轻松的上手。
Dash 的一个好处是什么样的数据都可以获取。这里为了方便,我们使用一个随机数生成一周 7 天的数据。
其他的数据是怎么获取呢?你可以使用库里的方法获取数据,或者针对数据库、文件这样的数据用 Pandas。读取文件 CSV 或者 Excel 就更容易了。
除了数据获取,我们第二个关注点就是页面布局。Dash 的页面布局并不是那么简单,因为它是纯 Python 来写,我们通过 Dash 里面封装的 HTML 到 div 这样去创建一个 div 对象。
关于图例使用这部分,这里面我们使用了一个 ECharts,要注意的是它的 Option。Option 传入要设定它的 X 轴,比如说 X 轴一周 7 天;Y 轴是值类型的。类型都是在 series 里面,它是一个数组,可以接受多组信号的传递。
信号传递这部分,我觉得这是 Dash 的一个精髓。它抽象了几个原语,第一个是 output,第二个是 input,还有 state,分别对应它的输出输入以及状态。
比如说这里面的例子。我们的定时器用 ID: interval 来表示,它的 n_interval 就是第几次,每一次它的跳动都会进行一次触发。当它触发的时候会影响到 Output,也就是 ECharts option 的变化。然后我们在改变的时候,因为是一个 EChart 对 Option 的更新,我们要拿到 ECharts Option 当前的状态。比如说这里面我们可以看到 Option 对应的 opt 变量,它就是对里面的 series 第一个元素的 Data 进行调用。
这里面要注意的是 Input、State 可以为多个,实际上 Output 也可以为多个,但是大多数情况下都是写一个,因为你默认大多数的函数返回值都是一个的,也就是说 Output 要对应 return 后面的,而 Input 和 State 实际上是按照顺序依次是对应函数的参数。这是使用 Dash 完成它信号传递的方式。完整的代码在这里。
ECharts 基础操作讲解
我们现在相对深入去了解一下 ECharts Option。下面的例子中,我们实际上关注的是 X 轴为周一到周日,Y 轴是随机数。
X 轴为 category 类型的时候,我们要把 Data 直接放在这里面,传一些数值或者其他的一些数据。
Y 轴一般常规是数值形态,我们就设置一个 Type 为 Value,它的 Data 我们放在 series 里边。
这里边 Type 要特别注意,我们如果把它设置成一个 Line,它就是一个线状图;如果是设置成 Bar,它就是个柱状图。这是 ECharts 非常强大的一个地方,因为它通过简单的配置就可以在不同的图表之间快速切换。
比如说下面我们想要一个线状图。我们要求一个面积,设置不同的参数就可以得到这样一个图。而右图并不是一个线状和柱状的混合图,它是一个线状图,后面是一个 markArea。我们是专门用一个区域作为一个 mark,实际上就是把周三到周四这块标记为橙色。
下面是一个线状堆叠,还有一个线状堆叠的区域。因为这是两个图,数组就有两个。但我们看它的数值是一样的,它应该是重叠的,我们想把它堆叠起来,就是在里面设置一个 Stack。设置 Stack 之后,我们给它同样的一个名称,然后就可以堆叠在一起。这个时候我们如果再加上一个 areaStyle 这样一个参数,它就变成一个在区域覆盖的图。
接下来我们看一下柱状图。很多时候有一些图表,比如说生产线上某一个区域超过了一个阈值,我们要对它标红,平时给它标绿。在 series 传入数据的时候,除了传入数值形态,我们还可以传入进去一个 Dict,然后这块我们就可以对这一个单独数据调整样式。比如说这里面的传入 Value 是 200,设置大于 150 的时候会触发。右图是柱状堆叠,原理也是一样的。
我们看另外一个稍微复杂的例子。我们在使用 ECharts 的时候也非常看重这一个特性,也就是它能跟一些地图结合。这个例子来自 ECharts 官网,是全国主要城市的空气质量。从数据上来看,我们可以看到它里面有很多的蓝色小圆点,还有绿色大圆点,它是用不同的样式展现出来的。它们都是不同城市 PM2.5 的数据,只不过对于排名前十位的用绿色标注,而其他的都用蓝色。
用 Dash ECharts 要实现这样一个图,首先我们要有数据。数据分两类,第一类是这些城市的坐标,第二类是 PM2.5 的数值。然后我们定义一个函数,按照我们想要的 ECharts 数据进行转换。
这里面生成了两类数据,有一个是这些 points 本身,另外就是我们算出来的前十名城市的数据。我们在 ECharts Series 里面放两个数据就可以完成图表的展示。
除了常规的操作之外,我们需要引入百度地图的脚本,然后我们用 external_scripts 在 Dash APP 声明的时候传入它。然后我们的 Layout 这里面使用了另外一个 Dash ECharts 的特性,就是说我们在 Python 里面去声明一个 JS 的函数去调用,调整默认的那个圆。
ECharts 结合百度地图的 Option 配置就是这样,我们重点关注点是在 Bmap 这块。Bmap 要设置默认情况下的缩放尺寸、中心位置以及它的 mapStyle。对于 mapStyle,你可以传入一个大数组进行一个相对复杂的定制,也可以使用它默认的一些模板。
上面这里是我们数据 series 的配置,我们可以看左边是普通的 Points 点,右边是 Top10。Top10 里面加了一些特殊效果。
小结
以上就是我本次分享的所有内容,包括了我们在使用 ECharts 的一些经验的分享,以及两个简单实例的上手,谢谢。
评论