Pluot: Towards 'write once, run everywhere' visualization software
Source: arXiv:2605.14118 · Published 2026-05-13 · By Mark S. Keller, Nils Gehlenborg
TL;DR
This paper addresses the fragmentation in visualization software ecosystems, where developers must build separate implementations for static vs interactive plots, desktop vs web environments, and multiple programming languages. Pluot proposes a unified architecture that enables a single rendering function, implemented once in Rust, to run across various environments and languages (including Python and JavaScript), targeting both static and interactive visualizations. This approach leverages Rust and WebGPU for performant GPU-accelerated rendering and compiles to WebAssembly for web deployment. Pluot supports asynchronous data loading for scalability to large or out-of-core datasets and can output both bitmap (raster) and vector (SVG) graphics, bridging interactivity and publication quality.
The authors demonstrate Pluot on use cases including rendering millions of scatterplot points, multi-scale bioimaging, and GPU-accelerated histograms. They show how bindings enable execution in command-line tools, HTTP servers, web browsers, and desktop applications, supporting coordinated multiple views architectures without coupling to a specific UI framework. The result is a flexible, cross-platform visualization architecture that reduces code duplication and runtime overhead compared to prior language- or platform-specific toolkits.
Key findings
- Pluot's Rust core library compiles to binaries under 5MB for WebAssembly, enabling feasible web deployment (Section 4).
- Rendering millions of scatterplot points to bitmap graphics can be performed with interactive frame rates; tens of thousands of points are feasible in vector (SVG) output (Figure 2a).
- Support for asynchronous, lazy data loading allows partial data reads based on zoom level or filtering predicates, scaling to datasets larger than memory (DG3, Section 4.3).
- Pluot can generate bindings for multiple languages (Python, JavaScript) enabling execution of visualizations without requiring a web browser, avoiding overhead of server or browser automation tools (DG1, Section 4.1.1).
- GPU compute pipelines are used in histogram rendering to accelerate bin counting and visualization caching, leveraging WebGPU through Rust's layer-based API (Section 5.3).
- Pluot treats interactive visualizations as sequences of static frames re-rendered for each user interaction frame, simplifying the rendering model (Figure 1c).
- Pluot's rendering logic is decoupled from any UI or window management, allowing flexible integration into environments such as CLI, HTTP servers, or custom GUIs (DG6, Section 5.4).
- The architecture supports composable layers with programmable shaders and can target both bitmap and vector outputs, enabling both high-performance interactive displays and publication-quality figures (DG4, Section 4.2).
Methodology — deep read
Threat Model & Assumptions: While not a security paper, Pluot addresses challenges faced by visualization developers requiring cross-environment execution of visualizations. The assumed adversary is complexity and inefficiency arising from duplicated codebases and runtime overhead. Pluot assumes developers want a single rendering implementation callable from multiple languages and platforms without requiring a browser or server.
Data: The authors show example data from large-scale datasets, including a million-point scatterplot (UMAP projections from MNIST), multi-scale bioimaging data stored in OME-Zarr format, and large histogram data. Data loading is asynchronous, supporting out-of-core access via partial reads based on viewport extent and filtering criteria, implemented via the Zarr storage interface in Rust with cross-language bindings.
Architecture / Algorithm: Pluot’s core is a Rust library implementing rendering functions that return either raster bitmap pixel buffers or vector SVG strings. This library compiles to native binaries or WebAssembly (WASM) for the web. The rendering functions are stateless and functional, taking input data and parameters and returning output graphics bytes. Interactive plotting is handled by re-rendering sequences of static frames per animation or user interaction frame.
A layer-based API facilitates constructing plots from modular composable layers, ranging from low-level graphics primitives to high-level chart abstractions (e.g., AxisLayer builds on TextLayer and LineLayer). Layers can implement GPU compute shaders during a prepare stage, supporting data transformations and aggregation, with rendering during the draw stage. CPU fallbacks are supported if GPU unavailable. Cross-language language bindings (Python, JavaScript) are generated, together with interactive adapters that enable zoom, pan, hover, and click event handling.
Training / Development Regime: N/A for visualization system; development involves optimizing Rust code for performance and minimal WASM binary size. Memoization inspired by React's hook system caches data to avoid redundant computations or IO.
Evaluation Protocol: No formal quantitative benchmarks across baselines; demonstrations include (a) rendering million-point scatterplots at interactive rates with bitmap output, (b) multi-scale bioimaging data visualization similar to Viv, and (c) accelerated histogram calculations using GPU compute pipelines. Comparison with prior multi-ecosystem reuse approaches shows Pluot avoids overheads associated with browser automation or headless JS runtimes.
Reproducibility: The software is open source and available at https://pluot.dev, including Rust library, language bindings, and demos. Data used are publicly available or standard benchmarks (MNIST, OME-Zarr). Code to produce visuals shown in paper is presumably included or linkable.
Example end-to-end usage: A developer writes a plotting function in Rust that renders a scatterplot with a given dataset. The function exposes both bitmap and SVG outputs. They compile the Rust code to a WASM module with Python bindings. In a Python notebook, a user calls the bound plotting function, which returns PNG bytes asynchronously based on current zoom and data filtering. The interactive adapter forwards mouse events to the function in real-time, triggering re-rendering on pan or zoom. The bitmap output is displayed using a widget without requiring a browser, enabling seamless high-performance visualization reuse in Python and web contexts from one codebase.
Technical innovations
- Unified Rust-based rendering core compiling to both native and WebAssembly targets enables reusable visualization implementations across desktop, web, and multiple language bindings.
- Layer-based API supports both declarative grammar-of-graphics style and programmable shader-level control, simultaneously targeting bitmap (GPU-accelerated) and vector (SVG) graphics for interactivity and publication quality.
- Asynchronous lazy data loading integrated via cross-language bindings to enable out-of-core, partial data reads driven by visualization parameters, reducing redundant filtering logic across ecosystems.
- Interactive visualization modeled as sequences of static frames re-rendered on user input reduces complexity and allows simple rendering API decoupled from UI frameworks.
Datasets
- MNIST UMAP projection — 70,000 points — public dataset
- OME-Zarr multi-scale bioimaging data — multi-gigabyte images — Image Data Resource [29,41]
- Synthetic one million point dataset for histogram demonstration — internally generated
Baselines vs proposed
- Prior web reuse with headless JS runtimes: Slower and requires browser automation; Pluot achieves interactive performance without browser overhead.
- Pyodide/WebR: 3x-5x slower than native Python with large WASM bundles ~6.4MB; Pluot's WASM binary is under 5MB, enabling faster load times and smaller bundles.
- SciChart (closed-source C++): lacks vector output and Python/R bindings; Pluot supports both vector output and multi-language bindings.
Figures from the paper
Figures are reproduced from the source paper for academic discussion. Original copyright: the paper authors. See arXiv:2605.14118.

