# Troubleshooting Guide

Complete guide to common issues, error messages, and performance expectations for ruviz.

## Common Issues

### Performance Issues

**Q: My 1K point plot takes 250ms, is this normal?**

A: **Yes!** This is "cold start" performance. The time breakdown:
- Font initialization: 50-100ms (cosmic-text system setup)
- Canvas setup: 20-50ms (memory allocation, DPI scaling)
- Rendering pipeline: 50-100ms (Skia initialization, theme application)
- File I/O: 30-50ms (PNG encoding, disk write)
- **Actual plotting: < 10ms** ✅

**Key Insight**: The system is optimized for large datasets where this overhead is amortized. For 100K points, total time is only 34.6ms because the fixed overhead becomes negligible.

**Solutions**:
- For single plots: 250ms is acceptable for publication-quality output
- For multiple plots: Create larger datasets to amortize overhead
- Future: Batch API will enable < 10ms per plot after warmup

**Q: My 100K point plot is slow**

A: Use `.auto_optimize()` to enable parallel rendering:
```rust
Plot::new()
    .line(&x, &y)
    .auto_optimize()  // Selects best backend automatically
    .save("plot.png")?;
```

Expected performance with auto-optimize:
- 100K points: ~35ms (2.9x faster than target) ✅
- 1M points: ~87ms (5.7x faster than target) ✅

**Q: How do I know which backend is being used?**

A: Backend selection is automatic with `.auto_optimize()`:
- < 1K points → Skia (simple, fast)
- 1K-100K points → Parallel (multi-threaded)
- > 100K points → GPU/DataShader (hardware accelerated)

You can also manually select:
```rust
use ruviz::core::BackendType;

Plot::new()
    .line(&x, &y)
    .backend(BackendType::Parallel)
    .save("plot.png")?;
```

### Rendering Issues

**Q: Fonts look different on different platforms**

A: ruviz uses system fonts by default. To ensure consistency:

**Option 1: Specify explicit fonts**
```rust
Plot::new()
    .title("My Plot")
    .title_font("Arial", 16.0)  // System font
    .save("plot.png")?;
```

**Option 2: Use open fonts (auto-downloaded)**
```rust
Plot::new()
    .title("My Plot")
    .title_font("Open Sans", 16.0)  // Downloaded from Google Fonts
    .save("plot.png")?;
```

**Option 3: Provide custom TTF**
```rust
Plot::new()
    .title("My Plot")
    .title_font_file(&Path::new("fonts/MyFont.ttf"), 16.0)
    .save("plot.png")?;
```

**Q: Text is rotated incorrectly**

A: This is a known limitation with complex Unicode. Workarounds:
- Use ASCII labels for axes when possible
- Simplify special characters in labels
- File a bug report with your specific Unicode case

**Q: Plot looks pixelated or low quality**

A: Increase DPI for publication-quality output:
```rust
Plot::new()
    .line(&x, &y)
    .dpi(300)  // IEEE publication standard
    .save("plot.png")?;
```

Standard DPI settings:
- 96 DPI: Screen display (default)
- 150 DPI: Presentations
- 300 DPI: IEEE publications, journals
- 600 DPI: High-resolution printing

For Typst text specifically:
- PNG output uses native 1x rasterized Typst text; higher DPI still increases overall output pixel density.
- SVG/PDF exports preserve vector text and are preferred for publication workflows.

### API Issues

**Q: Which backend should I use?**

A: **Always use `.auto_optimize()` unless you have specific requirements.** It automatically selects the optimal backend based on data size:

```rust
// Recommended - automatic backend selection
Plot::new()
    .line(&x, &y)
    .auto_optimize()
    .save("plot.png")?;
```

Backend decision overhead is negligible (< 142µs worst case).

**Q: Can I reuse a plot object?**

A: **No**. Plot uses a consuming API pattern. Each plot is rendered once via `.save()`:

