# Migrating from matplotlib to ruviz
Complete guide for Python/matplotlib users transitioning to ruviz.
## Quick Comparison
### Basic Line Plot
**Python/matplotlib**:
```python
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.title('Sine Wave')
plt.xlabel('X axis')
plt.ylabel('Y axis')
plt.grid(True)
plt.savefig('plot.png', dpi=300)
plt.show()
```
**Rust/ruviz**:
```rust
use ruviz::prelude::*;
Plot::new()
.line(&x, &y)
.title("Sine Wave")
.xlabel("X axis")
.ylabel("Y axis")
.grid(true)
.save("plot.png")?;
```
## API Translation Table
| `plt.plot(x, y)` | `Plot::new().line(&x, &y)` | Builder pattern |
| `plt.scatter(x, y)` | `Plot::new().scatter(&x, &y)` | |
| `plt.bar(x, y)` | `Plot::new().bar(&categories, &values)` | |
| `plt.hist(data)` | `Plot::new().histogram(&data, None)` | |
| `plt.title('text')` | `.title("text")` | Method chaining |
| `plt.xlabel('text')` | `.xlabel("text")` | |
| `plt.ylabel('text')` | `.ylabel("text")` | |
| `plt.legend()` | `.legend(Position::TopRight)` | Explicit position |
| `plt.grid(True)` | `.grid(true)` | |
| `plt.xlim(0, 10)` | `.xlim(0.0, 10.0)` | |
| `plt.ylim(0, 10)` | `.ylim(0.0, 10.0)` | |
| `plt.savefig('file.png')` | `.save("file.png")?` | Returns Result |
| `plt.savefig('file.png', dpi=300)` | `.dpi(300).save("file.png")?` | |
| `plt.show()` | N/A | Save to file instead |
## Common Patterns
### Multiple Series
**matplotlib**:
```python
plt.plot(x, y1, label='Linear')
plt.plot(x, y2, label='Quadratic')
plt.plot(x, y3, label='Cubic')
plt.legend()
```
**ruviz**:
```rust
Plot::new()
.line(&x, &y1).label("Linear")
.line(&x, &y2).label("Quadratic")
.line(&x, &y3).label("Cubic")
.legend(Position::TopLeft)
.save("multi_series.png")?;
```
### Styling
**matplotlib**:
```python
plt.plot(x, y, color='red', linewidth=2, linestyle='--', marker='o')
```
**ruviz**:
```rust
Plot::new()
.line(&x, &y)
.color(Color::from_rgb(255, 0, 0))
.line_width(2.0)
.line_style(LineStyle::Dashed)
.marker(MarkerStyle::Circle)
.save("styled.png")?;
```
### Subplots
**matplotlib**:
```python
fig, axes = plt.subplots(2, 2, figsize=(12, 9))
axes[0, 0].plot(x, y1)
axes[0, 0].set_title('Plot 1')
axes[0, 1].scatter(x, y2)
axes[0, 1].set_title('Plot 2')
fig.suptitle('Multiple Plots')
plt.savefig('subplots.png')
```
**ruviz**:
```rust
let plot1 = Plot::new().line(&x, &y1).title("Plot 1").end_series();
let plot2 = Plot::new().scatter(&x, &y2).title("Plot 2").end_series();
let plot3 = Plot::new().bar(&cats, &vals).title("Plot 3").end_series();
let plot4 = Plot::new().histogram(&data, None).title("Plot 4").end_series();
subplots(2, 2, 1200, 900)?
.subplot(0, 0, plot1)?
.subplot(0, 1, plot2)?
.subplot(1, 0, plot3)?
.subplot(1, 1, plot4)?
.suptitle("Multiple Plots")
.save("subplots.png")?;
```
### Themes/Styles
**matplotlib**:
```python
plt.style.use('seaborn')
# or
plt.style.use('ggplot')
# or
import seaborn as sns
sns.set_theme()
```
**ruviz**:
```rust
Plot::new()
.theme(Theme::seaborn())
.line(&x, &y)
.save("themed.png")?;
// Available themes:
// - Theme::light() (default)
// - Theme::dark()
// - Theme::publication() (for papers)
// - Theme::seaborn() (matplotlib seaborn style)
```
## Feature Comparison
### Supported in ruviz ✅
| Line plots | `plot()` | `.line()` |
| Scatter plots | `scatter()` | `.scatter()` |
| Bar charts | `bar()` | `.bar()` |
| Histograms | `hist()` | `.histogram()` |
| Box plots | `boxplot()` | `.boxplot()` |
| Multiple series | ✅ | ✅ |
| Legends | `legend()` | `.legend()` |
| Grid | `grid()` | `.grid()` |
| Titles/labels | ✅ | ✅ |
| Custom colors | ✅ | ✅ |
| Line styles | ✅ | ✅ |
| Markers | ✅ | ✅ |
| Subplots | `subplots()` | `subplots()` |
| Themes | `style.use()` | `.theme()` |
| DPI control | `dpi=` | `.dpi()` |
| Figure size | `figsize=` | `.dimensions()` |
| PNG export | `savefig()` | `.save()` |
### Support Snapshot ⚠️
| SVG export | `savefig('file.svg')` | Supported via `.export_svg("file.svg")?` |
| Heatmaps | `imshow()`, `pcolormesh()` | Supported via `.heatmap(...)` |
| Contour plots | `contour()` | Supported via `.contour(...)` |
| 3D plots | `mpl_toolkits.mplot3d` | Planned v1.0+ |
| Interactive plots | `%matplotlib notebook` | Experimental via `show_interactive(plot).await` |
| Polar plots | `projection='polar'` | Supported via `.polar_line(...)` |
| Animations | `FuncAnimation` | Supported with the `record!` macro |
### Different Approach 🔄
| Interactive display | `plt.show()` | Save to file, view externally |
| Jupyter integration | `%matplotlib inline` | Save + display markdown cell |
| Global state | `plt.plot()` then `plt.title()` | Builder pattern (no global state) |
| Automatic figure mgmt | Implicit figure creation | Explicit `Plot::new()` |
## Data Types
### numpy arrays → Rust vectors
**matplotlib**:
```python
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
```
**ruviz with ndarray** (closest to numpy):
```rust
use ndarray::Array1;
let x = Array1::linspace(0.0, 10.0, 100);
Plot::new()
.line(&x, &y)
.save("plot.png")?;
```
**ruviz with Vec** (standard Rust):
```rust
Plot::new()
.line(&x, &y)
.save("plot.png")?;
```
### pandas → polars
**matplotlib with pandas**:
```python
import pandas as pd
df = pd.read_csv('data.csv')
plt.plot(df['x'], df['y'])
```
**ruviz with polars**:
```rust
use polars::prelude::*;
let df = CsvReader::from_path("data.csv")?.finish()?;
let x = df.column("x")?.f64()?;
let y = df.column("y")?.f64()?;
Plot::new()
.line(x, y)
.save("plot.png")?;
```
## Performance Comparison
| 1K points | ~5ms | ~5ms | 1x |
| 10K points | ~50ms | ~18ms | 2.8x |
| 100K points | ~500ms | ~100ms | 5x |
| 1M points | ~5s | ~720ms | 7x |
| 10M points | ~60s | ~2s | 30x |
*Benchmarks on AMD Ryzen 9 5950X, Ubuntu 22.04*
## Migration Examples
### Example 1: Scientific Plot
**Before (Python)**:
```python
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, 1000)
y_sin = np.sin(x)
y_cos = np.cos(x)
plt.figure(figsize=(10, 6), dpi=300)
plt.plot(x, y_sin, 'b-', label='sin(x)', linewidth=2)
plt.plot(x, y_cos, 'r--', label='cos(x)', linewidth=2)
plt.title('Trigonometric Functions', fontsize=16)
plt.xlabel('x (radians)', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.legend(loc='upper right')
plt.grid(True, alpha=0.3)
plt.savefig('trig.png', dpi=300, bbox_inches='tight')
```
**After (Rust)**:
```rust
use ruviz::prelude::*;
use std::f64::consts::PI;
let y_cos: Vec<f64> = x.iter().map(|v| v.cos()).collect();
Plot::new()
.dimensions(1000, 600)
.dpi(300)
.line(&x, &y_sin)
.color(Color::from_rgb(0, 0, 255))
.line_width(2.0)
.label("sin(x)")
.line(&x, &y_cos)
.color(Color::from_rgb(255, 0, 0))
.line_style(LineStyle::Dashed)
.line_width(2.0)
.label("cos(x)")
.title("Trigonometric Functions")
.xlabel("x (radians)")
.ylabel("y")
.legend(Position::TopRight)
.grid(true)
.save("trig.png")?;
```
### Example 2: Data Analysis
**Before (Python)**:
```python
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('measurements.csv')
grouped = df.groupby('category')['value'].mean()
plt.bar(grouped.index, grouped.values)
plt.title('Average Values by Category')
plt.xlabel('Category')
plt.ylabel('Average Value')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('analysis.png')
```
**After (Rust)**:
```rust
use ruviz::prelude::*;
use polars::prelude::*;
let df = CsvReader::from_path("measurements.csv")?.finish()?;
let grouped = df
.lazy()
.groupby([col("category")])
.agg([col("value").mean()])
.collect()?;
let categories: Vec<&str> = grouped
.column("category")?
.utf8()?
.into_iter()
.map(|opt| opt.unwrap_or(""))
.collect();
let values: Vec<f64> = grouped
.column("value")?
.f64()?
.into_iter()
.map(|opt| opt.unwrap_or(0.0))
.collect();
Plot::new()
.bar(&categories, &values)
.title("Average Values by Category")
.xlabel("Category")
.ylabel("Average Value")
.save("analysis.png")?;
```
## FAQ
### Q: Can I use ruviz in Jupyter notebooks?
**A**: Not directly (no Python bindings yet). However, you can:
1. Save plots to files in Rust
2. Display them in Jupyter using `IPython.display.Image()`
3. Or use PyO3 to create Python bindings (community contribution welcome!)
### Q: How do I display plots interactively?
**A**: Current focus is file output. For interactive:
1. Enable `interactive` or `interactive-gpu`
2. Build a `Plot`
3. Call `show_interactive(plot).await`
### Q: What about animations?
**A**: Animations are available behind the `animation` feature via the `record!` macro.
### Q: Can I customize colors like matplotlib's colormap?
**A**: Yes, but differently:
```rust
// Custom colors
.color(Color::from_rgb(255, 128, 0))
.color(Color::from_hex("#FF8000")?)
let viridis_like = Theme::builder()
.palette([
Color::from_hex("#440154").unwrap(),
Color::from_hex("#31688e").unwrap(),
Color::from_hex("#35b779").unwrap(),
Color::from_hex("#fde725").unwrap(),
])
.build();
```
### Q: Performance tips for large datasets?
**A**:
1. Use `features = ["parallel"]` for >10K points
2. Use `features = ["parallel", "simd"]` for >100K points
3. DataShader automatically activates for >1M points
4. See [Performance Guide](../guide/08_performance.md)
## Migration Checklist
- [ ] Install Rust and cargo
- [ ] Add `ruviz = "0.1"` to `Cargo.toml`
- [ ] Convert numpy arrays to `Vec<f64>` or `ndarray`
- [ ] Replace `plt.plot()` with `Plot::new().line()`
- [ ] Change `plt.savefig()` to `.save()?`
- [ ] Handle `Result` types with `?` operator
- [ ] Update data loading (pandas → polars if needed)
- [ ] Test with small dataset first
- [ ] Optimize with appropriate backend features
- [ ] Update CI/CD to compile Rust code
## Resources
- **[ruviz User Guide](../guide/README.md)** - Complete documentation
- **[Examples](../../examples/)** - Working code samples
- **[API Docs](https://docs.rs/ruviz)** - Full API reference
- **[Quickstart](../QUICKSTART.md)** - 5-minute tutorial
## Getting Help
- **GitHub Issues**: Bug reports and feature requests
- **GitHub Discussions**: Questions and community support
- **Examples Directory**: Real-world usage patterns
Ready to start? Follow the [User Guide](../guide/README.md) for step-by-step instructions.