audio_visualizer/spectrum/
plotters_png_file.rs

1//! Static spectrum analysis: print spectrum to PNG file.
2
3use plotters::prelude::*;
4use std::collections::BTreeMap;
5use std::path::PathBuf;
6
7pub fn spectrum_static_plotters_png_visualize(
8    frequency_spectrum: &BTreeMap<u32, f32>,
9    directory: &str,
10    filename: &str,
11) {
12    // assert no NAN
13    assert!(
14        !frequency_spectrum.iter().any(|(_, f)| f.is_nan()),
15        "There are NAN-values in the spectrum!"
16    );
17
18    // find maximum for graphics scaling
19    let mut max = 0.0;
20    for mag in frequency_spectrum.values() {
21        if *mag > max {
22            max = *mag;
23        }
24    }
25
26    let max_frequency = *frequency_spectrum
27        .iter()
28        .skip(frequency_spectrum.len() - 2)
29        .last()
30        .unwrap()
31        .0;
32
33    let mut path = PathBuf::new();
34    path.push(directory);
35    path.push(filename);
36
37    let mut width = frequency_spectrum.len() as u32;
38    if width < 700 {
39        width = 700;
40    }
41
42    let height = if width < 700 {
43        (width as f32 / 0.8) as u32
44    } else {
45        700
46    };
47
48    let root = BitMapBackend::new(&path, (width, height)).into_drawing_area();
49    root.fill(&WHITE).unwrap();
50    let mut chart = ChartBuilder::on(&root)
51        .caption("y=f magnitudes of sample", ("sans-serif", 20).into_font())
52        .margin(5)
53        .x_label_area_size(60)
54        .y_label_area_size(60)
55        .build_cartesian_2d(0.0..(max_frequency as f32) /*.log10()*/, 0.0..max)
56        .unwrap();
57
58    chart.configure_mesh().draw().unwrap();
59
60    chart
61        .draw_series(LineSeries::new(
62            // (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
63            frequency_spectrum
64                .iter()
65                .map(|(frequency, magnitude)| ((*frequency as f32) /*.log10()*/, *magnitude)),
66            &RED,
67        ))
68        .unwrap()
69        .label("frequency magnitude")
70        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));
71
72    chart
73        .configure_series_labels()
74        .background_style(WHITE.mix(0.8))
75        .border_style(BLACK)
76        .draw()
77        .unwrap();
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use crate::tests::testutil::TEST_OUT_DIR;
84    use std::f32::NAN;
85
86    #[test]
87    fn test_visualize_sine_waves_spectrum_plotters() {
88        let mut spectrum = BTreeMap::new();
89        spectrum.insert(0, 0.0);
90        spectrum.insert(10, 5.0);
91        spectrum.insert(20, 20.0);
92        spectrum.insert(30, 40.0);
93        spectrum.insert(40, 80.0);
94        spectrum.insert(50, 120.0);
95        spectrum.insert(55, 130.0);
96        spectrum.insert(60, 140.0);
97        spectrum.insert(65, 130.0);
98        spectrum.insert(70, 120.0);
99        spectrum.insert(80, 80.0);
100        spectrum.insert(90, 40.0);
101        spectrum.insert(100, 20.0);
102        spectrum.insert(110, 5.0);
103        spectrum.insert(120, 0.0);
104        spectrum.insert(130, 0.0);
105
106        spectrum_static_plotters_png_visualize(
107            &spectrum,
108            TEST_OUT_DIR,
109            "spectrum_60hz_peak_plotters_visualization.png",
110        );
111    }
112
113    #[allow(non_snake_case)]
114    #[test]
115    #[should_panic]
116    fn test_panic_on_NAN() {
117        let mut spectrum = BTreeMap::new();
118        spectrum.insert(0, NAN);
119
120        spectrum_static_plotters_png_visualize(
121            &spectrum,
122            TEST_OUT_DIR,
123            "spectrum_60hz_peak_plotters_visualization_NAN.png",
124        );
125    }
126}