FAQ
Installation
Python installation fails on Windows
Python wheels are published for supported Python versions and platforms. On Windows, ensure you have a compatible Python version and architecture. Install with:
pip install perspective-python
If you encounter C++ binding errors or link errors, make sure you are using a
supported Python version and that your pip is up to date. Pre-built wheels
eliminate the need for a C++ compiler in most cases.
Python import perspective fails with ImportError or undefined symbol
This typically happens when the C++ shared library (libpsp.so) cannot be found
or was built against a different Python version. Ensure your Python version
matches the installed wheel. On Linux, verify that required system libraries are
present. If you see errors about libpsp.so or undefined symbols, try
reinstalling in a clean virtual environment.
Python installation fails on macOS
On Apple Silicon (M1/M2/M3), make sure you are using a native ARM Python build,
not one running under Rosetta. The published wheels include aarch64 variants
for supported platforms.
How do I install Perspective in a Docker container?
Perspective’s Python wheels are built against manylinux_2_28 containers (see
.github/workflows/build.yaml), so they
are compatible with most Linux distributions based on glibc 2.28+ (e.g., Debian
10+, Ubuntu 20.04+, RHEL 8+). Use a compatible base image:
FROM python:3.12-slim
RUN pip install perspective-python
Alpine Linux uses musl instead of glibc and is not compatible with the published wheels.
JavaScript Bundling
How do I use Perspective with Vite, Webpack, or esbuild?
Perspective no longer exports bundler plugins. Instead, you must manually bootstrap the WASM binaries using your bundler’s asset handling. See Importing with or without a bundler for complete examples for Vite, Webpack, esbuild, CDN, and inline builds.
Framework Integration
How do I use Perspective with React?
Perspective provides a dedicated React component. You must also still initialize Perspective’s WebAssembly as per your bundler — see Importing with or without a bundler.
How do I use Perspective with Next.js?
Perspective relies on Web Workers and WASM, which require client-side rendering.
Use dynamic imports with ssr: false in Next.js to load Perspective components
only on the client.
How do I use Perspective with Vue.js/Angular/etc?
As a standard Web Component, <perspective-viewer> works in most JavaScript web
frameworks directly via standard HTML/DOM APIs, but does not have dedicated
integration libraries for these frameworks.
Expressions
How do I create computed/expression columns?
Use the expressions config option
in your View to define new columns with ExprTK syntax, which must then be
used somewhere else in your config (like columns) to actually be visible &
calculated. In <perspective-viewer>, expression columns can be created from
the UI column sidebar by clicking the “New Column” button.
Can I reference one expression column from another?
No, you must duplicate calculations that are shared between expression columns.
Can I do date arithmetic in expressions?
Yes, but they must be converted to float values first (integer is an i32
which is too small). See
Expressions.
Can I do rolling sums or cumulative calculations?
Not in Perspective’s built-in engine, but as an alternative, DuckDB supports
rolling and cumulative sums via WINDOW functions,
and DuckDB now has
native Perspective Virtual Server support
which allows arbitrary DuckDB queries (as a TABLE or VIEW) to be
<perspective-viewer> Tables.
Filters
Can I compose filters with OR logic?
Perspective filters are composed with AND logic by default. As an alternative, you can use expression columns to create a boolean column that encodes your OR logic (or any arbitrary multi-column predicate), then filter on that column:
const view = await table.view({
expressions: {
or_filter:
"if (\"State\" == 'Texas') true; else if (\"State\" == 'California') true; else false",
},
filter: [["or_filter", "==", true]],
});
How do I update filters programmatically?
Set the
filter
property on a View config, or use the <perspective-viewer>
.restore() method to update filters
at runtime.
Does date filtering support ranges?
Date columns can be
filtered with
comparison operators (>, <, >=, <=) to achieve range-based filtering.
Apply two filters on the same date column for a range.
JupyterLab
PerspectiveWidget is not loading in JupyterLab
See the PerspectiveWidget guide for full
setup details. Ensure the JupyterLab extension version matches your
perspective-python version. Make sure you are using a compatible JupyterLab
for your Perspective version (JupyterLab 4+ currently).
Check that the extension is enabled with jupyter labextension list.
Memory and Performance
Perspective has a memory leak
Maybe, but please review the
Cleaning up resources docs carefully before
opening an Issue reporting it (and of course review
CONTRIBUTING.md
before opening any Issue). Ensure you call .delete() on Views, Tables, and
<perspective-viewer> instances when they are no longer needed, in reverse
dependency order.
How many rows can Perspective’s built-in engine handle?
Perspective is designed for large datasets and can handle millions of rows
depending on the number of columns and available memory. Performance also
significantly depends on column types ("string" being slower and larger than
other types due to dictionary interning).
For larger datasets or out-of-memory virtualized datasets, see Virtual Servers.
How do I control threading in perspective-python?
The Python library uses a thread pool internally. For advanced threading control, consult the multithreading documentation.
Theming and Styling
How do I enable dark theme?
Import themes.css (see Theming) and set the
theme via restore():
await viewer.restore({ theme: "Pro Dark" });
Or import just the dark theme directly:
import "@perspective-dev/viewer/dist/css/pro-dark.css";
Can I create a custom cell renderer for the datagrid?
The datagrid plugin supports custom styling via
column_config
and CSS custom properties, but custom cell renderers require building a custom
plugin.
How do I customize chart colors?
Chart colors can be customized via
CSS custom properties on the
<perspective-viewer> element.
Streaming and Real-Time Updates
How do I stream data into a Perspective table?
Use table.update() to push new
data incrementally. For indexed tables,
updates with matching index values will replace existing rows.
table.update() raises “No Running Event Loop”
Perspective 3+ is now threadsafe by default and no longer requires special loop integration.
How do I listen for data updates?
Use view.on_update() to register a callback that fires when the underlying
table data changes. See
Listening for events and
Advanced View Operations.
Server Architecture
What is the difference between Client-only, Client/Server, and Server-only modes?
- Client-only: The Perspective engine runs entirely in the browser via WASM. Best for small to medium datasets.
- Client/Server (replicated): Data is hosted on a server and replicated to the client. The client has a full copy and performs queries locally.
- Server-only: All queries are executed on the server. The client only renders results. Best for very large datasets.
See Data Architecture for detailed explanations of each mode.
How do I set up WebSocket authentication?
The WebSocketServer does not include
built-in authentication. Implement authentication at the transport layer (e.g.,
via middleware in your HTTP server) before the WebSocket upgrade. For more
complex needs, WebSocketServer is a simple example server based on the
node:http module which can serve as a starting point for a custom server.
Can I bind Perspective to a database?
Perspective supports Virtual Servers that proxy queries to external data sources, with built-in implementations for e.g. DuckDB.
Aggregation
Can I apply multiple aggregates to the same column?
Yes, by creating a duplicate/alias for your column via
expressions:
await viewer.restore({
columns: ["Sales", "Sales 2"],
expresions: { "Sales 2": '"Sales"' },
aggregate: {
Sales: "sum",
"Sales 2": "avg",
},
});
Can I compute a ratio between aggregated columns?
Use expression columns on an aggregated View to compute ratios. Define an expression that divides one column by another.
Data Loading and Arrow
How do I load Apache Arrow data into Perspective?
Perspective natively accepts
Apache Arrow format. Pass an
ArrayBuffer containing Arrow IPC data directly to table() or
table.update().
What data formats does Perspective accept?
Perspective accepts (see Loading data):
- JavaScript: JSON (row-oriented or column-oriented objects), CSV strings,
Apache Arrow
ArrayBuffer - Python:
dict,list,pandas.DataFrame,pyarrow.Table, CSV strings, Apache Arrow bytes
CSV update fails but CSV creation works
When updating a table created with a schema, ensure the CSV column names and types match the schema exactly. Mismatched column names or types will cause update failures.
Export
Can I export the viewer to HTML, PNG or PDF?
HTML and PNG exports are available via viewer.export("html") and
viewer.export("png"), respectively. For PDF, render the viewer and use browser
or headless browser screenshot capabilities.
Can I export data to Excel?
Perspective does not have built-in Excel export. Export data via
view.to_csv(), view.to_json(), or view.to_arrow() (see
Serializing data) and convert to Excel
using a library like xlsx (JavaScript) or openpyxl (Python).
How do I copy data from a cell or row?
Use the "text" export mode when data is selected:
await viewer.export("text").
Table Operations
table.remove() does not update the viewer
The remove() method requires an
indexed table. Ensure your table was created
with an index option, and pass the index values to remove.
Viewer Configuration
How do I save and restore the viewer state?
Use
viewer.save() and viewer.restore()
to serialize and deserialize the full viewer configuration.
Can I hide the configuration panel?
The settings panel can be toggled programmatically via
await viewer.restore({ settings: true }).
Can I collapse row groups by default?
Row group expansion state is not persisted or configurable via the API by
default, but can be closed imperatively via
view.set_depth().
Internationalization
Can I change the UI language?
Perspective’s UI text is defined via CSS variables, which can be customized per theme. See the Icons and Translation section of the theming guide for details.
Rust
How do I build Perspective from Rust?
See the Getting Started guide for Rust. The Rust crate wraps
the C++ engine and requires a C++ toolchain. You need cmake installed and on
your path to build the engine.
Miscellaneous
Can I use Perspective without <perspective-viewer>?
Yes. The perspective library (data engine) can be used independently for
server-side data processing without any UI. Use
table() and view() directly to query data.
Can I use Perspective in Pyodide?
There is an emscripten wheel published via Releases, but it must be downloaded and hosted manually and is only built for specific pyodide versions.
How do I handle row selection events?
Listen for
perspective-click and perspective-select
events on the <perspective-viewer> element.