plotlars/plots/
array2dplot.rs

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