```rust
// Wrong - plot is consumed by save()
let plot = Plot::new().line(&x, &y);
plot.save("plot1.png")?;  // Consumes plot
plot.save("plot2.png")?;  // ERROR: plot already consumed

// Correct - create separate Plot instances
Plot::new().line(&x, &y).save("plot1.png")?;
Plot::new().line(&x, &y).save("plot2.png")?;
```

**Q: How do I create multiple series on one plot?**

A: Chain `.line()`, `.scatter()`, or other plot methods:

```rust
let plot = Plot::new()
    .line(&x, &y1)
    .line(&x, &y2)
    .scatter(&x, &y3);

plot.save("multi_series.png")?;
```

**Q: Can I customize colors and styles?**

A: Yes, using themes and series customization:

```rust
// Use built-in themes
Plot::with_theme(Theme::publication())
    .line(&x, &y)
    .save("plot.png")?;

// Available themes: light(), dark(), minimal(), publication()
```

### Data Issues

**Q: My data has NaN or Inf values - will the plot work?**

A: No. Plotting will fail with invalid data. Filter first:

```rust
let x_clean: Vec<f64> = x.iter()
    .copied()
    .filter(|v| v.is_finite())
    .collect();
let y_clean: Vec<f64> = y.iter()
    .copied()
    .filter(|v| v.is_finite())
    .collect();

Plot::new()
    .line(&x_clean, &y_clean)
    .save("plot.png")?;
```

**Q: My x and y vectors have different lengths**

A: Plot will fail with `DataLengthMismatch`. Ensure equal lengths:

```rust
let min_len = x.len().min(y.len());
let x = &x[..min_len];
let y = &y[..min_len];

Plot::new().line(x, y).save("plot.png")?;
```

## Error Messages

### `EmptyDataSet`

**Cause**: Attempted to plot empty data vectors

**Example**:
```rust
let x: Vec<f64> = vec![];
let y: Vec<f64> = vec![];
Plot::new().line(&x, &y).save("plot.png")?;  // ERROR
```

**Solution**: Ensure your data vectors contain at least one point

```rust
if !x.is_empty() && !y.is_empty() {
    Plot::new().line(&x, &y).save("plot.png")?;
}
```

### `DataLengthMismatch`

**Cause**: x and y data have different lengths

**Example**:
```rust
let x = vec![1.0, 2.0, 3.0];
let y = vec![1.0, 2.0];  // Different length!
Plot::new().line(&x, &y).save("plot.png")?;  // ERROR
```

**Solution**: Ensure `x.len() == y.len()`

```rust
assert_eq!(x.len(), y.len(), "Data vectors must have equal length");
Plot::new().line(&x, &y).save("plot.png")?;
```

### `FontLoadingError`

**Cause**: Cannot find or load specified font

**Solution**:
1. Check font name spelling (case-sensitive)
2. Ensure font is installed on system
3. Try open fonts (auto-downloaded from Google Fonts)
4. Provide custom TTF file path

```rust
// If system font fails, try open font
Plot::new()
    .title("My Plot")
    .title_font("Open Sans", 16.0)  // Auto-downloads if not cached
    .save("plot.png")?;
```

### `RenderingError`

**Cause**: Internal rendering failure (canvas allocation, drawing operations)

**Common causes**:
- Insufficient memory for large canvas
- Invalid dimensions (width or height = 0)
- Disk write failure (permissions, disk full)

**Solution**:
- Check available memory for large plots
- Ensure output directory exists and is writable
- Verify dimensions are positive integers

### `InvalidDPI`

**Cause**: DPI value below minimum (72) or unreasonably high

**Solution**: Use standard DPI values:
```rust
Plot::new()
    .line(&x, &y)
    .dpi(300)  // Valid: 72-600 recommended
    .save("plot.png")?;
```

## Performance Expectations

### Verified Benchmark Results (Week 6)

