plotlars/plots/
array2dplot.rs

1use bon::bon;
2
3use plotly::{image::ColorModel, Image as ImagePlotly, Layout as LayoutPlotly, Trace};
4
5use serde::Serialize;
6
7use crate::{
8    common::{Layout, PlotHelper},
9    components::{Axis, Rgb, Text},
10};
11
12/// A structure representing a 2D array plot.
13///
14/// The `Array2dPlot` struct allows for visualizing 2D arrays of RGB color values as images or heatmaps.
15/// Each element in the 2D array corresponds to a pixel, with its color defined by an `[u8; 3]` RGB triplet.
16/// This struct supports customizable titles, axis labels, and axis configurations for better presentation.
17///
18/// # Arguments
19///
20/// * `data` - A 2D vector of RGB triplets (`&[Vec<[u8; 3]>]`) representing pixel colors for the plot.
21/// * `plot_title` - An optional `Text` struct specifying the title of the plot.
22/// * `x_title` - An optional `Text` struct specifying the title of the x-axis.
23/// * `y_title` - An optional `Text` struct specifying the title of the y-axis.
24/// * `x_axis` - An optional reference to an `Axis` struct for customizing the x-axis.
25/// * `y_axis` - An optional reference to an `Axis` struct for customizing the y-axis.
26///
27/// # Example
28///
29/// ## Basic 2D Array Plot
30///
31/// ```rust
32/// use plotlars::{Array2dPlot, Plot, Text};
33///
34/// let data = vec![
35///     vec![[255, 0, 0], [0, 255, 0], [0, 0, 255]],
36///     vec![[0, 0, 255], [255, 0, 0], [0, 255, 0]],
37///     vec![[0, 255, 0], [0, 0, 255], [255, 0, 0]],
38/// ];
39///
40/// Array2dPlot::builder()
41///     .data(&data)
42///     .plot_title(
43///         Text::from("Array2D Plot")
44///             .font("Arial")
45///             .size(18)
46///     )
47///     .build()
48///     .plot();
49/// ```
50///
51/// ![Example](https://imgur.com/LMrqAaT.png)
52#[derive(Clone, Serialize)]
53pub struct Array2dPlot {
54    traces: Vec<Box<dyn Trace + 'static>>,
55    layout: LayoutPlotly,
56}
57
58#[bon]
59impl Array2dPlot {
60    #[builder(on(String, into), on(Text, into))]
61    pub fn new(
62        data: &[Vec<[u8; 3]>],
63        plot_title: Option<Text>,
64        x_title: Option<Text>,
65        y_title: Option<Text>,
66        x_axis: Option<&Axis>,
67        y_axis: Option<&Axis>,
68    ) -> Self {
69        let z_title = None;
70        let legend_title = None;
71        let z_axis = None;
72        let legend = None;
73        let y2_title = None;
74        let y2_axis = None;
75
76        let layout = Self::create_layout(
77            plot_title,
78            x_title,
79            y_title,
80            y2_title,
81            z_title,
82            legend_title,
83            x_axis,
84            y_axis,
85            y2_axis,
86            z_axis,
87            legend,
88        );
89
90        let mut traces = vec![];
91
92        let trace = Self::create_trace(data);
93
94        traces.push(trace);
95
96        Self { traces, layout }
97    }
98
99    fn create_trace(data: &[Vec<[u8; 3]>]) -> Box<dyn Trace + 'static> {
100        let pixels = data
101            .iter()
102            .map(|row| {
103                row.iter()
104                    .map(|&rgb| Rgb(rgb[0], rgb[1], rgb[2]).to_plotly())
105                    .collect::<Vec<_>>()
106            })
107            .collect::<Vec<_>>();
108
109        ImagePlotly::new(pixels).color_model(ColorModel::RGB)
110    }
111}
112
113impl Layout for Array2dPlot {}
114
115impl PlotHelper for Array2dPlot {
116    fn get_layout(&self) -> &LayoutPlotly {
117        &self.layout
118    }
119
120    fn get_traces(&self) -> &Vec<Box<dyn Trace + 'static>> {
121        &self.traces
122    }
123}