runmat-plot 0.0.17

GPU-accelerated and static plotting for RunMat with WGPU and Plotters
Documentation

RunMat Plot

RunMat Plot is a world-class interactive plotting library for Rust, designed to provide comprehensive 2D/3D plotting. It is built from the ground up for performance, featuring a GPU-accelerated rendering pipeline using wgpu, a modern theming system, and seamless integration with Jupyter notebooks.

As a core component of the RunMat project, it serves as the powerful handle-graphics engine for all visualization tasks.

Key Features

  • GPU-Accelerated Rendering: High-performance plotting powered by wgpu for fast, smooth, and interactive visualizations.
  • Comprehensive 2D Plots: Support for line plots, scatter plots, bar charts, and histograms with extensive styling options.
  • Advanced 3D Visualization: Create stunning 3D surface plots and point clouds with configurable colormaps and shading.
  • Interactive GUI: A feature-rich interactive window built with winit and egui, offering smooth camera controls, zooming, panning, and UI overlays.
  • Multi-Plot Figures: Combine multiple plot types in a single figure with automatic bounds computation, legends, and grid lines.
  • Language Compatibility: A familiar, language-agnostic API for quickly creating plots (e.g., plot(), surf(), scatter3()).
  • Jupyter Notebook Integration: Display plots directly in Jupyter notebooks as static images or interactive HTML widgets.
  • Modern Theming System: A professional and configurable styling system with beautiful presets like ModernDark.

Architecture

The runmat-plot crate is designed with a layered architecture to separate concerns, providing both high-level simplicity and low-level control.

  • src/core - The Rendering Engine: This is the heart of the library.

    • WgpuRenderer abstracts over wgpu to manage render pipelines, shaders, and GPU buffers.
    • Scene provides a scene graph to manage renderable objects, their transformations, and visibility.
    • Camera implements both orthographic (2D) and perspective (3D) cameras with interactive navigation controls.
    • PlotRenderer is a unified pipeline that handles rendering for both interactive windows and static exports, ensuring consistent output.
  • src/plots - High-Level Plot Types: This module defines the user-facing API for creating plots.

    • Figure is the main container for a visualization, managing multiple overlaid plots.
    • Structs like LinePlot, ScatterPlot, SurfacePlot, etc., encapsulate the data and styling for a specific plot type. They are responsible for generating RenderData (vertices, indices) to be consumed by the core renderer.
  • src/gui - Interactive Windowing: This module provides the interactive GUI.

    • PlotWindow is the main entry point, creating a winit window and managing the event loop.
    • PlotOverlay uses egui to draw UI elements (axes, grids, titles, controls) on top of the wgpu canvas.
    • thread_manager and native_window contain robust, cross-platform logic to handle GUI operations, especially the main-thread requirements on macOS.
  • src/styling - Theming & Appearance: This module controls the visual style.

    • PlotThemeConfig allows for complete customization of colors, fonts, and layout via RunMat's central configuration system (e.g., .runmat.yaml).
    • ModernDarkTheme provides a professional, out-of-the-box dark theme.

Crate Layout

The crate is organized to clearly separate rendering, plot logic, and UI.

runmat-plot/
├── Cargo.toml          # Dependencies and feature flags (gui, jupyter)
├── README.md           # This file
├── examples/           # Runnable examples (interactive_demo.rs, etc.)
├── shaders/            # WGSL shaders for GPU rendering pipelines
└── src/
    ├── core/           # Low-level rendering engine (WGPU, scene, camera)
    ├── data/           # Data processing, LOD, buffer management (TODO)
    ├── export/         # Static export to PNG, SVG, HTML (TODO)
    ├── gui/            # Interactive GUI window, controls, and UI overlays
    ├── jupyter/        # Jupyter Notebook integration
    ├── lib.rs          # Main library entry point and public API
    ├── plots/          # High-level plot types (LinePlot, SurfacePlot, etc.)
    ├── simple_plots.rs # Legacy static plotting with `plotters`
    └── styling/        # Theming, colors, and layout configuration

Usage Examples

1. Simple Line Plot

Create a figure, add a line plot, and prepare it for rendering.

use runmat_plot::plots::{Figure, LinePlot, LineStyle};
use glam::Vec4;

let x: Vec<f64> = (0..=100).map(|i| i as f64 * 0.1).collect();
let y: Vec<f64> = x.iter().map(|&x| x.sin()).collect();

let mut figure = Figure::new()
    .with_title("Sine Wave")
    .with_labels("X-axis", "Y-axis")
    .with_grid(true);

let line_plot = LinePlot::new(x, y)?
    .with_style(Vec4::new(0.35, 0.78, 0.48, 1.0), 2.0, LineStyle::Solid)
    .with_label("sin(x)");

figure.add_line_plot(line_plot);

2. Multi-Plot Figure

Overlay multiple plot types in a single figure for comprehensive visualizations.

use runmat_plot::plots::{Figure, LinePlot, ScatterPlot, BarChart, MarkerStyle};
use glam::Vec4;

let mut figure = Figure::new().with_title("Sales Data Analysis");

// Add a bar chart for monthly sales
let sales_bars = BarChart::new(
    vec!["Jan".to_string(), "Feb".to_string(), "Mar".to_string()],
    vec![120.0, 135.0, 155.0]
)?.with_label("Monthly Sales");

