scirs2_integrate/visualization/
utils.rs1use super::types::{ColorScheme, PlotStatistics};
7
8pub fn generate_colormap(values: &[f64], scheme: ColorScheme) -> Vec<(u8, u8, u8)> {
10 let n = values.len();
11 let mut colors = Vec::with_capacity(n);
12
13 let min_val = values.iter().fold(f64::INFINITY, |a, &b| a.min(b));
14 let max_val = values.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
15 let range = max_val - min_val;
16
17 for &val in values {
18 let normalized = if range > 0.0 {
19 (val - min_val) / range
20 } else {
21 0.5
22 };
23
24 let color = match scheme {
25 ColorScheme::Viridis => viridis_color(normalized),
26 ColorScheme::Plasma => plasma_color(normalized),
27 ColorScheme::Inferno => inferno_color(normalized),
28 ColorScheme::Grayscale => {
29 let gray = (normalized * 255.0) as u8;
30 (gray, gray, gray)
31 }
32 };
33 colors.push(color);
34 }
35
36 colors
37}
38
39fn viridis_color(t: f64) -> (u8, u8, u8) {
41 let t = t.max(0.0).min(1.0);
42 let r = (0.267004 + t * (0.127568 + t * (0.019234 - t * 0.012814))) * 255.0;
43 let g = (0.004874 + t * (0.950141 + t * (-0.334896 + t * 0.158789))) * 255.0;
44 let b = (0.329415 + t * (0.234092 + t * (1.384085 - t * 1.388488))) * 255.0;
45 (r as u8, g as u8, b as u8)
46}
47
48fn plasma_color(t: f64) -> (u8, u8, u8) {
50 let t = t.max(0.0).min(1.0);
51 let r = (0.050383 + t * (1.075483 + t * (-0.346066 + t * 0.220971))) * 255.0;
52 let g = (0.029803 + t * (0.089467 + t * (1.234884 - t * 1.281864))) * 255.0;
53 let b = (0.527975 + t * (0.670134 + t * (-1.397127 + t * 1.149498))) * 255.0;
54 (r as u8, g as u8, b as u8)
55}
56
57fn inferno_color(t: f64) -> (u8, u8, u8) {
59 let t = t.max(0.0).min(1.0);
60 let r = (0.001462 + t * (0.998260 + t * (-0.149678 + t * 0.150124))) * 255.0;
61 let g = (0.000466 + t * (0.188724 + t * (1.203007 - t * 1.391543))) * 255.0;
62 let b = (0.013866 + t * (0.160930 + t * (0.690929 - t * 0.865624))) * 255.0;
63 (r as u8, g as u8, b as u8)
64}
65
66pub fn optimal_grid_resolution(_domainsize: (f64, f64), target_density: f64) -> (usize, usize) {
68 let (width, height) = _domainsize;
69 let area = width * height;
70 let total_points = (area * target_density) as usize;
71
72 let aspect_ratio = width / height;
73 let ny = (total_points as f64 / aspect_ratio).sqrt() as usize;
74 let nx = (ny as f64 * aspect_ratio) as usize;
75
76 (nx.max(10), ny.max(10))
77}
78
79pub fn plot_statistics(data: &[f64]) -> PlotStatistics {
81 let n = data.len() as f64;
82 let mean = data.iter().sum::<f64>() / n;
83 let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n;
84 let std_dev = variance.sqrt();
85
86 let mut sorted_data = data.to_vec();
87 sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
88
89 let min = sorted_data[0];
90 let max = sorted_data[sorted_data.len() - 1];
91 let median = if sorted_data.len().is_multiple_of(2) {
92 (sorted_data[sorted_data.len() / 2 - 1] + sorted_data[sorted_data.len() / 2]) / 2.0
93 } else {
94 sorted_data[sorted_data.len() / 2]
95 };
96
97 PlotStatistics {
98 count: data.len(),
99 mean,
100 std_dev,
101 min,
102 max,
103 median,
104 }
105}