はじめに
大規模データの可視化って、正直なところ結構大変なんですよ。
データが数万行、数十万行になってくると、一般的なチャートライブラリではもっさりしてきて、ユーザー体験が悪くなる。かといって、データを間引くと本来見えるべきパターンが見えなくなったりする。
そんな悩みを解決してくれるのがPerspectiveというライブラリです。GitHubで10,000スター以上、FINOS(Fintech Open Source Foundation)傘下のプロジェクトで、金融業界を中心に本番環境で使われています。
30代になって思うのは、「とりあえず動く」と「本番で使える」の間には大きな差があるということ。Perspectiveは後者なんですよね。
Perspectiveとは
Perspectiveは、大規模またはストリーミングデータセットに最適化された、インタラクティブな分析・データ可視化コンポーネントです。
もともとはJPモルガンが社内ツールとして開発し、2018年にオープンソース化されました。現在はOpenJS Foundation傘下のプロジェクトとして、活発に開発が続けられています。
主な特徴:
- 高速クエリエンジン: C++で書かれ、WebAssemblyにコンパイル
- ストリーミング対応: リアルタイムデータの更新に強い
- Apache Arrow対応: 列指向データフォーマットで効率的なデータ処理
- マルチプラットフォーム: JavaScript、Python、Rustで利用可能
特徴・メリット
1. WebAssemblyベースの高速処理
これ、意外と重要なポイントなんですけど、PerspectiveのクエリエンジンはC++で書かれてWebAssemblyにコンパイルされています。
つまり、ブラウザ上でネイティブに近い速度でデータ処理ができる。100万行のデータでもサクサク集計・フィルタリングできるのは、この技術のおかげです。
2. ストリーミングデータに強い
金融データや IoT センサーデータなど、リアルタイムで更新されるデータの可視化に特化しています。
従来のライブラリだと、データ更新のたびにチャート全体を再描画して重くなりがち。Perspectiveは差分更新に対応しているので、高頻度のデータ更新でもスムーズに動作します。
3. Apache Arrow対応
Apache Arrowは列指向のインメモリデータフォーマットで、データ処理の効率化に貢献しています。
個人的には、この辺の「データエンジニアリング的な基盤技術をしっかり押さえている」ところが信頼できるポイントですね。
4. フレームワーク非依存
Web Components(Custom Elements)として実装されているので、React、Vue、Angular、素のHTMLでも使えます。フレームワークに縛られないのはQOL上がりますね。
5. JupyterLab統合
データサイエンティストにはありがたい機能。JupyterLabウィジェットとして使えるので、ノートブック上でインタラクティブなデータ探索ができます。
インストール方法
JavaScript(ブラウザ)
npm install @finos/perspective @finos/perspective-viewer
CDNから直接読み込むこともできます:
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective/dist/cdn/perspective.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>
Python
pip install perspective-python
JupyterLabで使う場合:
pip install perspective-python[jupyter]
Rust
[dependencies]
perspective = "2.0"
基本的な使い方
HTMLでシンプルに使う
最も簡単な使い方はこんな感じ:
<!DOCTYPE html>
<html>
<head>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-d3fc/dist/cdn/perspective-viewer-d3fc.js"></script>
<style>
perspective-viewer {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<perspective-viewer id="viewer"></perspective-viewer>
<script type="module">
import perspective from "https://cdn.jsdelivr.net/npm/@finos/perspective/dist/cdn/perspective.js";
const viewer = document.getElementById("viewer");
const worker = await perspective.worker();
// サンプルデータ
const data = {
name: ["Alice", "Bob", "Charlie", "Diana", "Eve"],
age: [28, 35, 42, 31, 27],
department: ["Engineering", "Sales", "Engineering", "Marketing", "Sales"],
salary: [75000, 65000, 95000, 70000, 60000]
};
const table = await worker.table(data);
await viewer.load(table);
</script>
</body>
</html>
これだけで、フィルタリング、ソート、ピボットテーブル、チャート表示ができるビューワーが完成します。
Reactでの使用
import React, { useEffect, useRef } from 'react';
import perspective from '@finos/perspective';
import '@finos/perspective-viewer';
import '@finos/perspective-viewer-datagrid';
import '@finos/perspective-viewer-d3fc';
interface PerspectiveViewerProps {
data: Record<string, unknown[]>;
}
export const PerspectiveViewer: React.FC<PerspectiveViewerProps> = ({ data }) => {
const viewerRef = useRef<HTMLElement>(null);
const workerRef = useRef<perspective.Worker | null>(null);
const tableRef = useRef<perspective.Table | null>(null);
useEffect(() => {
const init = async () => {
if (!viewerRef.current) return;
workerRef.current = await perspective.worker();
tableRef.current = await workerRef.current.table(data);
const viewer = viewerRef.current as any;
await viewer.load(tableRef.current);
};
init();
return () => {
tableRef.current?.delete();
};
}, [data]);
return (
<perspective-viewer
ref={viewerRef}
style={{ width: '100%', height: '500px' }}
/>
);
};
ストリーミングデータの更新
リアルタイムデータの更新はこんな感じで書けます:
// テーブル作成時にインデックスを指定
const table = await worker.table(data, { index: "id" });
// データ更新(既存行はupsert、新規行は追加)
await table.update([
{ id: 1, price: 150.25, timestamp: Date.now() },
{ id: 2, price: 148.50, timestamp: Date.now() }
]);
// 行の削除
await table.remove([3, 4, 5]); // idが3, 4, 5の行を削除
Pythonでの使用
import perspective
import pandas as pd
# DataFrameからテーブル作成
df = pd.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"value": [100, 200, 300],
"category": ["A", "B", "A"]
})
table = perspective.Table(df)
# ビューの作成(集計設定)
view = table.view(
group_by=["category"],
aggregates={"value": "sum"}
)
# 結果を取得
result = view.to_df()
print(result)
実践的なユースケース
金融データダッシュボード
Perspectiveの出自が金融業界なので、株価やトレードデータの可視化には特に強いです。
// リアルタイム株価データの表示
const schema = {
symbol: "string",
price: "float",
volume: "integer",
timestamp: "datetime"
};
const table = await worker.table(schema, { index: "symbol" });
// WebSocketからデータ受信
ws.onmessage = async (event) => {
const data = JSON.parse(event.data);
await table.update(data);
};
// ビューワーの設定
await viewer.restore({
plugin: "Y Line",
group_by: ["timestamp"],
split_by: ["symbol"],
columns: ["price"]
});
IoTセンサーデータの監視
センサーからの大量データをリアルタイムで監視するダッシュボード。
const sensorTable = await worker.table({
sensor_id: "string",
temperature: "float",
humidity: "float",
timestamp: "datetime"
}, { index: "sensor_id" });
// 1秒ごとにデータ更新
setInterval(async () => {
const newData = await fetchSensorData();
await sensorTable.update(newData);
}, 1000);
ログ分析ツール
大量のログデータを集計・分析するツール。
const logTable = await worker.table({
timestamp: "datetime",
level: "string",
service: "string",
message: "string",
response_time: "float"
});
// CSVからデータ読み込み
const response = await fetch("/logs/access.csv");
const csv = await response.text();
await logTable.update(csv);
// エラーログの集計
await viewer.restore({
plugin: "Datagrid",
group_by: ["service", "level"],
aggregates: {
"timestamp": "count",
"response_time": "avg"
},
filter: [["level", "==", "ERROR"]]
});
Excelライクなピボットテーブル
ビジネスユーザー向けの分析ツールとして。
await viewer.restore({
plugin: "Datagrid",
group_by: ["region", "category"],
split_by: ["year"],
columns: ["sales"],
aggregates: {
"sales": "sum"
},
sort: [["sales", "desc"]]
});
ドラッグ&ドロップで列の配置を変えたり、フィルターをかけたりできるので、非エンジニアでも使いやすい。
他のライブラリとの比較
vs D3.js
D3は自由度が高いけど、ダッシュボード的なものを作るには記述量が多い。Perspectiveは「分析・可視化」に特化しているので、その用途なら圧倒的に効率が良い。
vs Chart.js / Recharts
これらは主に「チャートを描く」ことに特化。Perspectiveは「データの探索・分析」が目的なので、ピボットテーブルやフィルタリングの機能が充実している。大規模データの処理性能も段違い。
vs ag-Grid
ag-Gridはグリッド表示に強いけど、チャート機能は別ライセンス。Perspectiveはグリッドもチャートもオープンソースで使える。
まとめ
Perspectiveを使ってみて感じたこと:
- パフォーマンス: WebAssemblyのおかげで100万行でもサクサク
- 機能の充実度: ピボット、チャート、フィルターが標準装備
- リアルタイム対応: ストリーミングデータの可視化に強い
- 学習コスト: 基本的な使い方は簡単、細かいカスタマイズはドキュメント参照
- 信頼性: FINOS傘下で金融機関での実績あり
正直なところ、「大量データをインタラクティブに可視化したい」という要件なら、Perspective一択ですね。
特に金融、IoT、ログ分析など、データ量が多くてリアルタイム性が求められる領域では、他のライブラリでは実現が難しいパフォーマンスを出せます。
まだ日本語の情報は少ないですが、公式ドキュメントは充実しているので、興味がある人はぜひ試してみてください。