plotlars/components/legend.rs
1use plotly::{
2 common::Font,
3 layout::Legend as LegendPlotly,
4};
5
6use crate::{Orientation, Rgb, Text};
7
8/// A structure representing a customizable plot legend.
9///
10/// # Example
11///
12/// ```rust
13/// use plotlars::{Histogram, Legend, Orientation, Plot, Rgb};
14///
15/// let dataset = LazyCsvReader::new("data/penguins.csv")
16/// .finish()
17/// .unwrap()
18/// .select([
19/// col("species"),
20/// col("sex").alias("gender"),
21/// col("flipper_length_mm").cast(DataType::Int16),
22/// col("body_mass_g").cast(DataType::Int16),
23/// ])
24/// .collect()
25/// .unwrap();
26///
27/// let legend = Legend::new()
28/// .orientation(Orientation::Horizontal)
29/// .border_width(1)
30/// .x(0.78)
31/// .y(0.825);
32///
33/// Histogram::builder()
34/// .data(&dataset)
35/// .x("body_mass_g")
36/// .group("species")
37/// .colors(vec![
38/// Rgb(255, 0, 0),
39/// Rgb(0, 255, 0),
40/// Rgb(0, 0, 255),
41/// ])
42/// .opacity(0.5)
43/// .x_title("Body Mass (g)")
44/// .y_title("Frequency")
45/// .legend_title("Species")
46/// .legend(&legend)
47/// .build()
48/// .plot();
49/// ```
50///
51/// 
52#[derive(Clone, Default)]
53pub struct Legend {
54 pub(crate) background_color: Option<Rgb>,
55 pub(crate) border_color: Option<Rgb>,
56 pub(crate) border_width: Option<usize>,
57 pub(crate) font: Option<String>,
58 pub(crate) orientation: Option<Orientation>,
59 pub(crate) x: Option<f64>,
60 pub(crate) y: Option<f64>,
61}
62
63impl Legend {
64 /// Creates a new `Legend` instance with default values.
65 pub fn new() -> Self {
66 Self::default()
67 }
68
69 /// Sets the background color of the legend.
70 ///
71 /// # Argument
72 ///
73 /// * `color` - An `Rgb` struct representing the background color.
74 pub fn background_color(mut self, color: Rgb) -> Self {
75 self.background_color = Some(color);
76 self
77 }
78
79 /// Sets the border color of the legend.
80 ///
81 /// # Argument
82 ///
83 /// * `color` - An `Rgb` struct representing the border color.
84 pub fn border_color(mut self, color: Rgb) -> Self {
85 self.border_color = Some(color);
86 self
87 }
88
89 /// Sets the border width of the legend.
90 ///
91 /// # Argument
92 ///
93 /// * `width` - A `usize` value representing the width of the border.
94 pub fn border_width(mut self, width: usize) -> Self {
95 self.border_width = Some(width);
96 self
97 }
98
99 /// Sets the font of the legend labels.
100 ///
101 /// # Argument
102 ///
103 /// * `font` - A value that can be converted into a `String`, representing the font name for the labels.
104 pub fn font(mut self, font: impl Into<String>) -> Self {
105 self.font = Some(font.into());
106 self
107 }
108
109 /// Sets the orientation of the legend.
110 ///
111 /// # Argument
112 ///
113 /// * `orientation` - An `Orientation` enum value representing the layout direction of the legend.
114 pub fn orientation(mut self, orientation: Orientation) -> Self {
115 self.orientation = Some(orientation);
116 self
117 }
118
119 /// Sets the horizontal position of the legend.
120 ///
121 /// # Argument
122 ///
123 /// * `x` - A `f64` value representing the horizontal position of the legend.
124 pub fn x(mut self, x: f64) -> Self {
125 self.x = Some(x);
126 self
127 }
128
129 /// Sets the vertical position of the legend.
130 ///
131 /// # Argument
132 ///
133 /// * `y` - A `f64` value representing the vertical position of the legend.
134 pub fn y(mut self, y: f64) -> Self {
135 self.y = Some(y);
136 self
137 }
138
139 pub(crate) fn set_legend(title: Option<Text>, format: Option<&Legend>) -> LegendPlotly {
140 let mut legend = LegendPlotly::new();
141
142 if let Some(title) = title {
143 legend = legend.title(title.to_plotly());
144 }
145
146 if let Some(format) = format {
147 legend = Self::set_format(legend, format);
148 }
149
150 legend
151 }
152
153 fn set_format(mut legend: LegendPlotly, format: &Legend) -> LegendPlotly {
154 if let Some(color) = format.background_color {
155 legend = legend.background_color(color.to_plotly());
156 }
157
158 if let Some(color) = format.border_color {
159 legend = legend.border_color(color.to_plotly());
160 }
161
162 if let Some(width) = format.border_width {
163 legend = legend.border_width(width);
164 }
165
166 if let Some(font) = &format.font {
167 legend = legend.font(Font::new().family(font.as_str()));
168 }
169
170 if let Some(orientation) = &format.orientation {
171 legend = legend.orientation(orientation.to_plotly());
172 }
173
174 if let Some(x) = format.x {
175 legend = legend.x(x);
176 }
177
178 if let Some(y) = format.y {
179 legend = legend.y(y);
180 }
181
182 legend
183 }
184}