// Add a line plot for the sales trend
let trend_line = LinePlot::new(vec![0.0, 1.0, 2.0], vec![120.0, 135.0, 155.0])?
    .with_label("Sales Trend");

// Add a scatter plot for KPI targets
let kpi_points = ScatterPlot::new(vec![0.0, 1.0, 2.0], vec![125.0, 130.0, 160.0])?
    .with_style(Vec4::new(1.0, 0.3, 0.3, 1.0), 8.0, MarkerStyle::Star)
    .with_label("KPI Targets");

figure.add_bar_chart(sales_bars);
figure.add_line_plot(trend_line);
figure.add_scatter_plot(kpi_points);

3. 3D Surface Plot

Create a 3D surface plot from a mathematical function.

use runmat_plot::plots::{SurfacePlot, ColorMap, ShadingMode};

let surface = SurfacePlot::from_function(
    (-3.0, 3.0),
    (-3.0, 3.0),
    (50, 50),
    |x, y| (-(x*x + y*y)).exp() * 2.0 - 1.0 // Gaussian
).unwrap()
    .with_colormap(ColorMap::Viridis)
    .with_shading(ShadingMode::Smooth);

let mut figure = Figure::new().with_title("3D Gaussian Surface");
// Figure currently only supports 2D plots, but 3D integration is planned.

4. Interactive Plotting

Launch a GPU-accelerated interactive window to display a figure.

// This requires the "gui" feature
// Add to Cargo.toml: runmat-plot = { version = "...", features = ["gui"] }

#[cfg(feature = "gui")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ... create your figure as in the examples above ...
    let mut figure = Figure::new().with_title("Interactive Demo");
    // ... add plots to figure ...

    // Launch the interactive window
    runmat_plot::show_interactive_with_figure(&figure).await?;
    Ok(())
}

Current Status & Known Issues

runmat-plot is under active development. The core GPU-accelerated architecture is implemented and functional, but there are several important limitations to be aware of:

⚠️ Current Limitations

  • Triangle Rendering Issue (macOS Metal): Bar charts and filled 2D shapes currently render as thin lines instead of filled areas on macOS. This is a low-level WGPU/Metal triangle rasterization issue that affects the triangle rendering pipeline. Line plots work correctly.

    Status: Under investigation. The issue has been isolated to triangle primitive assembly in the Metal backend. All high-level geometry generation, vertex data, shaders, and draw calls are correct.

    Workaround: Line plots, scatter plots, and 3D point clouds work as expected. Bar charts will display but appear as outlines only.

  • Sequential Plotting: Opening multiple plot windows sequentially may cause EventLoop recreation errors on macOS due to winit limitations. The first plot window works correctly.

    Workaround: Restart the application between different plotting sessions.

  • Legacy Export Backend: Static PNG exports currently use a fallback plotters-based renderer, which may not match the interactive GPU rendering exactly.

✅ What Works

  • Interactive GUI: Full-featured interactive plotting windows with smooth navigation, zooming, and real-time controls
  • Line Plots: Complete 2D line plotting with multiple series, styling, and legends
  • Scatter Plots: 2D and 3D scatter plots with configurable markers and colors
  • 3D Point Clouds: High-performance 3D visualization with interactive camera controls
  • GPU Performance: Excellent rendering performance for large datasets via WGPU acceleration
  • Cross-Platform: Works on Windows, Linux, and macOS (with triangle rendering limitation)
  • Language Compatibility: Familiar plot(), scatter(), scatter3() function interface

Roadmap & TODOs

Active areas of development, in priority order:

  • 🔥 PRIORITY: Fix Triangle Rendering (macOS Metal): Resolve the triangle rasterization issue preventing filled shapes from rendering correctly. Investigation points to WGPU primitive topology or Metal driver interaction.

  • EventLoop Management: Implement robust sequential plotting support to eliminate EventLoop recreation errors.

  • Unified Static Export: Replace the legacy plotters-based backend in simple_plots.rs with a unified headless rendering mode using the wgpu engine. This will ensure that exported PNGs and SVGs are pixel-perfect matches of the interactive plots.

  • Complete Export Modules: Fully implement the src/export modules for high-quality vector (SVG, PDF) and web (HTML, interactive widgets) outputs.

  • Advanced Data Handling: Implement the src/data modules for optimized GPU buffer management, level-of-detail (LOD) for large datasets, and advanced geometry processing.

  • Volume Rendering: Implement the VolumePlot type for 3D volumetric data visualization.

  • Jupyter WebGL Widget: Complete the WebGL-based interactive widget for Jupyter to provide a fully interactive experience within notebooks, matching the native GUI.

  • Expanded Theming: Add more built-in themes and expand the customizability of the styling system.

  • 3D in Figures: Fully integrate 3D plots like SurfacePlot into the Figure system for multi-plot 3D scenes.


For Developers: If you're contributing to the triangle rendering fix, see the detailed technical investigation in the Git history. Key files: crates/runmat-plot/src/plots/bar.rs, crates/runmat-plot/src/core/plot_renderer.rs, and crates/runmat-plot/shaders/vertex/triangle.wgsl. The issue has been isolated to direct vertex drawing with PrimitiveTopology::TriangleList on Metal backend.