Fig 1: Pluot architecture. a) The status quo. Visualization developers often use different toolkits depending on whether a plot

Fig 2 (page 1).

Fig 3 (page 1).

Fig 4 (page 1).

Fig 2: Examples of graphics created with Pluot. a) Scatterplot
Limitations
- Limited set of visualization encoding types and interaction modalities implemented; requires extension for broader chart types.
- Learning curve for developers unfamiliar with Rust and WebGPU shader programming compared to higher-level languages.
- Current WebAssembly tooling limitations include glue code dependencies and restricted multithreading, complicating certain web operations.
- Size constraints of WASM binaries require careful dependency management, limiting the ability to incorporate some Rust crates.
- Does not yet address mobile or extended reality platforms, focusing on web and desktop environments.
- CPU fallbacks for GPU compute/render not yet fully implemented, limiting accessibility on GPU-less hardware.
Open questions / follow-ons
- Can Pluot be extended to fully support mobile and extended reality visualization platforms while maintaining the 'write once, run everywhere' architecture?
- What optimizations and tooling improvements can reduce WebAssembly binary sizes to allow integration of richer Rust crates without overhead?
- How can richer grammar-based visualization systems be integrated as frontends with Pluot as a rendering backend while preserving interoperability?
- What are the best patterns for composable interaction models beyond simple static-frame re-rendering to support complex, stateful visualizations?
Why it matters for bot defense
While not directly related to bot-defense or CAPTCHA systems, Pluot’s approach to building cross-platform, high-performance, and language-agnostic visualization rendering has parallels to anti-automation challenges, where code reuse and efficiency across heterogeneous client environments is crucial. CAPTCHA engineers may find value in Pluot’s methodology of writing performant rendering code once and deploying it across web and native contexts, facilitating consistent visual challenge generation and rendering in diverse environments. The asynchronous, lazy data loading techniques could inspire scalable dynamic imagery generation, and the decoupling from UI frameworks allows flexible integration into custom GUIs or browsers, relevant to CAPTCHA presentation layers.
Cite
@article{arxiv2605_14118,
title={ Pluot: Towards 'write once, run everywhere' visualization software },
author={ Mark S. Keller and Nils Gehlenborg },
journal={arXiv preprint arXiv:2605.14118},
year={ 2026 },
url={https://arxiv.org/abs/2605.14118}
}