use glam::Vec2;
use vidi::core::{Color, Style};
use vidi::prelude::*;
fn main() {
dash()
.background_color(Color::BLACK)
.add_2d(|p| {
let noisy_data = generate_noisy_data();
let regression_line = compute_regression(&noisy_data);
p.scatter(
noisy_data,
Style {
color: Color::RED,
size: 3.0,
opacity: 0.6,
},
)
.line(
regression_line,
Style {
color: Color::BLUE,
size: 2.5,
opacity: 1.0,
},
)
.x_label("Time (s)")
.y_label("Amplitude")
})
.add_2d(|p| {
let (history, mean_forecast, bands) = generate_forecast_data();
let mut plot = p.line(
history,
Style {
color: Color::BLUE,
size: 2.5,
opacity: 1.0,
},
);
let band_styles = [
(0.15, Color::rgb(0.5, 0.7, 1.0)), (0.25, Color::rgb(0.4, 0.6, 0.95)),
(0.4, Color::rgb(0.3, 0.5, 0.9)),
(0.6, Color::rgb(0.2, 0.4, 0.85)), ];
for (i, (upper, lower)) in bands.iter().rev().enumerate() {
let (opacity, color) = band_styles[i];
plot = plot.fill_between(
upper.clone(),
lower.clone(),
Style {
color,
size: 1.0,
opacity,
},
);
}
plot.line(
mean_forecast,
Style {
color: Color::rgb(0.1, 0.3, 0.8),
size: 2.0,
opacity: 1.0,
},
)
.x_label("Days")
.y_label("Value")
})
.add_distribution(|d| {
let samples = generate_normal_samples(1000, 0.0, 1.0);
d.histogram(samples)
.bins(25)
.style(Style {
color: Color::rgb(0.2, 0.7, 0.4),
size: 1.0,
opacity: 0.8,
})
.x_label("Sample Value")
.y_label("Count")
})
.add_distribution(|d| {
let samples = generate_bimodal_samples(800);
d.pdf(samples)
.style(Style {
color: Color::rgb(0.8, 0.3, 0.5),
size: 2.0,
opacity: 1.0,
})
.x_label("Measurement")
.y_label("Probability")
})
.show();
}
fn generate_noisy_data() -> Vec<Vec2> {
let mut seed = 12345u64;
let mut rng = move || {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
(seed as f32 / u64::MAX as f32) * 2.0 - 1.0
};
(0..300)
.map(|i| {
let x = i as f32 * 0.05;
let noise = rng() * 0.3;
Vec2::new(x, x.sin() + noise)
})
.collect()
}
fn compute_regression(data: &[Vec2]) -> Vec<Vec2> {
let x_min = data.iter().map(|p| p.x).fold(f32::INFINITY, f32::min);
let x_max = data.iter().map(|p| p.x).fold(f32::NEG_INFINITY, f32::max);
(0..200)
.map(|i| {
let t = i as f32 / 199.0;
let x = x_min + t * (x_max - x_min);
Vec2::new(x, x.sin())
})
.collect()
}
fn generate_forecast_data() -> (Vec<Vec2>, Vec<Vec2>, Vec<(Vec<Vec2>, Vec<Vec2>)>) {
let history: Vec<Vec2> = (0..=50)
.map(|i| {
let x = i as f32 * 0.1;
let y = (x * 0.5).sin() + x * 0.05;
Vec2::new(x, y)
})
.collect();
let last_history = history.last().unwrap();
let forecast_start_x = last_history.x;
let n_forecast = 60;
let mean_forecast: Vec<Vec2> = (0..=n_forecast)
.map(|i| {
let x = forecast_start_x + i as f32 * 0.15;
let y = (x * 0.5).sin() + x * 0.05;
Vec2::new(x, y)
})
.collect();
let band_multipliers = [0.5, 1.0, 1.5, 2.0];
let bands: Vec<(Vec<Vec2>, Vec<Vec2>)> = band_multipliers
.iter()
.map(|&mult| {
let upper: Vec<Vec2> = (0..=n_forecast)
.map(|i| {
let x = forecast_start_x + i as f32 * 0.15;
let mean = (x * 0.5).sin() + x * 0.05;
let uncertainty = (x - forecast_start_x) * 0.03 * mult;
Vec2::new(x, mean + uncertainty)
})
.collect();
let lower: Vec<Vec2> = (0..=n_forecast)
.map(|i| {
let x = forecast_start_x + i as f32 * 0.15;
let mean = (x * 0.5).sin() + x * 0.05;
let uncertainty = (x - forecast_start_x) * 0.03 * mult;
Vec2::new(x, mean - uncertainty)
})
.collect();
(upper, lower)
})
.collect();
(history, mean_forecast, bands)
}
fn generate_normal_samples(n: usize, mean: f32, std_dev: f32) -> Vec<f32> {
let mut seed = 54321u64;
let mut rng = move || {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
(seed as f32 / u64::MAX as f32)
};
let mut samples = Vec::with_capacity(n);
for _ in 0..(n / 2 + 1) {
let u1 = rng().max(1e-10);
let u2 = rng();
let r = (-2.0 * u1.ln()).sqrt();
let theta = 2.0 * std::f32::consts::PI * u2;
samples.push(mean + std_dev * r * theta.cos());
if samples.len() < n {
samples.push(mean + std_dev * r * theta.sin());
}
}
samples.truncate(n);
samples
}
fn generate_bimodal_samples(n: usize) -> Vec<f32> {
let mut seed = 98765u64;
let mut rng = move || {
seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
(seed as f32 / u64::MAX as f32)
};
let mut samples = Vec::with_capacity(n);
for _ in 0..n {
let (mean, std_dev) = if rng() < 0.4 { (-2.0, 0.8) } else { (2.5, 1.2) };
let u1 = rng().max(1e-10);
let u2 = rng();
let r = (-2.0 * u1.ln()).sqrt();
let theta = 2.0 * std::f32::consts::PI * u2;
samples.push(mean + std_dev * r * theta.cos());
}
samples
}