8 releases

0.2.7 Dec 3, 2025
0.2.6 Nov 25, 2025
0.0.17 Oct 15, 2025

#234 in GUI

43 downloads per month
Used in 8 crates (3 directly)

MIT license

430KB
10K SLoC

RunMat Plot

RunMat Plot is the in-progress visualization layer for the RunMat pre-release. Simple 2D line and scatter plots run today on the GPU-backed renderer, while filled shapes, advanced 3D views, and polished exports are still being built. The focus is delivering fast, lightweight visuals for early adopters while the broader plotting surface takes shape.

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

Key Features (Pre-release)

  • GPU-Accelerated Rendering: The current builds use wgpu for fast 2D line/scatter plots; more chart types are under active development.
  • Foundational 2D Plots: Line and scatter plots work today. Bar charts, histograms, and other filled-shape plots are stubbed but not yet production-ready.
  • Planned 3D Visualization: Surface plots and point clouds are on the roadmap; 3D rendering paths exist in the codebase but are not feature-complete.
  • Interactive GUI (Preview): The winit/egui window handles basic zoom and pan. Advanced camera controls and multiple plot management are still being polished.
  • Multi-Plot Figures (Roadmap): Figure composition APIs exist, but mixed plot layouts are experimental and will stabilize post pre-release.
  • Language Compatibility: MATLAB-style APIs (plot, scatter, future surf) keep syntax familiar even as capabilities expand.
  • Jupyter Notebook Integration: Static image export works today; interactive HTML widgets are planned.
  • Modern Theming System: The ModernDark preset is available now, with broader theming to follow as features land.

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.

Dependencies

~28–75MB
~1.5M SLoC