1use bon::bon;
2
3use plotly::{HeatMap as HeatMapPlotly, Layout as LayoutPlotly, Trace};
4
5use polars::frame::DataFrame;
6use serde::Serialize;
7
8use crate::{
9 common::{Layout, Marker, PlotHelper, Polar},
10 components::{Axis, ColorBar, Palette, Text},
11};
12
13#[derive(Clone, Serialize)]
74pub struct HeatMap {
75 pub traces: Vec<Box<dyn Trace + 'static>>,
76 pub layout: LayoutPlotly,
77}
78
79#[bon]
80impl HeatMap {
81 #[builder(on(String, into), on(Text, into))]
82 pub fn new(
83 data: &DataFrame,
84 x: &str,
85 y: &str,
86 z: &str,
87 auto_color_scale: Option<bool>,
88 color_bar: Option<&ColorBar>,
89 color_scale: Option<Palette>,
90 reverse_scale: Option<bool>,
91 show_scale: Option<bool>,
92 plot_title: Option<Text>,
93 x_title: Option<Text>,
94 y_title: Option<Text>,
95 x_axis: Option<&Axis>,
96 y_axis: Option<&Axis>,
97 ) -> Self {
98 let legend = None;
99 let legend_title = None;
100 let z_title = None;
101 let z_axis = None;
102 let y2_title = None;
103 let y2_axis = None;
104
105 let layout = Self::create_layout(
106 plot_title,
107 x_title,
108 y_title,
109 y2_title,
110 z_title,
111 legend_title,
112 x_axis,
113 y_axis,
114 y2_axis,
115 z_axis,
116 legend,
117 );
118
119 let traces = Self::create_traces(
120 data,
121 x,
122 y,
123 z,
124 auto_color_scale,
125 color_bar,
126 color_scale,
127 reverse_scale,
128 show_scale,
129 );
130
131 Self { traces, layout }
132 }
133
134 #[allow(clippy::too_many_arguments)]
135 fn create_traces(
136 data: &DataFrame,
137 x: &str,
138 y: &str,
139 z: &str,
140 auto_color_scale: Option<bool>,
141 color_bar: Option<&ColorBar>,
142 color_scale: Option<Palette>,
143 reverse_scale: Option<bool>,
144 show_scale: Option<bool>,
145 ) -> Vec<Box<dyn Trace + 'static>> {
146 let mut traces: Vec<Box<dyn Trace + 'static>> = Vec::new();
147 let trace = Self::create_trace(
148 data,
149 x,
150 y,
151 z,
152 auto_color_scale,
153 color_bar,
154 color_scale,
155 reverse_scale,
156 show_scale,
157 );
158
159 traces.push(trace);
160 traces
161 }
162
163 #[allow(clippy::too_many_arguments)]
164 fn create_trace(
165 data: &DataFrame,
166 x: &str,
167 y: &str,
168 z: &str,
169 auto_color_scale: Option<bool>,
170 color_bar: Option<&ColorBar>,
171 color_scale: Option<Palette>,
172 reverse_scale: Option<bool>,
173 show_scale: Option<bool>,
174 ) -> Box<dyn Trace + 'static> {
175 let x = Self::get_string_column(data, x);
176 let y = Self::get_string_column(data, y);
177 let z = Self::get_numeric_column(data, z);
178
179 let mut trace = HeatMapPlotly::default().x(x).y(y).z(z);
180
181 trace = Self::set_auto_color_scale(trace, auto_color_scale);
182 trace = Self::set_color_bar(trace, color_bar);
183 trace = Self::set_color_scale(trace, color_scale);
184 trace = Self::set_reverse_scale(trace, reverse_scale);
185 trace = Self::set_show_scale(trace, show_scale);
186 trace
187 }
188
189 fn set_auto_color_scale<X, Y, Z>(
190 mut trace: Box<HeatMapPlotly<X, Y, Z>>,
191 auto_color_scale: Option<bool>,
192 ) -> Box<HeatMapPlotly<X, Y, Z>>
193 where
194 X: Serialize + Clone,
195 Y: Serialize + Clone,
196 Z: Serialize + Clone,
197 {
198 if let Some(auto_color_scale) = auto_color_scale {
199 trace = trace.auto_color_scale(auto_color_scale);
200 }
201
202 trace
203 }
204
205 fn set_color_bar<X, Y, Z>(
206 mut trace: Box<HeatMapPlotly<X, Y, Z>>,
207 color_bar: Option<&ColorBar>,
208 ) -> Box<HeatMapPlotly<X, Y, Z>>
209 where
210 X: Serialize + Clone,
211 Y: Serialize + Clone,
212 Z: Serialize + Clone,
213 {
214 if let Some(color_bar) = color_bar {
215 trace = trace.color_bar(color_bar.to_plotly())
216 }
217
218 trace
219 }
220
221 fn set_color_scale<X, Y, Z>(
222 mut trace: Box<HeatMapPlotly<X, Y, Z>>,
223 color_scale: Option<Palette>,
224 ) -> Box<HeatMapPlotly<X, Y, Z>>
225 where
226 X: Serialize + Clone,
227 Y: Serialize + Clone,
228 Z: Serialize + Clone,
229 {
230 if let Some(color_scale) = color_scale {
231 trace = trace.color_scale(color_scale.to_plotly());
232 }
233
234 trace
235 }
236
237 fn set_reverse_scale<X, Y, Z>(
238 mut trace: Box<HeatMapPlotly<X, Y, Z>>,
239 reverse_scale: Option<bool>,
240 ) -> Box<HeatMapPlotly<X, Y, Z>>
241 where
242 X: Serialize + Clone,
243 Y: Serialize + Clone,
244 Z: Serialize + Clone,
245 {
246 if let Some(reverse_scale) = reverse_scale {
247 trace = trace.reverse_scale(reverse_scale);
248 }
249 trace
250 }
251
252 fn set_show_scale<X, Y, Z>(
253 mut trace: Box<HeatMapPlotly<X, Y, Z>>,
254 show_scale: Option<bool>,
255 ) -> Box<HeatMapPlotly<X, Y, Z>>
256 where
257 X: Serialize + Clone,
258 Y: Serialize + Clone,
259 Z: Serialize + Clone,
260 {
261 if let Some(show_scale) = show_scale {
262 trace = trace.show_scale(show_scale);
263 }
264 trace
265 }
266}
267
268impl Layout for HeatMap {}
269impl Marker for HeatMap {}
270impl Polar for HeatMap {}
271
272impl PlotHelper for HeatMap {
273 fn get_layout(&self) -> &LayoutPlotly {
274 &self.layout
275 }
276
277 fn get_traces(&self) -> &Vec<Box<dyn Trace + 'static>> {
278 &self.traces
279 }
280}