1use plotlars::polars::prelude::*;
2use plotlars::{
3 Arrangement, Axis, BarPlot, BoxPlot, CandlestickPlot, ColorBar, CsvReader, Direction, HeatMap,
4 Histogram, Legend, Line, Mode, Orientation, Palette, Rgb, SankeyDiagram, Scatter3dPlot,
5 ScatterGeo, ScatterMap, ScatterPlot, ScatterPolar, Shape, SubplotGrid, Text, TickDirection,
6 TimeSeriesPlot, ValueExponent,
7};
8
9fn main() {
10 regular_grid_example();
11 irregular_grid_example();
12 mixed_grid_example();
13}
14
15fn regular_grid_example() {
16 let dataset1 = CsvReader::new("data/animal_statistics.csv")
17 .finish()
18 .unwrap();
19
20 let plot1 = BarPlot::builder()
21 .data(&dataset1)
22 .labels("animal")
23 .values("value")
24 .orientation(Orientation::Vertical)
25 .group("gender")
26 .sort_groups_by(|a, b| a.len().cmp(&b.len()))
27 .error("error")
28 .colors(vec![Rgb(255, 127, 80), Rgb(64, 224, 208)])
29 .plot_title(Text::from("Bar Plot").x(-0.05).y(1.35).size(14))
30 .y_title(Text::from("value").x(-0.055).y(0.76))
31 .x_title(Text::from("animal").x(0.97).y(-0.2))
32 .legend(
33 &Legend::new()
34 .orientation(Orientation::Horizontal)
35 .x(0.4)
36 .y(1.2),
37 )
38 .build();
39
40 let dataset2 = CsvReader::new("data/penguins.csv")
41 .finish()
42 .unwrap()
43 .lazy()
44 .select([
45 col("species"),
46 col("sex").alias("gender"),
47 col("flipper_length_mm").cast(DataType::Int16),
48 col("body_mass_g").cast(DataType::Int16),
49 ])
50 .collect()
51 .unwrap();
52
53 let axis = Axis::new()
54 .show_line(true)
55 .tick_direction(TickDirection::OutSide)
56 .value_thousands(true);
57
58 let plot2 = ScatterPlot::builder()
59 .data(&dataset2)
60 .x("body_mass_g")
61 .y("flipper_length_mm")
62 .group("species")
63 .sort_groups_by(|a, b| {
64 if a.len() == b.len() {
65 a.cmp(b)
66 } else {
67 a.len().cmp(&b.len())
68 }
69 })
70 .opacity(0.5)
71 .size(12)
72 .colors(vec![Rgb(178, 34, 34), Rgb(65, 105, 225), Rgb(255, 140, 0)])
73 .shapes(vec![Shape::Circle, Shape::Square, Shape::Diamond])
74 .plot_title(Text::from("Scatter Plot").x(-0.075).y(1.35).size(14))
75 .x_title(Text::from("body mass (g)").y(-0.4))
76 .y_title(Text::from("flipper length (mm)").x(-0.078).y(0.5))
77 .legend_title("species")
78 .x_axis(&axis.clone().value_range(2500.0, 6500.0))
79 .y_axis(&axis.clone().value_range(170.0, 240.0))
80 .legend(&Legend::new().x(0.98).y(0.95))
81 .build();
82
83 let dataset3 = CsvReader::new("data/debilt_2023_temps.csv")
84 .has_header(true)
85 .try_parse_dates(true)
86 .finish()
87 .unwrap()
88 .lazy()
89 .with_columns(vec![
90 (col("tavg") / lit(10)).alias("avg"),
91 (col("tmin") / lit(10)).alias("min"),
92 (col("tmax") / lit(10)).alias("max"),
93 ])
94 .collect()
95 .unwrap();
96
97 let plot3 = TimeSeriesPlot::builder()
98 .data(&dataset3)
99 .x("date")
100 .y("avg")
101 .additional_series(vec!["min", "max"])
102 .colors(vec![Rgb(128, 128, 128), Rgb(0, 122, 255), Rgb(255, 128, 0)])
103 .lines(vec![Line::Solid, Line::Dot, Line::Dot])
104 .plot_title(Text::from("Time Series Plot").x(-0.05).y(1.35).size(14))
105 .y_title(Text::from("temperature (ÂșC)").x(-0.055).y(0.6))
106 .legend(&Legend::new().x(0.9).y(1.25))
107 .build();
108
109 let plot4 = BoxPlot::builder()
110 .data(&dataset2)
111 .labels("species")
112 .values("body_mass_g")
113 .orientation(Orientation::Vertical)
114 .group("gender")
115 .box_points(true)
116 .point_offset(-1.5)
117 .jitter(0.01)
118 .opacity(0.1)
119 .colors(vec![Rgb(0, 191, 255), Rgb(57, 255, 20), Rgb(255, 105, 180)])
120 .plot_title(Text::from("Box Plot").x(-0.075).y(1.35).size(14))
121 .x_title(Text::from("species").y(-0.3))
122 .y_title(Text::from("body mass (g)").x(-0.08).y(0.5))
123 .legend_title(Text::from("gender").size(12))
124 .y_axis(&Axis::new().value_thousands(true))
125 .legend(&Legend::new().x(1.0))
126 .build();
127
128 SubplotGrid::regular()
129 .plots(vec![&plot1, &plot2, &plot3, &plot4])
130 .rows(2)
131 .cols(2)
132 .v_gap(0.4)
133 .title(
134 Text::from("Regular Subplot Grid")
135 .size(16)
136 .font("Arial Black")
137 .y(0.95),
138 )
139 .build()
140 .plot();
141}
142
143fn irregular_grid_example() {
144 let dataset1 = CsvReader::new("data/penguins.csv")
145 .finish()
146 .unwrap()
147 .lazy()
148 .select([
149 col("species"),
150 col("sex").alias("gender"),
151 col("flipper_length_mm").cast(DataType::Int16),
152 col("body_mass_g").cast(DataType::Int16),
153 ])
154 .collect()
155 .unwrap();
156
157 let axis = Axis::new()
158 .show_line(true)
159 .show_grid(true)
160 .value_thousands(true)
161 .tick_direction(TickDirection::OutSide);
162
163 let plot1 = Histogram::builder()
164 .data(&dataset1)
165 .x("body_mass_g")
166 .group("species")
167 .opacity(0.5)
168 .colors(vec![Rgb(255, 165, 0), Rgb(147, 112, 219), Rgb(46, 139, 87)])
169 .plot_title(Text::from("Histogram").x(0.0).y(1.35).size(14))
170 .x_title(Text::from("body mass (g)").x(0.94).y(-0.35))
171 .y_title(Text::from("count").x(-0.062).y(0.83))
172 .x_axis(&axis)
173 .y_axis(&axis)
174 .legend_title(Text::from("species"))
175 .legend(&Legend::new().x(0.87).y(1.2))
176 .build();
177
178 let dataset2 = CsvReader::new("data/stock_prices.csv").finish().unwrap();
179
180 let increasing = Direction::new()
181 .line_color(Rgb(0, 200, 100))
182 .line_width(0.5);
183
184 let decreasing = Direction::new()
185 .line_color(Rgb(200, 50, 50))
186 .line_width(0.5);
187
188 let plot2 = CandlestickPlot::builder()
189 .data(&dataset2)
190 .dates("date")
191 .open("open")
192 .high("high")
193 .low("low")
194 .close("close")
195 .increasing(&increasing)
196 .decreasing(&decreasing)
197 .whisker_width(0.1)
198 .plot_title(Text::from("Candlestick").x(0.0).y(1.35).size(14))
199 .y_title(Text::from("price ($)").x(-0.06).y(0.76))
200 .y_axis(&Axis::new().show_axis(true).show_grid(true))
201 .build();
202
203 let dataset3 = CsvReader::new("data/heatmap.csv").finish().unwrap();
204
205 let plot3 = HeatMap::builder()
206 .data(&dataset3)
207 .x("x")
208 .y("y")
209 .z("z")
210 .color_bar(
211 &ColorBar::new()
212 .value_exponent(ValueExponent::None)
213 .separate_thousands(true)
214 .tick_length(5)
215 .tick_step(5000.0),
216 )
217 .plot_title(Text::from("Heat Map").x(0.0).y(1.35).size(14))
218 .color_scale(Palette::Viridis)
219 .build();
220
221 SubplotGrid::irregular()
222 .plots(vec![
223 (&plot1, 0, 0, 1, 1),
224 (&plot2, 0, 1, 1, 1),
225 (&plot3, 1, 0, 1, 2),
226 ])
227 .rows(2)
228 .cols(2)
229 .v_gap(0.35)
230 .h_gap(0.05)
231 .title(
232 Text::from("Irregular Subplot Grid")
233 .size(16)
234 .font("Arial Black")
235 .y(0.95),
236 )
237 .build()
238 .plot();
239}
240
241fn mixed_grid_example() {
242 let penguins = CsvReader::new("data/penguins.csv")
244 .finish()
245 .unwrap()
246 .lazy()
247 .select([
248 col("species"),
249 col("bill_length_mm"),
250 col("flipper_length_mm"),
251 col("body_mass_g"),
252 ])
253 .collect()
254 .unwrap();
255
256 let scatter_2d = ScatterPlot::builder()
257 .data(&penguins)
258 .x("bill_length_mm")
259 .y("flipper_length_mm")
260 .group("species")
261 .opacity(0.65)
262 .size(10)
263 .plot_title(Text::from("Penguins 2D").y(1.3))
264 .build();
265
266 let scatter_3d = Scatter3dPlot::builder()
268 .data(&penguins)
269 .x("bill_length_mm")
270 .y("flipper_length_mm")
271 .z("body_mass_g")
272 .group("species")
273 .opacity(0.35)
274 .size(6)
275 .plot_title(Text::from("Penguins 3D").y(1.45))
276 .build();
277
278 let polar_df = CsvReader::new("data/product_comparison_polar.csv")
280 .finish()
281 .unwrap();
282
283 let polar = ScatterPolar::builder()
284 .data(&polar_df)
285 .theta("angle")
286 .r("score")
287 .group("product")
288 .mode(Mode::LinesMarkers)
289 .size(10)
290 .plot_title(Text::from("Product Comparison (Polar)").y(1.5).x(0.72))
291 .legend(&Legend::new().x(0.8))
292 .build();
293
294 let sankey_df = CsvReader::new("data/energy_transition.csv")
296 .finish()
297 .unwrap();
298
299 let sankey = SankeyDiagram::builder()
300 .data(&sankey_df)
301 .sources("source")
302 .targets("target")
303 .values("value")
304 .orientation(Orientation::Horizontal)
305 .arrangement(Arrangement::Freeform)
306 .plot_title(Text::from("Energy Flow").y(1.2))
307 .build();
308
309 let map_df = CsvReader::new("data/cities.csv").finish().unwrap();
311
312 let scatter_map = ScatterMap::builder()
313 .data(&map_df)
314 .latitude("latitude")
315 .longitude("longitude")
316 .group("city")
317 .zoom(4)
318 .center([50.0, 5.0])
319 .opacity(0.8)
320 .plot_title(Text::from("Cities (Mapbox)").y(1.2))
321 .build();
322
323 let geo_df = CsvReader::new("data/world_cities.csv").finish().unwrap();
325
326 let scatter_geo = ScatterGeo::builder()
327 .data(&geo_df)
328 .lat("lat")
329 .lon("lon")
330 .group("continent")
331 .mode(Mode::Markers)
332 .size(10)
333 .color(Rgb(255, 140, 0))
334 .shape(Shape::Circle)
335 .plot_title(Text::from("Global Cities (Geo)").x(0.65).y(1.2))
336 .legend(&Legend::new().x(0.8))
337 .build();
338
339 SubplotGrid::regular()
340 .plots(vec![
341 &scatter_2d,
342 &scatter_3d,
343 &polar,
344 &sankey,
345 &scatter_map,
346 &scatter_geo,
347 ])
348 .rows(2)
349 .cols(3)
350 .h_gap(0.12)
351 .v_gap(0.22)
352 .title(
353 Text::from("Mixed Subplot Grid")
354 .size(16)
355 .font("Arial Black")
356 .y(0.95),
357 )
358 .build()
359 .plot();
360}