| Dataset Size | Expected Time | Backend | vs Target |
|--------------|---------------|---------|-----------|
| 100 points | 250ms (cold) | Skia | N/A (cold start) |
| 1K points | 250ms (cold) | Skia | N/A (cold start) |
| 10K points | 50ms | Skia | Excellent |
| 100K points | **34.6ms** | Parallel | **2.9x faster** ✅ |
| 1M points | **87ms** | Parallel/DataShader | **5.7x faster** ✅ |

**Cold start**: First plot in application (font init overhead)
**Warm**: Subsequent plots (fonts cached)

### Throughput

**3.17 million elements/second** with auto-optimization enabled

### Auto-Optimization Overhead

Backend selection decision time: **< 142µs** (worst case)
- 100 points: 218 nanoseconds
- 1K points: 1.5 microseconds
- 100K points: 142 microseconds

**Conclusion**: Zero user-facing overhead

### Performance Best Practices

1. **Always use `.auto_optimize()` for datasets > 1K points**
2. **Batch multiple plots in single application** to amortize cold start
3. **Use appropriate plot types** (histogram faster than scatter for distributions)
4. **Profile before optimizing** - measure actual performance first

## Reporting Issues

When reporting performance or rendering issues, please include:

1. **ruviz version**
   ```bash
   cargo tree | grep ruviz
   ```

2. **Rust version**
   ```bash
   rustc --version
   ```

3. **Operating system and version**
   ```bash
   uname -a  # Linux/macOS
   # or System Information on Windows
   ```

4. **Dataset size**
   - Number of points
   - Data ranges (min/max values)

5. **Minimal reproducible example**
   ```rust
   use ruviz::prelude::*;

   fn main() -> Result<()> {
       let x = vec![/* your data */];
       let y = vec![/* your data */];

       Plot::new()
           .line(&x, &y)
           .save("plot.png")?;

       Ok(())
   }
   ```

6. **Expected vs actual behavior**
   - What did you expect to happen?
   - What actually happened?
   - Error messages (full stack trace if applicable)

### GitHub Issues

Report bugs and request features at:
https://github.com/ruviz/ruviz/issues

### Performance Issues

For performance problems, also include:
- Timing measurements (use `std::time::Instant`)
- System specifications (CPU cores, RAM)
- Whether `.auto_optimize()` was used

## Architecture Notes (for Advanced Users)

### Why is cold start 250ms?

ruviz uses a **one-shot rendering API** where every `.save()` call initializes everything from scratch. This design ensures:
- Thread safety (no global state)
- Predictable behavior (no hidden state)
- Simple API (no context management required)

**Trade-off**: Fixed overhead dominates small dataset performance but becomes negligible for large datasets.

**Future work**: Batch rendering API will enable < 10ms per plot after initial warmup.

### Backend Selection Algorithm

Auto-optimize uses these heuristics:
- < 1,000 points → Skia (simple rendering pipeline)
- 1,000-100,000 points → Parallel (multi-threaded)
- > 100,000 points → GPU/DataShader (hardware accelerated)

Thresholds are based on empirical benchmarking across diverse hardware.

### Memory Usage

Typical memory usage: < 2x data size
- 100K points (1.6MB data) → < 3.2MB peak memory
- Efficient buffer pooling reduces allocations
- Automatic cleanup on Plot drop

## FAQ

**Q: Is ruviz production-ready?**

A: Yes! Week 6 benchmarks show performance exceeding all targets by 2.9-5.7x. Property-based testing (Week 8) validates robustness.

**Q: Can I use ruviz in web applications (WASM)?**

A: WASM support is planned but not yet implemented. Follow GitHub issues for updates.

**Q: Does ruviz support interactive plots?**

A: Not currently. ruviz focuses on static, publication-quality output. Interactive features are on the roadmap.

**Q: How does ruviz compare to matplotlib/plotly?**

A: ruviz is **pure Rust**, with 2.9-5.7x faster rendering for large datasets. It prioritizes performance and type safety over extensive features.

**Q: Can I contribute to ruviz?**

A: Yes! See CONTRIBUTING.md for guidelines. We welcome bug reports, feature requests, and code contributions.
