天天看点

Perspective:不容错过的大型数据可视化利器!

作者:高级前端进阶

大家好,很高兴又见面了,我是"高级前端‬进阶‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

Perspective:不容错过的大型数据可视化利器!

高级前端‬进阶‬

今天给大家带来的主题是 Perspective,即一种交互式分析和数据可视化组件,特别适用于大型、流数据集。话不多说,直接开始。

1.什么是 Perspective

Perspective 是一种交互式分析和数据可视化组件,特别适用于大型、流数据集。 可以使用它来创建用户可配置的报告、仪表板(dashboards)、笔记(notebooks)、编辑表格等应用程序,然后在浏览器中独立部署,也可以与 Python 和 Jupyterlab 协同部署。

Perspective:不容错过的大型数据可视化利器!

Perspective 具有以下明显特征:

  • 快速、内存高效的流式查询引擎(streaming query engine),用 C++ 编写并为 WebAssembly 和 Python 编译,具有 Apache Arrow 的读/写/流式处理,以及基于 ExprTK 的高性能柱状表达式语言。
  • 与框架无关的用户界面,打包为自定义元素,通过 WebAssembly 在浏览器中或通过 WebSocket 服务器(Python/Node)虚拟地提供支持。
  • 一个 JupyterLab 小部件和 Python 客户端库,用于 notebook 中的交互式数据分析,以及可扩展的生产 Voila 应用程序。

下面是 Perspective 的一些生产示例,还是非常惊艳的,更多基于 Perspective 的示例可以在官网查看。

Perspective:不容错过的大型数据可视化利器!

目前 Perspective 在 Github 上通过 Apache-2.0 许可开源,有超过 6.3k 的 star、0.7k 的 fork,代码贡献者 80+,是一个值得关注的前端项目。

2.JavaScript 中使用 Perspective

Perspective 的 JavaScript 库提供了一个由快速流数据引擎提供支持的可配置 UI。 开发人员能够为自由挑选需要的模块,并为用户提供一个干净的用户界面,从而通过它来分析数据。

Node.js 环境安装

Perspective 发布包含多个不同的构建,以便在大多数环境中轻松使用,无论是通过带或不带打包器的 NPM,还是通过 CDN 或 Assets 服务器的<script> 标签都可以使用。

根据最终选择的构建,由于同时存在 WebAssembly 和 WebWorkers,如果想获得最佳的初始加载时性能,Perspective 的安装过程可能比大多数纯 Javascript 库复杂一些。

要在 Node.js 服务器使用 Perspective,只需通过 NPM 安装即可。

yarn add @finos/perspective           

浏览器环境安装

在浏览器中使用 Perspective 会有一些差异。为了将 Perspective 用作 webpack(或其他打包器)应用程序中的依赖项,Perspective 的 WebAssembly 数据引擎可通过@finos/perspective 这个同一包来使用。 如果要使用 @finos/perspective-viewer UI,需要一些额外的包:

yarn add @finos/perspective @finos/perspective-viewer @finos/perspective-viewer-d3fc @finos/perspective-viewer-datagrid           

除了打包的 .js 脚本之外,Perspective 还要求浏览器能够访问 Perspective 的 .worker.js 和 .wasm 文件。 默认情况下,Perspective 将这些文件内联到 .js 脚本中,并在一个文件中交付。 这对运行时性能没有影响,但会增加资源加载时间。 大多数应用程序可以借助 Webpack 的插件,如 @finos/perspective-webpack-plugin 正确地打包这些文件 。

通过打包器

从浏览器应用程序的 NPM 模块导入 Perspective 时,开发者可以选择使用提供的打包器插件来管理 .worker.js 和 .wasm 文件。 这样做会提高应用程序的初始加载性能,因为 Perspective 的插件辅助打包版本:

  • 并行下载 .wasm 和 .js 文件。
  • 通过流式实例化增量编译 .wasm。
  • 整体包大小减少了约 20%(由于 bas64 编码开销)。

Perspective 带有打包插件,比如:

  • Webpack 通过 @finos/perspective-webpack-plugin
  • esbuild 通过 @finos/perspective-esbuild-plugin

Webpack 插件处理下载和打包 Perspective 的附加资源,并且很容易在 webpack.config 中设置:

const PerspectivePlugin = require("@finos/perspective-webpack-plugin");
module.exports = {
  entry: "./in.js",
  output: {
    filename: "out.js",
    path: "build",
  },
  plugins: [new PerspectivePlugin()],
};           

如果是 esbuild,可以使用 @finos/perspective-esbuild-plugin 模块。

const esbuild = require("esbuild");
const {
  PerspectiveEsbuildPlugin,
} = require("@finos/perspective-esbuild-plugin");

esbuild.build({
  entryPoints: ["src/index.js"],
  plugins: [PerspectiveEsbuildPlugin()],
  format: "esm",
  bundle: true,
  loader: {
    ".ttf": "file",
  },
});           

通过 esbuild 打包时,还必须设置以下内容:

  • 在应用的 <script> 标签中使用 type="module" 属性,因为这种构建模式仅通过 ES 模块支持。
  • 对 esm 版本 Perspective 使用直接导入,特别是 @finos/perspective/dsti/esm/perspective.js 和 @finos/perspective-viewer/dist/esm/perspective-viewer.js

3.Perspectives 数据绑定(Data Binding)的几种方式

应用程序开发人员可以选择客户端 (WebAssembly)、服务器 (Python/Node) 或客户端/服务器复制设计(Client/Server Replicated designs)来绑定数据,Web 应用程序可以根据需要使用这些设计中的一种或多种。 通过序列化到 Apache Arrow,可以有效地跨运行时复制和同步表。

