# ruviz

**High-performance 2D plotting library for Rust combining matplotlib's ease-of-use with Makie's performance.**

[![Crates.io](https://img.shields.io/crates/v/ruviz)](https://crates.io/crates/ruviz)
[![Documentation](https://docs.rs/ruviz/badge.svg)](https://docs.rs/ruviz)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue)](LICENSE-MIT)
[![CI](https://github.com/Ameyanagi/ruviz/actions/workflows/ci.yml/badge.svg)](https://github.com/Ameyanagi/ruviz/actions/workflows/ci.yml)

## Release Notes

- [Changelog](CHANGELOG.md)
- [Release Notes Index](docs/releases/README.md)
- [Latest Release Notes (v0.1.4)](docs/releases/v0.1.4.md)

## Quick Start

```rust
use ruviz::prelude::*;

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

Plot::new()
    .line(&x, &y)
    .title("Quadratic Function")
    .xlabel("x")
    .ylabel("y = x^2")
    .save("plot.png")?;
```

Need typeset math labels? See [Typst Text Mode](#typst-text-mode) below.

![Example Plot](assets/readme_example.png)

## Features

### 🛡️ Safety & Quality
- **Zero unsafe** in public API
- Strong type system prevents runtime errors
- Comprehensive error handling with `Result` types
- Memory-safe by design

### 📊 Plot Types
**Basic**: Line, Scatter, Bar, Histogram, Box Plot, Heatmap
**Distribution**: Violin, KDE, ECDF
**Composition**: Pie, Donut
**Continuous**: Contour
**Polar**: Polar Plot, Radar Chart
**Error**: Error Bars (symmetric/asymmetric)

### 🎨 Publication Quality
- **High-DPI export**: 72, 96, 300, 600 DPI for print
- **Multiple formats**: PNG, SVG *(SVG in development)*
- **Professional themes**: Light, Dark, Publication, Seaborn-style
- **Custom styling**: Colors, fonts, markers, line styles
- **International text**: Full UTF-8 support (Japanese, Chinese, Korean, etc.) with cosmic-text

### ⚡ Advanced Features
- **Simple API**: One-liner functions for quick plotting
- **Parallel rendering**: Multi-threaded for large datasets (rayon)
- **GPU acceleration**: Optional wgpu backend (experimental)
- **Interactive plots**: Optional winit window integration
- **Animation**: GIF export with `record!` macro and easing functions
- **Cross-platform**: Linux, macOS, Windows

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
ruviz = "0.1.4"
```

### Feature Flags

Choose features based on your needs:

```toml
[dependencies]
ruviz = { version = "0.1.4", features = ["parallel", "simd"] }
```

| Feature | Description | Use When |
|---------|-------------|----------|
| `default` | ndarray + parallel | General use |
| `parallel` | Multi-threaded rendering | Large datasets |
| `simd` | Vectorized transforms | Performance-critical |
| `animation` | GIF animation export | Animated plots |
| `gpu` | GPU acceleration (experimental) | Real-time rendering |
| `interactive` | winit window support | Interactive plots |
| `ndarray_support` | ndarray types | Scientific computing |
| `nalgebra_support` | nalgebra vectors/matrices | Linear algebra workloads |
| `polars_support` | DataFrame support | Data analysis |
| `pdf` | PDF export | Publication output |
| `typst-math` | Typst text engine for all plot text | Math-heavy publication plots |
| `full` | All features | Power users |

For minimal builds: `default-features = false`

### Typst Text Mode

Enable Typst text rendering:

```toml
[dependencies]
ruviz = { version = "0.1.4", features = ["typst-math"] }
```

Use `.typst(true)` on a plot to render all static text surfaces (titles, axis labels, ticks,
legend labels, and annotations) through Typst:

```rust
use ruviz::prelude::*;

let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.1).collect();
let y: Vec<f64> = x.iter().map(|&v| (-v).exp()).collect();

Plot::new()
    .line(&x, &y)
    .title("$f(x) = e^(-x)$")
    .xlabel("$x$")
    .ylabel("$f(x)$")
    .typst(true)
    .save("typst_plot.png")?;
```

Notes:
- Invalid Typst snippets fail render/export with a `TypstError`.
- If `typst-math` is not enabled, `.typst(true)` returns `FeatureNotEnabled` at render/export.
- Migration: `.latex(true)` has been removed; use `.typst(true)` instead.
- Typst text in PNG output is rasterized at native output scale (1x).
- For maximum text sharpness, prefer higher DPI (for example `.dpi(300)`) or vector export (`.export_svg(...)` / `.save_pdf(...)`).

## Examples

### Basic Line Plot

```rust
use ruviz::prelude::*;

let x = vec![0.0, 1.0, 2.0, 3.0, 4.0];
let y = vec![0.0, 1.0, 4.0, 9.0, 16.0];

Plot::new()
    .line(&x, &y)
    .title("My First Plot")
    .save("output.png")?;
```

### Multi-Series with Styling

```rust
use ruviz::prelude::*;

let x = vec![0.0, 1.0, 2.0, 3.0, 4.0];

Plot::new()
    .line(&x, &x.iter().map(|&x| x).collect::<Vec<_>>())
    .label("Linear")
    .line(&x, &x.iter().map(|&x| x * x).collect::<Vec<_>>())
    .label("Quadratic")
    .line(&x, &x.iter().map(|&x| x.powi(3)).collect::<Vec<_>>())
    .label("Cubic")
    .title("Polynomial Functions")
    .xlabel("x")
    .ylabel("y")
    .theme(Theme::publication())
    .save("polynomials.png")?;
```

### Grouped Series with Shared Styling

```rust
use ruviz::prelude::*;

let x = vec![0.0, 1.0, 2.0, 3.0];
let a = vec![0.0, 1.0, 2.0, 3.0];
let b = vec![0.0, 1.5, 3.0, 4.5];
let baseline = vec![0.2, 1.2, 2.2, 3.2];

Plot::new()
    .group(|g| {
        g.group_label("Sensors")
            .line_style(LineStyle::Dashed)
            .line_width(2.0)
            .color(Color::from_hex("#1E88E5").unwrap())
            .line(&x, &a)
            .line(&x, &b)
    })
    .line(&x, &baseline)
    .label("Baseline")
    .legend(Position::TopRight)
    .save("grouped_series.png")?;
```

### Subplots

```rust
use ruviz::prelude::*;

let plot1 = Plot::new().line(&x, &y).title("Line").end_series();
let plot2 = Plot::new().scatter(&x, &y).title("Scatter").end_series();
let plot3 = Plot::new().bar(&["A", "B", "C"], &[1.0, 2.0, 3.0]).title("Bar").end_series();
let plot4 = Plot::new().histogram(&data).title("Histogram").end_series();

subplots(2, 2, 800, 600)?
    .suptitle("Scientific Analysis")
    .subplot(0, 0, plot1)?
    .subplot(0, 1, plot2)?
    .subplot(1, 0, plot3)?
    .subplot(1, 1, plot4)?
    .save("subplots.png")?;
```

### Large Dataset

```rust
use ruviz::prelude::*;

// 100K points with parallel rendering (enable "parallel" feature)
let x: Vec<f64> = (0..100_000).map(|i| i as f64).collect();
let y: Vec<f64> = x.iter().map(|&x| x.sin()).collect();

Plot::new()
    .line(&x, &y)
    .title("Large Dataset")
    .save("large.png")?;
```

### Animation

```rust
use ruviz::prelude::*;
use ruviz::animation::RecordConfig;
use ruviz::record;

let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
let config = RecordConfig::new().max_resolution(800, 600).framerate(30);

record!(
    "wave.gif",
    2 secs,
    config: config,
    |t| {
        let phase = t.time * 2.0 * std::f64::consts::PI;
        let y: Vec<f64> = x.iter().map(|&xi| (xi + phase).sin()).collect();
        Plot::new()
            .line(&x, &y)
            .title(format!("Wave Animation (t={:.2}s)", t.time))
            .xlim(0.0, 10.0)
            .ylim(-1.5, 1.5)
    }
)?;
```

![Animation Example](docs/images/animation_sine_wave.gif)

### Typst Text Example

Run:

```bash
cargo run --example doc_typst_text --features typst-math
```

## Documentation

- **[User Guide](docs/guide/README.md)** - Comprehensive tutorials and examples
- **[API Documentation](https://docs.rs/ruviz)** - Complete API reference
- **[Gallery](docs/gallery/README.md)** - Visual examples showcase
- **[Migration from matplotlib](docs/migration/matplotlib.md)** - For Python users
- **[Migration from seaborn](docs/migration/seaborn.md)** - Statistical plots
- **[Performance Guide](docs/performance/PERFORMANCE.md)** - Optimization techniques

## Why ruviz?

Rust's plotting ecosystem has several options, but each has trade-offs:

| Library | Approach | Limitation |
|---------|----------|------------|
| [plotters](https://github.com/plotters-rs/plotters) | Low-level drawing API | Verbose, requires boilerplate for common plots |
| [plotly.rs](https://github.com/plotly/plotly.rs) | JavaScript bindings | Requires JS runtime, web-focused |
| [plotpy](https://github.com/cpmech/plotpy) | Python/matplotlib wrapper | Requires Python installed |

**ruviz fills the gap** with:
- **High-level API**: matplotlib-style `Plot::new().line().title().save()` - no boilerplate
- **Pure Rust**: No Python, JavaScript, or external runtime needed
- **Built-in plot types**: 15+ plot types out of the box (violin, KDE, radar, etc.)
- **Publication quality**: Professional themes and high-DPI export

```rust
// plotters: ~30 lines for a simple line plot
// ruviz: 4 lines
Plot::new()
    .line(&x, &y)
    .title("My Plot")
    .save("plot.png")?;
```

## Contributing

Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

### Development

```bash
# Clone repository
git clone https://github.com/Ameyanagi/ruviz.git
cd ruviz

# Setup pre-commit hooks (recommended)
make setup-hooks

# Run code quality checks
make check

# Run tests
cargo test --all-features

# Run examples
cargo run --example basic_example --release

# Run benchmarks
cargo bench --all-features
```

The pre-commit hooks will automatically run `cargo fmt --check` and `cargo clippy` before each commit to ensure code quality.

## Roadmap

- [x] Core plot types (line, scatter, bar, histogram, boxplot, heatmap)
- [x] Parallel rendering
- [x] SIMD optimization
- [x] GPU acceleration (experimental)
- [x] Professional themes
- [x] Subplots and multi-panel figures
- [x] Distribution plots: Violin, KDE, ECDF
- [x] Composition plots: Pie, Donut
- [x] Continuous plots: Contour
- [x] Polar plots: Polar, Radar
- [x] Error bars
- [ ] More plot types: Area, Hexbin, Step, Stem (v0.2)
- [ ] Regression plots: Regplot, Residplot (v0.2)
- [ ] Composite plots: Joint, Pair (v0.2)
- [ ] SVG export (v0.2)
- [ ] Interactive plots with zoom/pan (v0.3)
- [ ] 3D plotting (v1.0+)

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

## Acknowledgments

- Inspired by [matplotlib](https://matplotlib.org/), [seaborn](https://seaborn.pydata.org/), and [Makie.jl](https://makie.juliaplots.org/)
- Built with [tiny-skia](https://github.com/RazrFalcon/tiny-skia) for rendering
- Text rendering by [cosmic-text](https://github.com/pop-os/cosmic-text)
- Thanks to the Rust community for excellent crates and feedback

---

**Status**: v0.1.4 - Early development, API may change. Production use at your own risk.

**Support**: [Open an issue](https://github.com/Ameyanagi/ruviz/issues) or [start a discussion](https://github.com/Ameyanagi/ruviz/discussions)
