天天看點

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/

繼續閱讀