仅限客户端(Client-only)

Perspective:不容错过的大型数据可视化利器!

Client-only 适用于静态数据集、用户提供的数据集以及简单的无服务器和只读 Web 应用程序。

Perspective 作为客户端浏览器 WebAssembly 库运行,数据集完全下载到客户端,所有计算和 UI 交互都在本地执行。 交互性能非常好,使用 WebAssembly 引擎实现近乎原生的运行时,加上 WebWorker 隔离以在浏览器内进行并行渲染。

在 Client-only 模式下,滚动和创建新视图等操作是响应式的, 但是缺点就是必须将整个数据集下载到客户端。 Perspective 不是典型的浏览器组件,Apache Arrow 格式的 1GB+ 数据集大小可以很好地加载并具有良好的交互性能。

Apache Arrow 是一种基于内存的列式数据结构,使大型数据系统能够快速有效地处理和传输数据,被 AWS Data Wrangler、python 库 Pandas、MATLAB 和许多其他技术使用。 Apache Arrow 的主要组件是内存中的列格式规范,用于在内存中表示类似表格的数据集

Client-only 的水平扩展不是问题,因为没有可扩展的并发状态,并且仅通过 WebAssembly 客户端使用客户端计算。 仅客户端视角可以支持与下载 Web 应用程序本身一样多的并发用户。 加载数据后,不需要服务器连接,所有操作都在客户端浏览器中进行,除初始加载外,不会给服务器带来额外的运行时成本。 这也意味着更新和编辑在浏览器客户端本地进行,并且在刷新页面时丢失。

由于仅客户端设计从创建客户端 Perspective 表开始,因此任何标准 Web 服务都可以以任何 Perspective 兼容的格式(JSON、CSV 或 Apache Arrow)提供数据。

const worker = perspective.worker();
const table = await worker.table(csv);

const viewer = document.createElement("perspective-viewer");
document.body.appendChild(viewer);
viewer.load(table);           

Server-only

在 Server-only 模式下,Perspective 数据集使用 Python 或 Node.js 服务器在内存中实例化,Web 应用程序虚拟连接。 具有非常好的初始加载性能,因为没有数据被下载。 如果配置分组依据和其他操作将按列并行运行。

Perspective:不容错过的大型数据可视化利器!

但在 Server-only 模式下交互性能很差,因为每次用户交互都必须分页服务器才能渲染。 滚动等操作响应速度较慢,并且可能会受到网络延迟的影响。 Web 应用程序必须通过 WebSocket 始终连接到服务器。 断开连接将阻止 UI 的任何交互、滚动等,而且不使用 WebAssembly。

只要连接打开,每个连接的浏览器都会影响服务器性能,进而影响每个客户端的交互性能。 这最终限制了该架构的水平可扩展性。 由于每个客户端都以虚拟方式读取 Perspective 表,因此编辑和更新等更改会自动反映到所有客户端,并在浏览器刷新时持续存在。 使用与之前设计相同的 Python 服务器,可以简单地跳过中间的 WebAssembly 表并将虚拟表直接传递给 load():

const websocket = perspective.websocket("ws://localhost:8080");
const server_table = websocket.open("my_table");
const viewer = document.createElement("perspective-viewer");
document.body.appendChild(viewer);
viewer.load(server_table);           

Client/Server Replicated

数据集使用 Python 或 Node.js Perspective 服务器在内存中实例化,Web 应用程序在浏览器的本地 WebAssembly 客户端中创建这些表的副本,并通过 Apache Arrow 高效地同步到服务器。 这种设计可以很好地适应额外的并发用户,因为浏览器只需要下载初始数据集和后续更新增量,而滚动、旋转、排序等操作则在客户端上执行。

Perspective:不容错过的大型数据可视化利器!

Python 服务器可以很好地利用额外的线程,因为 Perspective 将为几乎所有操作释放 GIL(Global Interpreter Lock,即 Python 的全局解释器锁)。 客户端的交互性能非常好,与仅客户端架构相同。 更新和编辑通过使用 websockets 和 Apache Arrow 的对应虚拟服务器在客户端之间无缝同步。

Python 和 Tornado 服务器的代码示例:

from perspective import Table, PerspectiveManager, PerspectiveTornadoHandler
table = Table(csv)
manager = PerspectiveManager()
manager.host("my_table", table)
routes = [(
    r"/websocket",
    PerspectiveTornadoHandler,
    {"manager": manager, "check_origin": True},
)]

app = tornado.web.Application(routes)
app.listen(8080)
loop = tornado.ioloop.IOLoop.current()
loop.start()           

在 Javascript 客户端, Perspective 通过 websocket 客户端与 Python 服务器交互,然后复制服务器端表。

const websocket = perspective.websocket("ws://localhost:8080");
const server_table = websocket.open("my_table");
const server_view = await server_table.view();

const worker = perspective.worker();
const client_table = await worker.table(server_view);

const viewer = document.createElement("perspective-viewer");
document.body.appendChild(viewer);
viewer.load(client_table);           

4.本文总结

本文主要和大家介绍下 Perspective,即一种交互式分析和数据可视化组件,特别适用于大型、流数据集。相信通过本文的阅读,大家对 Perspective 都会有一个初步的了解。

因为篇幅有限,文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!

参考资料

https://perspective.finos.org/docs/js/

https://perspective.finos.org/docs/server/

https://github.com/finos/perspective

https://perspective.finos.org/

继续阅读