elemental/standard/
plot.rs

1//! Plots two lists of data (two vectors).
2
3use plotlib::{
4    page::Page,
5    repr::Plot,
6    view::ContinuousView,
7    style::{
8        PointStyle,
9        PointMarker,
10    },
11};
12
13use crate::Matrix;
14use crate::error::*;
15
16use super::StdFunc;
17
18#[derive(Clone)]
19pub struct Plt;
20
21impl Plt {
22    /// Evaluates `Plt` while minimizing heap allocation.
23    pub fn evalpure(vec1: &Matrix, vec2: &Matrix) -> Matrix {
24        let a = vec1.vals();
25        let b = vec2.vals();
26
27        if vec1.rows() != vec2.rows()
28            || vec1.cols() != vec2.cols()
29        {
30            throw(ImproperDimensions);
31            return Matrix::empty();
32        }
33
34        // Zip the two vector values into one vector of tuples
35        let data = a.iter().zip(b).map(|(i, j)| (*i, *j)).collect::<Vec<(f64, f64)>>();
36
37        // Create a new plot with the data and a custom point style
38        let plot = Plot::new(data).point_style(
39            PointStyle::new()
40                .marker(PointMarker::Circle)
41                .colour("#3264a8"),
42        );
43
44        // Plot the data
45        let v = ContinuousView::new()
46            .add(plot)
47            .x_label("Independent")
48            .y_label("Dependent");
49
50        // Render the plot in the terminal
51        match Page::single(&v).dimensions(150, 40).to_text() {
52            Ok(p) => println!("{}", p),
53            Err(_) => throw(CouldNotDisplayPlot),
54        };
55        
56        // Save the plot to a file
57        match Page::single(&v).save("plot.svg") {
58            Ok(_) => (),
59            Err(_) => throw(CouldNotWriteToFile),
60        };
61
62        Matrix::empty()
63    }
64}
65
66impl StdFunc for Plt {
67    fn eval(&self, args: Vec<Matrix>) -> Matrix {
68        if args.len() != 2 {
69            throw(WrongNumberOfArgs);
70            return Matrix::new(0, 0, Vec::new());
71        }
72
73        Self::evalpure(&args[0], &args[1])
74    }
75}