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(PlRefPath::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(
363 x_vals.len(),
364 vec![
365 Column::new("x".into(), x_vals),
366 Column::new("y".into(), y_vals),
367 Column::new("z".into(), z_vals),
368 Column::new("surface_type".into(), surface_type),
369 ],
370 )
371 .unwrap();
372
373 let config = FacetConfig::new().cols(3).rows(1);
374
375 let lighting = Lighting::new().ambient(0.6).diffuse(0.8).specular(0.4);
376
377 Mesh3D::builder()
378 .data(&dataset)
379 .x("x")
380 .y("y")
381 .z("z")
382 .facet("surface_type")
383 .facet_config(&config)
384 .color(Rgb(100, 150, 200))
385 .lighting(&lighting)
386 .plot_title(
387 Text::from("Mathematical Surfaces Comparison")
388 .font("Arial")
389 .size(20),
390 )
391 .build()
392 .plot();
393}
394
395fn piechart_example() {
396 let dataset = CsvReadOptions::default()
397 .with_has_header(true)
398 .try_into_reader_with_file_path(Some("data/industry_region.csv".into()))
399 .unwrap()
400 .finish()
401 .unwrap();
402
403 let facet_config = FacetConfig::new()
404 .cols(3)
405 .scales(FacetScales::Free)
406 .h_gap(0.08)
407 .v_gap(0.12)
408 .title_style(Text::from("").size(13).color(Rgb(60, 60, 60)));
409
410 PieChart::builder()
411 .data(&dataset)
412 .labels("category")
413 .facet("region")
414 .facet_config(&facet_config)
415 .colors(vec![
416 Rgb(192, 57, 43),
417 Rgb(39, 174, 96),
418 Rgb(41, 128, 185),
419 Rgb(243, 156, 18),
420 ])
421 .rotation(25.0)
422 .pull(0.02)
423 .plot_title(Text::from("Industry Analysis").size(18))
424 .build()
425 .plot();
426}
427
428fn sankeydiagram_example() {
429 let dataset = CsvReadOptions::default()
430 .with_has_header(true)
431 .try_into_reader_with_file_path(Some("data/energy_transition.csv".into()))
432 .unwrap()
433 .finish()
434 .unwrap();
435
436 let facet_config = FacetConfig::new()
437 .cols(4)
438 .h_gap(0.06)
439 .title_style(Text::from("").size(11).color(Rgb(50, 50, 50)));
440
441 let node_colors = vec![
442 Rgb(64, 64, 64),
443 Rgb(100, 149, 237),
444 Rgb(139, 69, 19),
445 Rgb(255, 195, 0),
446 Rgb(135, 206, 250),
447 Rgb(65, 105, 225),
448 Rgb(220, 20, 60),
449 Rgb(34, 139, 34),
450 ];
451
452 let link_colors = vec![
453 Rgb(220, 220, 220),
454 Rgb(200, 220, 245),
455 Rgb(220, 200, 180),
456 Rgb(255, 240, 200),
457 Rgb(220, 240, 255),
458 Rgb(200, 220, 240),
459 ];
460
461 SankeyDiagram::builder()
462 .data(&dataset)
463 .sources("source")
464 .targets("target")
465 .values("value")
466 .facet("year")
467 .facet_config(&facet_config)
468 .node_colors(node_colors)
469 .link_colors(link_colors)
470 .arrangement(Arrangement::Perpendicular)
471 .plot_title(
472 Text::from("Energy Transition Timeline (2020-2023)")
473 .font("Arial")
474 .size(16),
475 )
476 .pad(18)
477 .thickness(22)
478 .build()
479 .plot();
480}
481
482fn scatterplot_example() {
483 let dataset = LazyCsvReader::new(PlRefPath::new("data/penguins.csv"))
484 .finish()
485 .unwrap()
486 .select([
487 col("species"),
488 col("sex").alias("gender"),
489 col("bill_length_mm"),
490 col("bill_depth_mm"),
491 ])
492 .collect()
493 .unwrap();
494
495 let facet_config = FacetConfig::new()
496 .highlight_facet(true)
497 .unhighlighted_color(Rgb(220, 220, 220));
498
499 ScatterPlot::builder()
500 .data(&dataset)
501 .x("bill_length_mm")
502 .y("bill_depth_mm")
503 .group("gender")
504 .facet("species")
505 .facet_config(&facet_config)
506 .plot_title(Text::from("Penguin Bill Morphology with Gender Comparison"))
507 .x_title("bill length (mm)")
508 .y_title("bill depth (mm)")
509 .opacity(0.6)
510 .size(8)
511 .colors(vec![Rgb(128, 128, 128), Rgb(255, 0, 255), Rgb(0, 255, 255)])
512 .shapes(vec![Shape::Diamond, Shape::Circle, Shape::Square])
513 .legend_title("gender")
514 .build()
515 .plot();
516}
517
518fn scatter3d_example() {
519 let dataset = LazyCsvReader::new(PlRefPath::new("data/penguins.csv"))
520 .finish()
521 .unwrap()
522 .select([
523 col("species"),
524 col("sex").alias("gender"),
525 col("bill_length_mm").cast(DataType::Float32),
526 col("flipper_length_mm").cast(DataType::Int16),
527 col("body_mass_g").cast(DataType::Int16),
528 ])
529 .collect()
530 .unwrap();
531
532 let facet_config = FacetConfig::new()
533 .cols(3)
534 .highlight_facet(true)
535 .unhighlighted_color(Rgb(220, 220, 220));
536
537 Scatter3dPlot::builder()
538 .data(&dataset)
539 .x("body_mass_g")
540 .y("flipper_length_mm")
541 .z("bill_length_mm")
542 .facet("species")
543 .facet_config(&facet_config)
544 .opacity(0.6)
545 .size(6)
546 .colors(vec![Rgb(178, 34, 34), Rgb(65, 105, 225), Rgb(255, 140, 0)])
547 .plot_title("Penguin Morphological Traits - 3D Faceted Analysis")
548 .build()
549 .plot();
550}
551
552fn scatterpolar_example() {
553 let dataset = CsvReadOptions::default()
554 .with_has_header(true)
555 .try_into_reader_with_file_path(Some("data/wind_patterns.csv".into()))
556 .unwrap()
557 .finish()
558 .unwrap();
559
560 let facet_config = FacetConfig::new()
561 .highlight_facet(true)
562 .unhighlighted_color(Rgb(220, 220, 220))
563 .cols(3);
564
565 ScatterPolar::builder()
566 .data(&dataset)
567 .theta("angle")
568 .r("speed")
569 .group("time")
570 .facet("season")
571 .facet_config(&facet_config)
572 .plot_title(Text::from("Wind Patterns by Season and Time of Day"))
573 .mode(Mode::LinesMarkers)
574 .opacity(0.7)
575 .size(7)
576 .width(2.5)
577 .colors(vec![Rgb(255, 105, 180), Rgb(30, 144, 255)])
578 .shapes(vec![Shape::Circle, Shape::Diamond])
579 .lines(vec![Line::Solid, Line::DashDot])
580 .legend_title("time of day")
581 .build()
582 .plot();
583}
584
585fn timeseriesplot_example() {
586 let dataset = CsvReadOptions::default()
587 .with_has_header(true)
588 .try_into_reader_with_file_path(Some("data/financial_timeseries.csv".into()))
589 .unwrap()
590 .finish()
591 .unwrap();
592
593 let facet_config = FacetConfig::new()
594 .highlight_facet(true)
595 .unhighlighted_color(Rgb(220, 220, 220));
596
597 TimeSeriesPlot::builder()
598 .data(&dataset)
599 .x("date")
600 .y("revenue")
601 .additional_series(vec!["costs"])
602 .facet("region")
603 .facet_config(&facet_config)
604 .plot_title(Text::from("Regional Financial Metrics"))
605 .x_title("Month")
606 .y_title("Amount ($)")
607 .legend_title("Metric")
608 .width(2.0)
609 .with_shape(false)
610 .colors(vec![Rgb(255, 105, 180), Rgb(30, 144, 255)])
611 .lines(vec![Line::Solid, Line::Dash])
612 .build()
613 .plot();
614}
615
616fn surfaceplot_example() {
617 let n: usize = 50;
618 let x_base: Vec<f64> = (0..n)
619 .map(|i| {
620 let step = (5.0 - (-5.0)) / (n - 1) as f64;
621 -5.0 + step * i as f64
622 })
623 .collect();
624 let y_base: Vec<f64> = (0..n)
625 .map(|i| {
626 let step = (5.0 - (-5.0)) / (n - 1) as f64;
627 -5.0 + step * i as f64
628 })
629 .collect();
630
631 let mut x_all = Vec::new();
632 let mut y_all = Vec::new();
633 let mut z_all = Vec::new();
634 let mut category_all = Vec::new();
635
636 type SurfaceFunction = Box<dyn Fn(f64, f64) -> f64>;
637 let functions: Vec<(&str, SurfaceFunction)> = vec![
638 (
639 "Sine Wave",
640 Box::new(|xi: f64, yj: f64| (xi * xi + yj * yj).sqrt().sin()),
641 ),
642 ("Saddle", Box::new(|xi: f64, yj: f64| xi * xi - yj * yj)),
643 (
644 "Gaussian",
645 Box::new(|xi: f64, yj: f64| (-0.5 * (xi * xi + yj * yj)).exp()),
646 ),
647 ];
648
649 for (name, func) in &functions {
650 for &xi in x_base.iter() {
651 for &yj in y_base.iter() {
652 x_all.push(xi);
653 y_all.push(yj);
654 z_all.push(func(xi, yj));
655 category_all.push(*name);
656 }
657 }
658 }
659
660 let dataset = df![
661 "x" => &x_all,
662 "y" => &y_all,
663 "z" => &z_all,
664 "function" => &category_all,
665 ]
666 .unwrap();
667
668 SurfacePlot::builder()
669 .data(&dataset)
670 .x("x")
671 .y("y")
672 .z("z")
673 .facet("function")
674 .facet_config(&FacetConfig::new().cols(3).rows(1).h_gap(0.08).v_gap(0.12))
675 .plot_title(
676 Text::from("3D Mathematical Functions")
677 .font("Arial")
678 .size(20),
679 )
680 .color_scale(Palette::Viridis)
681 .opacity(0.9)
682 .build()
683 .plot();
684}