Perspective is an interactive analytics and data visualization component, especially well-suited for large and streaming datasets. It features a fast, memory-efficient streaming query engine written in C++ and compiled for WebAssembly, with framework-agnostic user interface components and comprehensive APIs for JavaScript/TypeScript, Python, and Rust environments.
npm install @finos/perspective@finos/perspective-viewer - Web component UI@finos/perspective-react - React integration@finos/perspective-viewer-datagrid - Data grid plugin@finos/perspective-viewer-d3fc - Chart plugin@finos/perspective-jupyterlab - JupyterLab extensionBrowser Environment:
// Main Perspective engine
import perspective from "@finos/perspective";
// Web components and viewer
import "@finos/perspective-viewer";
import "@finos/perspective-viewer-datagrid";
import "@finos/perspective-viewer-d3fc";
// React components
import { PerspectiveViewer } from "@finos/perspective-react";Node.js Environment:
// Main Perspective engine (default auto-detects environment)
import perspective from "@finos/perspective";
// Explicit Node.js import
import perspective from "@finos/perspective/node";
// Server components
import { WebSocketServer, PerspectiveServer } from "@finos/perspective";CommonJS (Node.js):
const perspective = require("@finos/perspective");
const { WebSocketServer } = require("@finos/perspective");CDN (Browser):
<script src="https://unpkg.com/@finos/perspective/dist/cdn/perspective.js"></script>
<script src="https://unpkg.com/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>Core Data Engine:
import perspective from "@finos/perspective";
// Node.js: Direct table creation (synchronous client)
const table = await perspective.table([
{ name: "Alice", age: 25, active: true },
{ name: "Bob", age: 30, active: false },
]);
// Browser: Create Web Worker client
const client = await perspective.worker();
const table = await client.table([
{ name: "Alice", age: 25, active: true },
{ name: "Bob", age: 30, active: false },
]);
// Create a view with aggregation and filtering
const view = await table.view({
group_by: ["active"],
aggregates: { age: "mean" },
filter: [["age", ">", 20]],
});
// Export data
const data = await view.to_json();
console.log(data);
// Clean up resources
await view.delete();
await table.delete();Web Components (Browser):
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@finos/perspective/dist/cdn/perspective.js"></script>
<script src="https://unpkg.com/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>
<script src="https://unpkg.com/@finos/perspective-viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
</head>
<body>
<perspective-viewer id="viewer"></perspective-viewer>
<script>
const data = [
{ name: "Alice", age: 25, sales: 1000 },
{ name: "Bob", age: 30, sales: 1500 },
];
document.getElementById("viewer").load(perspective.table(data));
</script>
</body>
</html>React Integration:
import React from "react";
import { PerspectiveViewer } from "@finos/perspective-react";
import perspective from "@finos/perspective";
function App() {
const data = [
{ name: "Alice", age: 25, sales: 1000 },
{ name: "Bob", age: 30, sales: 1500 },
];
return (
<PerspectiveViewer
table={perspective.table(data)}
group_by={["name"]}
aggregates={{ sales: "sum" }}
/>
);
}Server-Side (Node.js):
import { WebSocketServer } from "@finos/perspective";
// Create WebSocket server with static assets
const server = new WebSocketServer({
port: 8080,
assets: ["./dist", "./public"],
});
console.log("Perspective server running on http://localhost:8080");Perspective is built around several key components:
Client creation and connection management for different environments and transport protocols.
// Browser Web Worker client
function worker(worker?: Promise<SharedWorker | ServiceWorker | Worker>): Promise<Client>;
// WebSocket client (browser and Node.js)
function websocket(url: string): Promise<Client>;
// Initialization functions (browser only)
function init_client(wasm: PerspectiveWasm, disable_stage_0?: boolean): void;
function init_server(wasm: PerspectiveWasm, disable_stage_0?: boolean): void;Core table functionality for creating, updating, and managing columnar data structures.
interface Client {
table(data: TableInitData, options?: TableInitOptions): Promise<Table>;
open_table(name: string): Promise<Table>;
get_hosted_table_names(): Promise<string[]>;
}
interface Table {
schema(): Promise<Schema>;
size(): Promise<number>;
update(data: TableInitData, options?: UpdateOptions): Promise<void>;
clear(): Promise<void>;
delete(options?: DeleteOptions): Promise<void>;
}Query interface providing aggregations, pivots, filtering, and data export capabilities.
interface Table {
view(config?: ViewConfigUpdate): Promise<View>;
}
interface View {
to_json(window?: ViewWindow): Promise<Record<string, any>[]>;
to_arrow(window?: ViewWindow): Promise<ArrayBuffer>;
to_csv(window?: ViewWindow): Promise<string>;
on_update(callback: Function, options?: OnUpdateOptions): Promise<number>;
delete(): Promise<void>;
}Server-side components for hosting Perspective engines and WebSocket communication (Node.js only).
class PerspectiveServer {
constructor(options?: PerspectiveServerOptions);
make_session(send_response: (buffer: Uint8Array) => Promise<void>): Promise<Session>;
}
class WebSocketServer {
constructor(options?: { port?: number; assets?: string[]; server?: PerspectiveServer });
close(): Promise<void>;
}// Data input formats
type TableInitData = string | ArrayBuffer | Record<string, unknown[]> | Record<string, unknown>[];
// Table configuration
interface TableInitOptions {
limit?: number;
index?: string;
name?: string;
format?: "json" | "columns" | "csv" | "arrow";
}
// Update operation options
interface UpdateOptions {
format?: "json" | "columns" | "csv" | "arrow";
port_id?: number;
}
// Delete operation options
interface DeleteOptions {
lazy?: boolean;
}
// View configuration
interface ViewConfigUpdate {
columns?: string[];
group_by?: string[];
split_by?: string[];
aggregates?: Record<string, string>;
sort?: [string, "asc" | "desc"][];
filter?: [string, string, any][];
expressions?: Record<string, string>;
}
// Update callback options
interface OnUpdateOptions {
mode?: "row";
}
// Update event data
interface OnUpdateData {
port_id: number;
delta?: ArrayBuffer;
}
// Schema definition
type Schema = Record<string, "boolean" | "date" | "datetime" | "float" | "integer" | "string">;
// Data window specification
interface ViewWindow {
start_row?: number;
end_row?: number;
start_col?: number;
end_col?: number;
}
// System information
interface SystemInfo {
server_used?: number;
server_heap?: number;
client_used?: number;
client_heap?: number;
timestamp?: number;
}
// WebAssembly module types
type PerspectiveWasm = ArrayBuffer | Response | WebAssembly.Module | Promise<ArrayBuffer | Response | Object>;
// Aggregation functions
type AggregateFunction =
| "abs sum" | "and" | "any" | "avg" | "count" | "distinct count"
| "dominant" | "first" | "high" | "last" | "low" | "max" | "mean"
| "median" | "min" | "or" | "pct sum parent" | "pct sum grand total"
| "stddev" | "sum" | "sum abs" | "sum not null" | "unique" | "var";
// Filter operators
type FilterOperator =
| "==" | "!=" | ">" | "<" | ">=" | "<="
| "begins with" | "ends with" | "contains" | "in" | "not in"
| "is null" | "is not null";