plotlars/plots/
density_mapbox.rs1use bon::bon;
2
3use plotly::{
4 layout::{Center, Layout as LayoutPlotly, Mapbox, MapboxStyle, Margin},
5 DensityMapbox as DensityMapboxPlotly, Trace,
6};
7
8use polars::frame::DataFrame;
9use serde::Serialize;
10
11use crate::{
12 common::{Layout, PlotHelper, Polar},
13 components::{Legend, Text},
14};
15
16#[derive(Clone, Serialize)]
70pub struct DensityMapbox {
71 traces: Vec<Box<dyn Trace + 'static>>,
72 layout: LayoutPlotly,
73}
74
75#[bon]
76impl DensityMapbox {
77 #[builder(on(String, into), on(Text, into))]
78 pub fn new(
79 data: &DataFrame,
80 lat: &str,
81 lon: &str,
82 z: &str,
83 center: Option<[f64; 2]>,
84 zoom: Option<u8>,
85 radius: Option<u8>,
86 opacity: Option<f64>,
87 z_min: Option<f64>,
88 z_max: Option<f64>,
89 z_mid: Option<f64>,
90 plot_title: Option<Text>,
91 legend_title: Option<Text>,
92 legend: Option<&Legend>,
93 ) -> Self {
94 let x_title = None;
95 let y_title = None;
96 let z_title = None;
97 let x_axis = None;
98 let y_axis = None;
99 let z_axis = None;
100 let y2_title = None;
101 let y2_axis = None;
102
103 let mut layout = Self::create_layout(
104 plot_title,
105 x_title,
106 y_title,
107 y2_title,
108 z_title,
109 legend_title,
110 x_axis,
111 y_axis,
112 y2_axis,
113 z_axis,
114 legend,
115 None,
116 )
117 .margin(Margin::new().bottom(0));
118
119 let mut map_box = Mapbox::new().style(MapboxStyle::OpenStreetMap);
120
121 if let Some(center) = center {
122 map_box = map_box.center(Center::new(center[0], center[1]));
123 }
124
125 if let Some(zoom) = zoom {
126 map_box = map_box.zoom(zoom);
127 } else {
128 map_box = map_box.zoom(1);
129 }
130
131 layout = layout.mapbox(map_box);
132
133 let traces = Self::create_traces(data, lat, lon, z, radius, opacity, z_min, z_max, z_mid);
134
135 Self { traces, layout }
136 }
137
138 #[allow(clippy::too_many_arguments)]
139 fn create_traces(
140 data: &DataFrame,
141 lat: &str,
142 lon: &str,
143 z: &str,
144 radius: Option<u8>,
145 opacity: Option<f64>,
146 z_min: Option<f64>,
147 z_max: Option<f64>,
148 z_mid: Option<f64>,
149 ) -> Vec<Box<dyn Trace + 'static>> {
150 let mut traces: Vec<Box<dyn Trace + 'static>> = Vec::new();
151
152 let trace = Self::create_trace(data, lat, lon, z, radius, opacity, z_min, z_max, z_mid);
153
154 traces.push(trace);
155 traces
156 }
157
158 #[allow(clippy::too_many_arguments)]
159 fn create_trace(
160 data: &DataFrame,
161 lat: &str,
162 lon: &str,
163 z: &str,
164 radius: Option<u8>,
165 opacity: Option<f64>,
166 z_min: Option<f64>,
167 z_max: Option<f64>,
168 z_mid: Option<f64>,
169 ) -> Box<dyn Trace + 'static> {
170 let lat_data = Self::get_numeric_column(data, lat);
171 let lon_data = Self::get_numeric_column(data, lon);
172 let z_data = Self::get_numeric_column(data, z);
173
174 let mut trace = DensityMapboxPlotly::new(lat_data, lon_data, z_data);
175
176 if let Some(radius) = radius {
177 trace = trace.radius(radius);
178 }
179
180 if let Some(opacity) = opacity {
181 trace = trace.opacity(opacity);
182 }
183
184 if let Some(z_min) = z_min {
185 trace = trace.zmin(Some(z_min as f32));
186 }
187
188 if let Some(z_max) = z_max {
189 trace = trace.zmax(Some(z_max as f32));
190 }
191
192 if let Some(z_mid) = z_mid {
193 trace = trace.zmid(Some(z_mid as f32));
194 }
195
196 trace
197 }
198}
199
200impl Layout for DensityMapbox {}
201impl Polar for DensityMapbox {}
202
203impl PlotHelper for DensityMapbox {
204 fn get_layout(&self) -> &LayoutPlotly {
205 &self.layout
206 }
207
208 fn get_traces(&self) -> &Vec<Box<dyn Trace + 'static>> {
209 &self.traces
210 }
211}