1use plotlars::{
2 Arrangement, BarPlot, BoxPlot, ContourPlot, FacetConfig, FacetScales, HeatMap, Histogram,
3 Lighting, Line, LinePlot, Mesh3D, Mode, Palette, PieChart, Plot, Rgb, SankeyDiagram,
4 Scatter3dPlot, ScatterPlot, ScatterPolar, Shape, SurfacePlot, Text, TimeSeriesPlot,
5};
6use polars::prelude::*;
7
8fn main() {
9 barplot_example();
10 boxplot_example();
11 contourplot_example();
12 heatmap_example();
13 histogram_example();
14 lineplot_example();
15 mesh3d_example();
16 piechart_example();
17 sankeydiagram_example();
18 scatter3d_example();
19 scatterplot_example();
20 scatterpolar_example();
21 surfaceplot_example();
22 timeseriesplot_example();
23}
24
25fn barplot_example() {
26 let regional_data = CsvReadOptions::default()
27 .with_has_header(true)
28 .try_into_reader_with_file_path(Some("data/regional_sales.csv".into()))
29 .unwrap()
30 .finish()
31 .unwrap();
32
33 let facet_config = FacetConfig::new().cols(4).rows(2).h_gap(0.05).v_gap(0.30);
34
35 BarPlot::builder()
36 .data(®ional_data)
37 .labels("product")
38 .values("sales")
39 .facet("region")
40 .facet_config(&facet_config)
41 .color(Rgb(70, 130, 180))
42 .plot_title(Text::from("8-Region Sales Facet Grid"))
43 .x_title("Product")
44 .y_title("Sales")
45 .build()
46 .plot();
47}
48
49fn boxplot_example() {
50 let dataset = LazyCsvReader::new(PlPath::new("data/penguins.csv"))
51 .finish()
52 .unwrap()
53 .select([
54 col("species"),
55 col("island"),
56 col("sex"),
57 col("body_mass_g").cast(DataType::Int16),
58 ])
59 .collect()
60 .unwrap();
61
62 BoxPlot::builder()
63 .data(&dataset)
64 .labels("island")
65 .values("body_mass_g")
66 .group("sex")
67 .colors(vec![Rgb(0, 119, 182), Rgb(0, 180, 216), Rgb(144, 224, 239)])
68 .facet("species")
69 .facet_config(&FacetConfig::new().cols(3))
70 .plot_title(Text::from("Body Mass by Island, Sex and Species").size(16))
71 .x_title(Text::from("Island"))
72 .y_title(Text::from("Body Mass (g)"))
73 .legend_title(Text::from("Sex"))
74 .build()
75 .plot();
76}
77
78fn contourplot_example() {
79 let mut x_vals = Vec::new();
80 let mut y_vals = Vec::new();
81 let mut z_vals = Vec::new();
82 let mut patterns = Vec::new();
83
84 let grid_size = 25;
85
86 for i in 0..grid_size {
88 for j in 0..grid_size {
89 let x = (i as f64 - 12.0) / 3.0;
90 let y = (j as f64 - 12.0) / 3.0;
91 let z = (-x * x - y * y).exp();
92 x_vals.push(x);
93 y_vals.push(y);
94 z_vals.push(z);
95 patterns.push("Gaussian");
96 }
97 }
98
99 for i in 0..grid_size {
101 for j in 0..grid_size {
102 let x = (i as f64 - 12.0) / 3.0;
103 let y = (j as f64 - 12.0) / 3.0;
104 let z = x * x - y * y;
105 x_vals.push(x);
106 y_vals.push(y);
107 z_vals.push(z);
108 patterns.push("Saddle");
109 }
110 }
111
112 for i in 0..grid_size {
114 for j in 0..grid_size {
115 let x = (i as f64 - 12.0) / 3.0;
116 let y = (j as f64 - 12.0) / 3.0;
117 let r = (x * x + y * y).sqrt();
118 let z = (r * 2.0).sin() / (r + 0.1);
119 x_vals.push(x);
120 y_vals.push(y);
121 z_vals.push(z);
122 patterns.push("Ripple");
123 }
124 }
125
126 for i in 0..grid_size {
128 for j in 0..grid_size {
129 let x = (i as f64 - 12.0) / 3.0;
130 let y = (j as f64 - 12.0) / 3.0;
131 let z = x * x + y * y;
132 x_vals.push(x);
133 y_vals.push(y);
134 z_vals.push(z);
135 patterns.push("Paraboloid");
136 }
137 }
138
139 for i in 0..grid_size {
141 for j in 0..grid_size {
142 let x = (i as f64 - 12.0) / 3.0;
143 let y = (j as f64 - 12.0) / 3.0;
144 let z = (x * 2.0).sin() * (y * 2.0).cos();
145 x_vals.push(x);
146 y_vals.push(y);
147 z_vals.push(z);
148 patterns.push("Wave");
149 }
150 }
151
152 for i in 0..grid_size {
154 for j in 0..grid_size {
155 let x = (i as f64 - 12.0) / 3.0;
156 let y = (j as f64 - 12.0) / 3.0;
157 let z = ((x + y) * 2.0).sin();
158 x_vals.push(x);
159 y_vals.push(y);
160 z_vals.push(z);
161 patterns.push("Diagonal");
162 }
163 }
164
165 let contour_data = df! {
166 "x" => x_vals,
167 "y" => y_vals,
168 "z" => z_vals,
169 "pattern" => patterns,
170 }
171 .unwrap();
172
173 ContourPlot::builder()
174 .data(&contour_data)
175 .x("x")
176 .y("y")
177 .z("z")
178 .facet("pattern")
179 .facet_config(&FacetConfig::new().rows(2).cols(3))
180 .plot_title(Text::from("Mathematical Surface Patterns").size(16))
181 .x_title(Text::from("X Axis"))
182 .y_title(Text::from("Y Axis"))
183 .build()
184 .plot();
185}
186
187fn heatmap_example() {
188 let mut regions = Vec::new();
189 let mut x_coords = Vec::new();
190 let mut y_coords = Vec::new();
191 let mut intensities = Vec::new();
192
193 let region_names = ["North", "South", "East", "West"];
194 let x_labels = ["X0", "X1", "X2", "X3", "X4"];
195 let y_labels = ["Y0", "Y1", "Y2", "Y3", "Y4"];
196
197 for (region_idx, region_name) in region_names.iter().enumerate() {
198 for (y_idx, y_label) in y_labels.iter().enumerate() {
199 for (x_idx, x_label) in x_labels.iter().enumerate() {
200 regions.push(*region_name);
201 x_coords.push(*x_label);
202 y_coords.push(*y_label);
203
204 let intensity = match region_idx {
205 0 => (x_idx + y_idx * 5) as f64 * 4.0,
206 1 => {
207 let dx = x_idx as f64 - 2.0;
208 let dy = y_idx as f64 - 2.0;
209 100.0 - (dx * dx + dy * dy) * 4.0
210 }
211 2 => ((x_idx * x_idx + y_idx * y_idx) as f64).sqrt() * 10.0,
212 3 => x_idx.max(y_idx) as f64 * 20.0,
213 _ => 0.0,
214 };
215
216 intensities.push(intensity);
217 }
218 }
219 }
220
221 let heatmap_data = df! {
222 "region" => regions,
223 "x" => x_coords,
224 "y" => y_coords,
225 "intensity" => intensities,
226 }
227 .unwrap();
228
229 HeatMap::builder()
230 .data(&heatmap_data)
231 .x("x")
232 .y("y")
233 .z("intensity")
234 .facet("region")
235 .facet_config(&FacetConfig::new().rows(2).cols(2))
236 .plot_title(Text::from("Regional Heat Intensity Patterns").size(16))
237 .x_title(Text::from("X Coordinate"))
238 .y_title(Text::from("Y Coordinate"))
239 .build()
240 .plot();
241}
242
243fn histogram_example() {
244 let csv_path = "data/temperature_seasonal.csv";
245
246 let df = CsvReadOptions::default()
247 .with_has_header(true)
248 .try_into_reader_with_file_path(Some(csv_path.into()))
249 .unwrap()
250 .finish()
251 .unwrap();
252
253 let facet_config = FacetConfig::new().rows(2).cols(3);
254
255 Histogram::builder()
256 .data(&df)
257 .x("temperature")
258 .group("season")
259 .facet("city")
260 .facet_config(&facet_config)
261 .opacity(0.5)
262 .plot_title("Seasonal Temperature Distribution by City")
263 .x_title("Temperature (°C)")
264 .y_title("Frequency")
265 .build()
266 .plot();
267}
268
269fn lineplot_example() {
270 let dataset = create_lineplot_dataset();
271
272 let facet_config = FacetConfig::new().highlight_facet(true);
273
274 LinePlot::builder()
275 .data(&dataset)
276 .x("x")
277 .y("sine")
278 .facet("category")
279 .facet_config(&facet_config)
280 .plot_title(Text::from("Sine Wave Patterns by Amplitude Level"))
281 .x_title("x")
282 .y_title("sin(x)")
283 .width(2.5)
284 .with_shape(false)
285 .color(Rgb(255, 69, 0))
286 .build()
287 .plot();
288}
289
290fn create_lineplot_dataset() -> DataFrame {
291 let x_values: Vec<f64> = (0..200)
292 .map(|i| {
293 let step = (2.0 * std::f64::consts::PI - 0.0) / 199.0;
294 0.0 + step * i as f64
295 })
296 .collect();
297
298 let mut category = Vec::new();
299 let mut amplitude = Vec::new();
300 let mut sine_values = Vec::new();
301
302 for cat in ["Low", "Medium", "High"].iter() {
303 let amp = match *cat {
304 "Low" => 0.5,
305 "Medium" => 1.0,
306 "High" => 1.5,
307 _ => 1.0,
308 };
309
310 for &x in &x_values {
311 category.push(cat.to_string());
312 amplitude.push(amp);
313 sine_values.push(amp * x.sin());
314 }
315 }
316
317 let x_repeated: Vec<f64> = x_values
318 .iter()
319 .cycle()
320 .take(x_values.len() * 3)
321 .copied()
322 .collect();
323
324 df![
325 "x" => &x_repeated,
326 "category" => &category,
327 "amplitude" => &litude,
328 "sine" => &sine_values,
329 ]
330 .unwrap()
331}
332
333fn mesh3d_example() {
334 let mut x_vals = Vec::new();
335 let mut y_vals = Vec::new();
336 let mut z_vals = Vec::new();
337 let mut surface_type = Vec::new();
338
339 let n = 25;
340
341 for surface in ["Gaussian", "Saddle", "Ripple"].iter() {
342 for i in 0..n {
343 for j in 0..n {
344 let x = (i as f64 / (n - 1) as f64) * 4.0 - 2.0;
345 let y = (j as f64 / (n - 1) as f64) * 4.0 - 2.0;
346
347 let z = match *surface {
348 "Gaussian" => (-0.5 * (x * x + y * y)).exp(),
349 "Saddle" => 0.3 * (x * x - y * y),
350 "Ripple" => 0.4 * ((x * 3.0).sin() + (y * 3.0).cos()),
351 _ => 0.0,
352 };
353
354 x_vals.push(x);
355 y_vals.push(y);
356 z_vals.push(z);
357 surface_type.push(surface.to_string());
358 }
359 }
360 }
361
362 let dataset = DataFrame::new(vec![
363 Column::new("x".into(), x_vals),
364 Column::new("y".into(), y_vals),
365 Column::new("z".into(), z_vals),
366 Column::new("surface_type".into(), surface_type),
367 ])
368 .unwrap();
369
370 let config = FacetConfig::new().cols(3).rows(1);
371
372 let lighting = Lighting::new().ambient(0.6).diffuse(0.8).specular(0.4);
373
374 Mesh3D::builder()
375 .data(&dataset)
376 .x("x")
377 .y("y")
378 .z("z")
379 .facet("surface_type")
380 .facet_config(&config)
381 .color(Rgb(100, 150, 200))
382 .lighting(&lighting)
383 .plot_title(
384 Text::from("Mathematical Surfaces Comparison")
385 .font("Arial")
386 .size(20),
387 )
388 .build()
389 .plot();
390}
391
392fn piechart_example() {
393 let dataset = CsvReadOptions::default()
394 .with_has_header(true)
395 .try_into_reader_with_file_path(Some("data/industry_region.csv".into()))
396 .unwrap()
397 .finish()
398 .unwrap();
399
400 let facet_config = FacetConfig::new()
401 .cols(3)
402 .scales(FacetScales::Free)
403 .h_gap(0.08)
404 .v_gap(0.12)
405 .title_style(Text::from("").size(13).color(Rgb(60, 60, 60)));
406
407 PieChart::builder()
408 .data(&dataset)
409 .labels("category")
410 .facet("region")
411 .facet_config(&facet_config)
412 .colors(vec![
413 Rgb(192, 57, 43),
414 Rgb(39, 174, 96),
415 Rgb(41, 128, 185),
416 Rgb(243, 156, 18),
417 ])
418 .rotation(25.0)
419 .pull(0.02)
420 .plot_title(Text::from("Industry Analysis").size(18))
421 .build()
422 .plot();
423}
424
425fn sankeydiagram_example() {
426 let dataset = CsvReadOptions::default()
427 .with_has_header(true)
428 .try_into_reader_with_file_path(Some("data/energy_transition.csv".into()))
429 .unwrap()
430 .finish()
431 .unwrap();
432
433 let facet_config = FacetConfig::new()
434 .cols(4)
435 .h_gap(0.06)
436 .title_style(Text::from("").size(11).color(Rgb(50, 50, 50)));
437
438 let node_colors = vec![
439 Rgb(64, 64, 64),
440 Rgb(100, 149, 237),
441 Rgb(139, 69, 19),
442 Rgb(255, 195, 0),
443 Rgb(135, 206, 250),
444 Rgb(65, 105, 225),
445 Rgb(220, 20, 60),
446 Rgb(34, 139, 34),
447 ];
448
449 let link_colors = vec![
450 Rgb(220, 220, 220),
451 Rgb(200, 220, 245),
452 Rgb(220, 200, 180),
453 Rgb(255, 240, 200),
454 Rgb(220, 240, 255),
455 Rgb(200, 220, 240),
456 ];
457
458 SankeyDiagram::builder()
459 .data(&dataset)
460 .sources("source")
461 .targets("target")
462 .values("value")
463 .facet("year")
464 .facet_config(&facet_config)
465 .node_colors(node_colors)
466 .link_colors(link_colors)
467 .arrangement(Arrangement::Perpendicular)
468 .plot_title(
469 Text::from("Energy Transition Timeline (2020-2023)")
470 .font("Arial")
471 .size(16),
472 )
473 .pad(18)
474 .thickness(22)
475 .build()
476 .plot();
477}
478
479fn scatterplot_example() {
480 let dataset = LazyCsvReader::new(PlPath::new("data/penguins.csv"))
481 .finish()
482 .unwrap()
483 .select([
484 col("species"),
485 col("sex").alias("gender"),
486 col("bill_length_mm"),
487 col("bill_depth_mm"),
488 ])
489 .collect()
490 .unwrap();
491
492 let facet_config = FacetConfig::new()
493 .highlight_facet(true)
494 .unhighlighted_color(Rgb(220, 220, 220));
495
496 ScatterPlot::builder()
497 .data(&dataset)
498 .x("bill_length_mm")
499 .y("bill_depth_mm")
500 .group("gender")
501 .facet("species")
502 .facet_config(&facet_config)
503 .plot_title(Text::from("Penguin Bill Morphology with Gender Comparison"))
504 .x_title("bill length (mm)")
505 .y_title("bill depth (mm)")
506 .opacity(0.6)
507 .size(8)
508 .colors(vec![Rgb(128, 128, 128), Rgb(255, 0, 255), Rgb(0, 255, 255)])
509 .shapes(vec![Shape::Diamond, Shape::Circle, Shape::Square])
510 .legend_title("gender")
511 .build()
512 .plot();
513}
514
515fn scatter3d_example() {
516 let dataset = LazyCsvReader::new(PlPath::new("data/penguins.csv"))
517 .finish()
518 .unwrap()
519 .select([
520 col("species"),
521 col("sex").alias("gender"),
522 col("bill_length_mm").cast(DataType::Float32),
523 col("flipper_length_mm").cast(DataType::Int16),
524 col("body_mass_g").cast(DataType::Int16),
525 ])
526 .collect()
527 .unwrap();
528
529 let facet_config = FacetConfig::new()
530 .cols(3)
531 .highlight_facet(true)
532 .unhighlighted_color(Rgb(220, 220, 220));
533
534 Scatter3dPlot::builder()
535 .data(&dataset)
536 .x("body_mass_g")
537 .y("flipper_length_mm")
538 .z("bill_length_mm")
539 .facet("species")
540 .facet_config(&facet_config)
541 .opacity(0.6)
542 .size(6)
543 .colors(vec![Rgb(178, 34, 34), Rgb(65, 105, 225), Rgb(255, 140, 0)])
544 .plot_title("Penguin Morphological Traits - 3D Faceted Analysis")
545 .build()
546 .plot();
547}
548
549fn scatterpolar_example() {
550 let dataset = CsvReadOptions::default()
551 .with_has_header(true)
552 .try_into_reader_with_file_path(Some("data/wind_patterns.csv".into()))
553 .unwrap()
554 .finish()
555 .unwrap();
556
557 let facet_config = FacetConfig::new()
558 .highlight_facet(true)
559 .unhighlighted_color(Rgb(220, 220, 220))
560 .cols(3);
561
562 ScatterPolar::builder()
563 .data(&dataset)
564 .theta("angle")
565 .r("speed")
566 .group("time")
567 .facet("season")
568 .facet_config(&facet_config)
569 .plot_title(Text::from("Wind Patterns by Season and Time of Day"))
570 .mode(Mode::LinesMarkers)
571 .opacity(0.7)
572 .size(7)
573 .width(2.5)
574 .colors(vec![Rgb(255, 105, 180), Rgb(30, 144, 255)])
575 .shapes(vec![Shape::Circle, Shape::Diamond])
576 .lines(vec![Line::Solid, Line::DashDot])
577 .legend_title("time of day")
578 .build()
579 .plot();
580}
581
582fn timeseriesplot_example() {
583 let dataset = CsvReadOptions::default()
584 .with_has_header(true)
585 .try_into_reader_with_file_path(Some("data/financial_timeseries.csv".into()))
586 .unwrap()
587 .finish()
588 .unwrap();
589
590 let facet_config = FacetConfig::new()
591 .highlight_facet(true)
592 .unhighlighted_color(Rgb(220, 220, 220));
593
594 TimeSeriesPlot::builder()
595 .data(&dataset)
596 .x("date")
597 .y("revenue")
598 .additional_series(vec!["costs"])
599 .facet("region")
600 .facet_config(&facet_config)
601 .plot_title(Text::from("Regional Financial Metrics"))
602 .x_title("Month")
603 .y_title("Amount ($)")
604 .legend_title("Metric")
605 .width(2.0)
606 .with_shape(false)
607 .colors(vec![Rgb(255, 105, 180), Rgb(30, 144, 255)])
608 .lines(vec![Line::Solid, Line::Dash])
609 .build()
610 .plot();
611}
612
613fn surfaceplot_example() {
614 let n: usize = 50;
615 let x_base: Vec<f64> = (0..n)
616 .map(|i| {
617 let step = (5.0 - (-5.0)) / (n - 1) as f64;
618 -5.0 + step * i as f64
619 })
620 .collect();
621 let y_base: Vec<f64> = (0..n)
622 .map(|i| {
623 let step = (5.0 - (-5.0)) / (n - 1) as f64;
624 -5.0 + step * i as f64
625 })
626 .collect();
627
628 let mut x_all = Vec::new();
629 let mut y_all = Vec::new();
630 let mut z_all = Vec::new();
631 let mut category_all = Vec::new();
632
633 type SurfaceFunction = Box<dyn Fn(f64, f64) -> f64>;
634 let functions: Vec<(&str, SurfaceFunction)> = vec![
635 (
636 "Sine Wave",
637 Box::new(|xi: f64, yj: f64| (xi * xi + yj * yj).sqrt().sin()),
638 ),
639 ("Saddle", Box::new(|xi: f64, yj: f64| xi * xi - yj * yj)),
640 (
641 "Gaussian",
642 Box::new(|xi: f64, yj: f64| (-0.5 * (xi * xi + yj * yj)).exp()),
643 ),
644 ];
645
646 for (name, func) in &functions {
647 for &xi in x_base.iter() {
648 for &yj in y_base.iter() {
649 x_all.push(xi);
650 y_all.push(yj);
651 z_all.push(func(xi, yj));
652 category_all.push(*name);
653 }
654 }
655 }
656
657 let dataset = df![
658 "x" => &x_all,
659 "y" => &y_all,
660 "z" => &z_all,
661 "function" => &category_all,
662 ]
663 .unwrap();
664
665 SurfacePlot::builder()
666 .data(&dataset)
667 .x("x")
668 .y("y")
669 .z("z")
670 .facet("function")
671 .facet_config(&FacetConfig::new().cols(3).rows(1).h_gap(0.08).v_gap(0.12))
672 .plot_title(
673 Text::from("3D Mathematical Functions")
674 .font("Arial")
675 .size(20),
676 )
677 .color_scale(Palette::Viridis)
678 .opacity(0.9)
679 .build()
680 .plot();
681}