pub struct Aes {
pub mappings: Vec<AesMapping>,
pub after_scale: Vec<AfterScaleSpec>,
}Expand description
Builder for aesthetic mappings.
Fields§
§mappings: Vec<AesMapping>§after_scale: Vec<AfterScaleSpec>Post-scale color derivations (after_scale).
Implementations§
Source§impl Aes
impl Aes
Sourcepub fn new() -> Self
pub fn new() -> Self
Examples found in repository?
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let df = df! {
6 "fruit" => ["Apple", "Apple", "Apple", "Banana", "Banana",
7 "Cherry", "Cherry", "Cherry", "Cherry", "Date"],
8 }?;
9
10 GGPlot::new(df)
11 .aes(Aes::new().x("fruit"))
12 .geom_bar()
13 .title("Fruit Counts")
14 .xlab("Fruit")
15 .ylab("Count")
16 .save("bar_chart.svg")?;
17
18 println!("Saved bar_chart.svg");
19 Ok(())
20}More examples
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let df = df! {
6 "language" => ["Rust", "Python", "JavaScript", "Go", "TypeScript", "Java", "C++"],
7 "satisfaction" => [92.0, 88.0, 85.0, 78.0, 82.0, 70.0, 75.0],
8 }?;
9
10 // Horizontal bar chart using coord_flip
11 GGPlot::new(df)
12 .aes(Aes::new().x("language").y("satisfaction"))
13 .geom_col()
14 .coord_flip()
15 .title("Developer Satisfaction by Language")
16 .xlab("Language")
17 .ylab("Satisfaction Score")
18 .save("coord_flip.svg")?;
19
20 println!("Saved coord_flip.svg");
21 Ok(())
22}45fn scatter() -> Result<(), Box<dyn std::error::Error>> {
46 let n = 150;
47 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
48 let y: Vec<f64> = (0..n)
49 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
50 .collect();
51 let species: Vec<&str> = (0..n)
52 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
53 .collect();
54
55 let df = df! { "x" => x, "y" => y, "species" => species }?;
56 GGPlot::new(df)
57 .aes(Aes::new().x("x").y("y").color("species"))
58 .geom_point()
59 .scale_color_brewer(PaletteName::Set1)
60 .title("Grouped Scatter")
61 .xlab("Sepal Length")
62 .ylab("Sepal Width")
63 .theme_minimal()
64 .save_with_size(&out("scatter"), W, H)?;
65 Ok(())
66}
67
68/// Points overlaid with a LOESS trend line and confidence band.
69fn smooth() -> Result<(), Box<dyn std::error::Error>> {
70 let n = 120;
71 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
72 let y: Vec<f64> = (0..n)
73 .map(|i| {
74 let t = i as f64 * 0.1;
75 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
76 })
77 .collect();
78
79 let df = df! { "x" => x, "y" => y }?;
80 GGPlot::new(df)
81 .aes(Aes::new().x("x").y("y"))
82 .geom_point()
83 .geom_smooth_with(GeomSmooth {
84 method: SmoothMethod::Loess { span: 0.5 },
85 ..Default::default()
86 })
87 .title("LOESS Smoothing")
88 .xlab("x")
89 .ylab("y")
90 .theme_bw()
91 .save_with_size(&out("smooth"), W, H)?;
92 Ok(())
93}
94
95/// Histogram of an approximately-normal sample.
96fn histogram() -> Result<(), Box<dyn std::error::Error>> {
97 let values: Vec<f64> = (0..1500)
98 .map(|i: i32| {
99 let r: f64 = (0..6)
100 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
101 .sum();
102 (r - 3.0) * 2.0
103 })
104 .collect();
105
106 let df = df! { "measurement" => values }?;
107 GGPlot::new(df)
108 .aes(Aes::new().x("measurement"))
109 .geom_histogram_with(GeomHistogram {
110 bins: 30,
111 ..Default::default()
112 })
113 .title("Histogram")
114 .xlab("Value")
115 .ylab("Count")
116 .theme_minimal()
117 .save_with_size(&out("histogram"), W, H)?;
118 Ok(())
119}
120
121/// Bar chart of category counts with a fill palette.
122fn bar() -> Result<(), Box<dyn std::error::Error>> {
123 let mut fruit: Vec<&str> = Vec::new();
124 for (f, c) in [
125 ("Apple", 8),
126 ("Banana", 5),
127 ("Cherry", 11),
128 ("Date", 3),
129 ("Elder", 7),
130 ] {
131 for _ in 0..c {
132 fruit.push(f);
133 }
134 }
135 let df = df! { "fruit" => fruit }?;
136 GGPlot::new(df)
137 .aes(Aes::new().x("fruit").fill("fruit"))
138 .geom_bar()
139 .scale_fill_brewer(PaletteName::Set2)
140 .title("Bar Chart")
141 .xlab("Fruit")
142 .ylab("Count")
143 .theme_minimal()
144 .save_with_size(&out("bar"), W, H)?;
145 Ok(())
146}
147
148/// Grouped boxplots.
149fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
150 let n = 240;
151 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
152 let value: Vec<f64> = (0..n)
153 .map(|i| {
154 let base = (i % 4) as f64 * 1.5;
155 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
156 })
157 .collect();
158
159 let df = df! { "group" => group, "value" => value }?;
160 GGPlot::new(df)
161 .aes(Aes::new().x("group").y("value"))
162 .geom_boxplot_with(GeomBoxplot {
163 fill: (70, 130, 180),
164 ..Default::default()
165 })
166 .title("Boxplot")
167 .xlab("Group")
168 .ylab("Value")
169 .theme_bw()
170 .save_with_size(&out("boxplot"), W, H)?;
171 Ok(())
172}
173
174/// Violin plots of grouped distributions.
175fn violin() -> Result<(), Box<dyn std::error::Error>> {
176 let n = 360;
177 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
178 let value: Vec<f64> = (0..n)
179 .map(|i| {
180 let g = (i % 3) as f64;
181 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
182 })
183 .collect();
184
185 let df = df! { "group" => group, "value" => value }?;
186 GGPlot::new(df)
187 .aes(Aes::new().x("group").y("value").fill("group"))
188 .geom_violin()
189 .scale_fill_brewer(PaletteName::Accent)
190 .title("Violin")
191 .xlab("Group")
192 .ylab("Value")
193 .theme_minimal()
194 .save_with_size(&out("violin"), W, H)?;
195 Ok(())
196}
197
198/// Spiral scatter coloured by a continuous variable (viridis).
199fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
200 let n = 400;
201 let x: Vec<f64> = (0..n)
202 .map(|i| {
203 let t = i as f64 * 0.05;
204 t.cos() * (1.0 + t * 0.12)
205 })
206 .collect();
207 let y: Vec<f64> = (0..n)
208 .map(|i| {
209 let t = i as f64 * 0.05;
210 t.sin() * (1.0 + t * 0.12)
211 })
212 .collect();
213 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
214
215 let df = df! { "x" => x, "y" => y, "z" => z }?;
216 GGPlot::new(df)
217 .aes(Aes::new().x("x").y("y").color("z"))
218 .geom_point()
219 .scale_color_viridis_c()
220 .title("Continuous Color (viridis)")
221 .xlab("x")
222 .ylab("y")
223 .theme_minimal()
224 .save_with_size(&out("continuous_color"), W, H)?;
225 Ok(())
226}
227
228/// Faceted scatter, one panel per group.
229fn facet() -> Result<(), Box<dyn std::error::Error>> {
230 let n = 180;
231 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
232 let y: Vec<f64> = (0..n)
233 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
234 .collect();
235 let species: Vec<&str> = (0..n)
236 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
237 .collect();
238
239 let df = df! { "x" => x, "y" => y, "species" => species }?;
240 GGPlot::new(df)
241 .aes(Aes::new().x("x").y("y").color("species"))
242 .geom_point()
243 .facet_wrap("species", Some(3))
244 .scale_color_brewer(PaletteName::Set1)
245 .title("Facet Wrap")
246 .xlab("x")
247 .ylab("y")
248 .theme_bw()
249 .save_with_size(&out("facet"), W, H)?;
250 Ok(())
251}
252
253/// Overlapping density curves by group.
254fn density() -> Result<(), Box<dyn std::error::Error>> {
255 let n = 600;
256 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
257 let value: Vec<f64> = (0..n)
258 .map(|i| {
259 let shift = (i % 2) as f64 * 2.5;
260 let t = i as f64 * 0.05;
261 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
262 })
263 .collect();
264
265 let df = df! { "value" => value, "group" => group }?;
266 GGPlot::new(df)
267 .aes(Aes::new().x("value").fill("group").color("group"))
268 .geom_density()
269 .scale_fill_brewer(PaletteName::Set1)
270 .scale_color_brewer(PaletteName::Set1)
271 .title("Density by Group")
272 .xlab("Value")
273 .ylab("Density")
274 .theme_minimal()
275 .save_with_size(&out("density"), W, H)?;
276 Ok(())
277}
278
279/// Filled contour bands from a gridded surface.
280fn contour_filled() -> Result<(), Box<dyn std::error::Error>> {
281 let (mut x, mut y, mut z) = (Vec::new(), Vec::new(), Vec::new());
282 for i in 0..40 {
283 for j in 0..40 {
284 let xv = i as f64 * 0.25 - 5.0;
285 let yv = j as f64 * 0.25 - 5.0;
286 x.push(xv);
287 y.push(yv);
288 z.push((xv * 0.6).sin() * (yv * 0.6).cos() + (-(xv * xv + yv * yv) / 30.0).exp());
289 }
290 }
291 let df = df! { "x" => x, "y" => y, "z" => z }?;
292 GGPlot::new(df)
293 .aes(Aes::new().x("x").y("y"))
294 .geom_contour_filled()
295 .scale_fill_viridis_c()
296 .title("Filled Contours")
297 .theme_minimal()
298 .save_with_size(&out("contour_filled"), W, H)?;
299 Ok(())
300}
301
302/// Hexagonal binning of a 2-D point cloud.
303fn hexbin() -> Result<(), Box<dyn std::error::Error>> {
304 let n = 4000;
305 let x: Vec<f64> = (0..n)
306 .map(|i| {
307 let t = i as f64;
308 (t * 0.017).sin() * 2.0 + ((i * 7919 % 1000) as f64 / 1000.0 - 0.5) * 3.0
309 })
310 .collect();
311 let y: Vec<f64> = (0..n)
312 .map(|i| {
313 let t = i as f64;
314 (t * 0.017).cos() * 2.0 + ((i * 6323 % 1000) as f64 / 1000.0 - 0.5) * 3.0
315 })
316 .collect();
317 let df = df! { "x" => x, "y" => y }?;
318 GGPlot::new(df)
319 .aes(Aes::new().x("x").y("y"))
320 .geom_hex()
321 .scale_fill_viridis_c()
322 .title("Hex Binning")
323 .theme_minimal()
324 .save_with_size(&out("hexbin"), W, H)?;
325 Ok(())
326}
327
328/// Heatmap of a gridded value with `geom_tile`.
329fn heatmap() -> Result<(), Box<dyn std::error::Error>> {
330 let (mut x, mut y, mut fill) = (Vec::new(), Vec::new(), Vec::new());
331 for i in 0..14 {
332 for j in 0..14 {
333 x.push(i as f64);
334 y.push(j as f64);
335 fill.push((i as f64 * 0.5).sin() * (j as f64 * 0.5).cos());
336 }
337 }
338 let df = df! { "x" => x, "y" => y, "fill" => fill }?;
339 GGPlot::new(df)
340 .aes(Aes::new().x("x").y("y").fill("fill"))
341 .geom_tile()
342 .scale_fill_viridis_c()
343 .title("Heatmap")
344 .theme_minimal()
345 .save_with_size(&out("heatmap"), W, H)?;
346 Ok(())
347}
348
349/// Jittered categorical scatter (`geom_jitter`).
350fn jitter() -> Result<(), Box<dyn std::error::Error>> {
351 let n = 300;
352 let group: Vec<&str> = (0..n).map(|i| ["Control", "Low", "High"][i % 3]).collect();
353 let value: Vec<f64> = (0..n)
354 .map(|i| {
355 let base = (i % 3) as f64 * 1.5;
356 base + ((i * 5701 % 1000) as f64 / 1000.0 - 0.5) * 2.0
357 })
358 .collect();
359 let df = df! { "group" => group, "value" => value }?;
360 GGPlot::new(df)
361 .aes(Aes::new().x("group").y("value").color("group"))
362 .geom_jitter()
363 .scale_color_brewer(PaletteName::Dark2)
364 .title("Jittered Points")
365 .theme_minimal()
366 .save_with_size(&out("jitter"), W, H)?;
367 Ok(())
368}
369
370/// A confidence band (`geom_ribbon`) under a line.
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}
388
389/// Stacked areas by group.
390fn area_stack() -> Result<(), Box<dyn std::error::Error>> {
391 let n = 40;
392 let mut x = Vec::new();
393 let mut y = Vec::new();
394 let mut g = Vec::new();
395 for grp in ["North", "South", "East"] {
396 for i in 0..n {
397 x.push(i as f64);
398 let base = match grp {
399 "North" => 2.0,
400 "South" => 3.0,
401 _ => 1.5,
402 };
403 y.push(base + (i as f64 * 0.2).sin().abs() * base);
404 g.push(grp);
405 }
406 }
407 let df = df! { "x" => x, "y" => y, "g" => g }?;
408 GGPlot::new(df)
409 .aes(Aes::new().x("x").y("y").fill("g"))
410 .geom_area()
411 .scale_fill_brewer(PaletteName::Set2)
412 .title("Stacked Area")
413 .theme_minimal()
414 .save_with_size(&out("area"), W, H)?;
415 Ok(())
416}
417
418/// The same plot rendered under every built-in theme.
419fn themes() -> Result<(), Box<dyn std::error::Error>> {
420 let n = 90;
421 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
422 let y: Vec<f64> = (0..n)
423 .map(|i| (i as f64 * 0.1).sin() + (i % 3) as f64 * 0.5)
424 .collect();
425 let g: Vec<&str> = (0..n).map(|i| ["A", "B", "C"][i % 3]).collect();
426 let df = df! { "x" => x, "y" => y, "g" => g }?;
427
428 type ThemeFn = fn() -> Theme;
429 let variants: [(&str, ThemeFn); 8] = [
430 ("gray", theme_gray),
431 ("bw", theme_bw),
432 ("minimal", theme_minimal),
433 ("classic", theme_classic),
434 ("light", theme_light),
435 ("dark", theme_dark),
436 ("linedraw", theme_linedraw),
437 ("void", theme_void),
438 ];
439 for (name, make) in variants {
440 GGPlot::new(df.clone())
441 .aes(Aes::new().x("x").y("y").color("g"))
442 .geom_point()
443 .theme(make())
444 .scale_color_brewer(PaletteName::Dark2)
445 .title(&format!("theme_{name}"))
446 .save_with_size(&out(&format!("theme_{name}")), TW, TH)?;
447 }
448 Ok(())
449}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Sales data with a notable spike
6 let month: Vec<f64> = (1..=12).map(|i| i as f64).collect();
7 let sales = vec![
8 120.0, 135.0, 150.0, 180.0, 210.0, 310.0, 280.0, 250.0, 190.0, 170.0, 155.0, 140.0,
9 ];
10
11 let df = df! {
12 "month" => month,
13 "sales" => sales,
14 }?;
15
16 GGPlot::new(df)
17 .aes(Aes::new().x("month").y("sales"))
18 .geom_line()
19 .geom_point()
20 // Highlight the peak region
21 .annotate_rect(4.5, 7.5, 100.0, 320.0)
22 // Label the peak
23 .annotate_text("Summer Peak", 6.0, 330.0)
24 // Draw an arrow-like segment pointing to the max
25 .annotate_segment(7.5, 330.0, 6.2, 312.0)
26 .title("Monthly Sales with Annotations")
27 .xlab("Month")
28 .ylab("Sales ($)")
29 .save("annotations.svg")?;
30
31 println!("Saved annotations.svg");
32 Ok(())
33}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate two overlapping distributions using deterministic pseudo-random values
6 let value: Vec<f64> = (0..200_u64)
7 .map(|i| {
8 let r = ((i.wrapping_mul(1103515245).wrapping_add(12345)) % (1 << 16)) as f64
9 / (1u64 << 16) as f64;
10 if i < 100 {
11 3.0 + r * 4.0
12 } else {
13 5.0 + r * 4.0
14 }
15 })
16 .collect();
17 let group: Vec<&str> = (0..200)
18 .map(|i| if i < 100 { "Group A" } else { "Group B" })
19 .collect();
20
21 let df = df! {
22 "value" => value,
23 "group" => group,
24 }?;
25
26 GGPlot::new(df)
27 .aes(Aes::new().x("value").color("group"))
28 .geom_density()
29 .title("Density Plot by Group")
30 .xlab("Value")
31 .ylab("Density")
32 .save("density.svg")?;
33
34 println!("Saved density.svg");
35 Ok(())
36}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let sepal_length: Vec<f64> = (0..50).map(|i| 4.5 + i as f64 * 0.05).collect();
6 let sepal_width: Vec<f64> = (0..50)
7 .map(|i| 2.0 + (i as f64 * 0.3).sin() + i as f64 * 0.02)
8 .collect();
9 let species: Vec<&str> = (0..50)
10 .map(|i| match i % 3 {
11 0 => "setosa",
12 1 => "versicolor",
13 _ => "virginica",
14 })
15 .collect();
16
17 let df = df! {
18 "sepal_length" => sepal_length,
19 "sepal_width" => sepal_width,
20 "species" => species,
21 }?;
22
23 GGPlot::new(df)
24 .aes(
25 Aes::new()
26 .x("sepal_length")
27 .y("sepal_width")
28 .color("species"),
29 )
30 .geom_point()
31 .title("Iris Scatter Plot")
32 .xlab("Sepal Length")
33 .ylab("Sepal Width")
34 .save("scatter.svg")?;
35
36 println!("Saved scatter.svg");
37 Ok(())
38}Sourcepub fn after_scale_fill_from_color(self, lightness: f64) -> Self
pub fn after_scale_fill_from_color(self, lightness: f64) -> Self
Set fill to the mapped color with adjusted lightness (R’s
aes(fill = after_scale(...))). lightness in -1.0..=1.0: positive
lightens toward white, negative darkens toward black.
Sourcepub fn after_scale_color_from_fill(self, lightness: f64) -> Self
pub fn after_scale_color_from_fill(self, lightness: f64) -> Self
Set color to the mapped fill with adjusted lightness — useful for a
darker border around a filled shape (color = after_scale(darken(fill))).
Sourcepub fn stage(self, aesthetic: Aesthetic, start: &str, after_stat: &str) -> Self
pub fn stage(self, aesthetic: Aesthetic, start: &str, after_stat: &str) -> Self
stage(start, after_stat): map aesthetic from start before the stat
and re-map it from after_stat afterwards (R’s stage()).
Sourcepub fn x(self, col: &str) -> Self
pub fn x(self, col: &str) -> Self
Examples found in repository?
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let df = df! {
6 "fruit" => ["Apple", "Apple", "Apple", "Banana", "Banana",
7 "Cherry", "Cherry", "Cherry", "Cherry", "Date"],
8 }?;
9
10 GGPlot::new(df)
11 .aes(Aes::new().x("fruit"))
12 .geom_bar()
13 .title("Fruit Counts")
14 .xlab("Fruit")
15 .ylab("Count")
16 .save("bar_chart.svg")?;
17
18 println!("Saved bar_chart.svg");
19 Ok(())
20}More examples
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let df = df! {
6 "language" => ["Rust", "Python", "JavaScript", "Go", "TypeScript", "Java", "C++"],
7 "satisfaction" => [92.0, 88.0, 85.0, 78.0, 82.0, 70.0, 75.0],
8 }?;
9
10 // Horizontal bar chart using coord_flip
11 GGPlot::new(df)
12 .aes(Aes::new().x("language").y("satisfaction"))
13 .geom_col()
14 .coord_flip()
15 .title("Developer Satisfaction by Language")
16 .xlab("Language")
17 .ylab("Satisfaction Score")
18 .save("coord_flip.svg")?;
19
20 println!("Saved coord_flip.svg");
21 Ok(())
22}45fn scatter() -> Result<(), Box<dyn std::error::Error>> {
46 let n = 150;
47 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
48 let y: Vec<f64> = (0..n)
49 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
50 .collect();
51 let species: Vec<&str> = (0..n)
52 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
53 .collect();
54
55 let df = df! { "x" => x, "y" => y, "species" => species }?;
56 GGPlot::new(df)
57 .aes(Aes::new().x("x").y("y").color("species"))
58 .geom_point()
59 .scale_color_brewer(PaletteName::Set1)
60 .title("Grouped Scatter")
61 .xlab("Sepal Length")
62 .ylab("Sepal Width")
63 .theme_minimal()
64 .save_with_size(&out("scatter"), W, H)?;
65 Ok(())
66}
67
68/// Points overlaid with a LOESS trend line and confidence band.
69fn smooth() -> Result<(), Box<dyn std::error::Error>> {
70 let n = 120;
71 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
72 let y: Vec<f64> = (0..n)
73 .map(|i| {
74 let t = i as f64 * 0.1;
75 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
76 })
77 .collect();
78
79 let df = df! { "x" => x, "y" => y }?;
80 GGPlot::new(df)
81 .aes(Aes::new().x("x").y("y"))
82 .geom_point()
83 .geom_smooth_with(GeomSmooth {
84 method: SmoothMethod::Loess { span: 0.5 },
85 ..Default::default()
86 })
87 .title("LOESS Smoothing")
88 .xlab("x")
89 .ylab("y")
90 .theme_bw()
91 .save_with_size(&out("smooth"), W, H)?;
92 Ok(())
93}
94
95/// Histogram of an approximately-normal sample.
96fn histogram() -> Result<(), Box<dyn std::error::Error>> {
97 let values: Vec<f64> = (0..1500)
98 .map(|i: i32| {
99 let r: f64 = (0..6)
100 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
101 .sum();
102 (r - 3.0) * 2.0
103 })
104 .collect();
105
106 let df = df! { "measurement" => values }?;
107 GGPlot::new(df)
108 .aes(Aes::new().x("measurement"))
109 .geom_histogram_with(GeomHistogram {
110 bins: 30,
111 ..Default::default()
112 })
113 .title("Histogram")
114 .xlab("Value")
115 .ylab("Count")
116 .theme_minimal()
117 .save_with_size(&out("histogram"), W, H)?;
118 Ok(())
119}
120
121/// Bar chart of category counts with a fill palette.
122fn bar() -> Result<(), Box<dyn std::error::Error>> {
123 let mut fruit: Vec<&str> = Vec::new();
124 for (f, c) in [
125 ("Apple", 8),
126 ("Banana", 5),
127 ("Cherry", 11),
128 ("Date", 3),
129 ("Elder", 7),
130 ] {
131 for _ in 0..c {
132 fruit.push(f);
133 }
134 }
135 let df = df! { "fruit" => fruit }?;
136 GGPlot::new(df)
137 .aes(Aes::new().x("fruit").fill("fruit"))
138 .geom_bar()
139 .scale_fill_brewer(PaletteName::Set2)
140 .title("Bar Chart")
141 .xlab("Fruit")
142 .ylab("Count")
143 .theme_minimal()
144 .save_with_size(&out("bar"), W, H)?;
145 Ok(())
146}
147
148/// Grouped boxplots.
149fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
150 let n = 240;
151 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
152 let value: Vec<f64> = (0..n)
153 .map(|i| {
154 let base = (i % 4) as f64 * 1.5;
155 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
156 })
157 .collect();
158
159 let df = df! { "group" => group, "value" => value }?;
160 GGPlot::new(df)
161 .aes(Aes::new().x("group").y("value"))
162 .geom_boxplot_with(GeomBoxplot {
163 fill: (70, 130, 180),
164 ..Default::default()
165 })
166 .title("Boxplot")
167 .xlab("Group")
168 .ylab("Value")
169 .theme_bw()
170 .save_with_size(&out("boxplot"), W, H)?;
171 Ok(())
172}
173
174/// Violin plots of grouped distributions.
175fn violin() -> Result<(), Box<dyn std::error::Error>> {
176 let n = 360;
177 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
178 let value: Vec<f64> = (0..n)
179 .map(|i| {
180 let g = (i % 3) as f64;
181 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
182 })
183 .collect();
184
185 let df = df! { "group" => group, "value" => value }?;
186 GGPlot::new(df)
187 .aes(Aes::new().x("group").y("value").fill("group"))
188 .geom_violin()
189 .scale_fill_brewer(PaletteName::Accent)
190 .title("Violin")
191 .xlab("Group")
192 .ylab("Value")
193 .theme_minimal()
194 .save_with_size(&out("violin"), W, H)?;
195 Ok(())
196}
197
198/// Spiral scatter coloured by a continuous variable (viridis).
199fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
200 let n = 400;
201 let x: Vec<f64> = (0..n)
202 .map(|i| {
203 let t = i as f64 * 0.05;
204 t.cos() * (1.0 + t * 0.12)
205 })
206 .collect();
207 let y: Vec<f64> = (0..n)
208 .map(|i| {
209 let t = i as f64 * 0.05;
210 t.sin() * (1.0 + t * 0.12)
211 })
212 .collect();
213 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
214
215 let df = df! { "x" => x, "y" => y, "z" => z }?;
216 GGPlot::new(df)
217 .aes(Aes::new().x("x").y("y").color("z"))
218 .geom_point()
219 .scale_color_viridis_c()
220 .title("Continuous Color (viridis)")
221 .xlab("x")
222 .ylab("y")
223 .theme_minimal()
224 .save_with_size(&out("continuous_color"), W, H)?;
225 Ok(())
226}
227
228/// Faceted scatter, one panel per group.
229fn facet() -> Result<(), Box<dyn std::error::Error>> {
230 let n = 180;
231 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
232 let y: Vec<f64> = (0..n)
233 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
234 .collect();
235 let species: Vec<&str> = (0..n)
236 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
237 .collect();
238
239 let df = df! { "x" => x, "y" => y, "species" => species }?;
240 GGPlot::new(df)
241 .aes(Aes::new().x("x").y("y").color("species"))
242 .geom_point()
243 .facet_wrap("species", Some(3))
244 .scale_color_brewer(PaletteName::Set1)
245 .title("Facet Wrap")
246 .xlab("x")
247 .ylab("y")
248 .theme_bw()
249 .save_with_size(&out("facet"), W, H)?;
250 Ok(())
251}
252
253/// Overlapping density curves by group.
254fn density() -> Result<(), Box<dyn std::error::Error>> {
255 let n = 600;
256 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
257 let value: Vec<f64> = (0..n)
258 .map(|i| {
259 let shift = (i % 2) as f64 * 2.5;
260 let t = i as f64 * 0.05;
261 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
262 })
263 .collect();
264
265 let df = df! { "value" => value, "group" => group }?;
266 GGPlot::new(df)
267 .aes(Aes::new().x("value").fill("group").color("group"))
268 .geom_density()
269 .scale_fill_brewer(PaletteName::Set1)
270 .scale_color_brewer(PaletteName::Set1)
271 .title("Density by Group")
272 .xlab("Value")
273 .ylab("Density")
274 .theme_minimal()
275 .save_with_size(&out("density"), W, H)?;
276 Ok(())
277}
278
279/// Filled contour bands from a gridded surface.
280fn contour_filled() -> Result<(), Box<dyn std::error::Error>> {
281 let (mut x, mut y, mut z) = (Vec::new(), Vec::new(), Vec::new());
282 for i in 0..40 {
283 for j in 0..40 {
284 let xv = i as f64 * 0.25 - 5.0;
285 let yv = j as f64 * 0.25 - 5.0;
286 x.push(xv);
287 y.push(yv);
288 z.push((xv * 0.6).sin() * (yv * 0.6).cos() + (-(xv * xv + yv * yv) / 30.0).exp());
289 }
290 }
291 let df = df! { "x" => x, "y" => y, "z" => z }?;
292 GGPlot::new(df)
293 .aes(Aes::new().x("x").y("y"))
294 .geom_contour_filled()
295 .scale_fill_viridis_c()
296 .title("Filled Contours")
297 .theme_minimal()
298 .save_with_size(&out("contour_filled"), W, H)?;
299 Ok(())
300}
301
302/// Hexagonal binning of a 2-D point cloud.
303fn hexbin() -> Result<(), Box<dyn std::error::Error>> {
304 let n = 4000;
305 let x: Vec<f64> = (0..n)
306 .map(|i| {
307 let t = i as f64;
308 (t * 0.017).sin() * 2.0 + ((i * 7919 % 1000) as f64 / 1000.0 - 0.5) * 3.0
309 })
310 .collect();
311 let y: Vec<f64> = (0..n)
312 .map(|i| {
313 let t = i as f64;
314 (t * 0.017).cos() * 2.0 + ((i * 6323 % 1000) as f64 / 1000.0 - 0.5) * 3.0
315 })
316 .collect();
317 let df = df! { "x" => x, "y" => y }?;
318 GGPlot::new(df)
319 .aes(Aes::new().x("x").y("y"))
320 .geom_hex()
321 .scale_fill_viridis_c()
322 .title("Hex Binning")
323 .theme_minimal()
324 .save_with_size(&out("hexbin"), W, H)?;
325 Ok(())
326}
327
328/// Heatmap of a gridded value with `geom_tile`.
329fn heatmap() -> Result<(), Box<dyn std::error::Error>> {
330 let (mut x, mut y, mut fill) = (Vec::new(), Vec::new(), Vec::new());
331 for i in 0..14 {
332 for j in 0..14 {
333 x.push(i as f64);
334 y.push(j as f64);
335 fill.push((i as f64 * 0.5).sin() * (j as f64 * 0.5).cos());
336 }
337 }
338 let df = df! { "x" => x, "y" => y, "fill" => fill }?;
339 GGPlot::new(df)
340 .aes(Aes::new().x("x").y("y").fill("fill"))
341 .geom_tile()
342 .scale_fill_viridis_c()
343 .title("Heatmap")
344 .theme_minimal()
345 .save_with_size(&out("heatmap"), W, H)?;
346 Ok(())
347}
348
349/// Jittered categorical scatter (`geom_jitter`).
350fn jitter() -> Result<(), Box<dyn std::error::Error>> {
351 let n = 300;
352 let group: Vec<&str> = (0..n).map(|i| ["Control", "Low", "High"][i % 3]).collect();
353 let value: Vec<f64> = (0..n)
354 .map(|i| {
355 let base = (i % 3) as f64 * 1.5;
356 base + ((i * 5701 % 1000) as f64 / 1000.0 - 0.5) * 2.0
357 })
358 .collect();
359 let df = df! { "group" => group, "value" => value }?;
360 GGPlot::new(df)
361 .aes(Aes::new().x("group").y("value").color("group"))
362 .geom_jitter()
363 .scale_color_brewer(PaletteName::Dark2)
364 .title("Jittered Points")
365 .theme_minimal()
366 .save_with_size(&out("jitter"), W, H)?;
367 Ok(())
368}
369
370/// A confidence band (`geom_ribbon`) under a line.
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}
388
389/// Stacked areas by group.
390fn area_stack() -> Result<(), Box<dyn std::error::Error>> {
391 let n = 40;
392 let mut x = Vec::new();
393 let mut y = Vec::new();
394 let mut g = Vec::new();
395 for grp in ["North", "South", "East"] {
396 for i in 0..n {
397 x.push(i as f64);
398 let base = match grp {
399 "North" => 2.0,
400 "South" => 3.0,
401 _ => 1.5,
402 };
403 y.push(base + (i as f64 * 0.2).sin().abs() * base);
404 g.push(grp);
405 }
406 }
407 let df = df! { "x" => x, "y" => y, "g" => g }?;
408 GGPlot::new(df)
409 .aes(Aes::new().x("x").y("y").fill("g"))
410 .geom_area()
411 .scale_fill_brewer(PaletteName::Set2)
412 .title("Stacked Area")
413 .theme_minimal()
414 .save_with_size(&out("area"), W, H)?;
415 Ok(())
416}
417
418/// The same plot rendered under every built-in theme.
419fn themes() -> Result<(), Box<dyn std::error::Error>> {
420 let n = 90;
421 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
422 let y: Vec<f64> = (0..n)
423 .map(|i| (i as f64 * 0.1).sin() + (i % 3) as f64 * 0.5)
424 .collect();
425 let g: Vec<&str> = (0..n).map(|i| ["A", "B", "C"][i % 3]).collect();
426 let df = df! { "x" => x, "y" => y, "g" => g }?;
427
428 type ThemeFn = fn() -> Theme;
429 let variants: [(&str, ThemeFn); 8] = [
430 ("gray", theme_gray),
431 ("bw", theme_bw),
432 ("minimal", theme_minimal),
433 ("classic", theme_classic),
434 ("light", theme_light),
435 ("dark", theme_dark),
436 ("linedraw", theme_linedraw),
437 ("void", theme_void),
438 ];
439 for (name, make) in variants {
440 GGPlot::new(df.clone())
441 .aes(Aes::new().x("x").y("y").color("g"))
442 .geom_point()
443 .theme(make())
444 .scale_color_brewer(PaletteName::Dark2)
445 .title(&format!("theme_{name}"))
446 .save_with_size(&out(&format!("theme_{name}")), TW, TH)?;
447 }
448 Ok(())
449}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Sales data with a notable spike
6 let month: Vec<f64> = (1..=12).map(|i| i as f64).collect();
7 let sales = vec![
8 120.0, 135.0, 150.0, 180.0, 210.0, 310.0, 280.0, 250.0, 190.0, 170.0, 155.0, 140.0,
9 ];
10
11 let df = df! {
12 "month" => month,
13 "sales" => sales,
14 }?;
15
16 GGPlot::new(df)
17 .aes(Aes::new().x("month").y("sales"))
18 .geom_line()
19 .geom_point()
20 // Highlight the peak region
21 .annotate_rect(4.5, 7.5, 100.0, 320.0)
22 // Label the peak
23 .annotate_text("Summer Peak", 6.0, 330.0)
24 // Draw an arrow-like segment pointing to the max
25 .annotate_segment(7.5, 330.0, 6.2, 312.0)
26 .title("Monthly Sales with Annotations")
27 .xlab("Month")
28 .ylab("Sales ($)")
29 .save("annotations.svg")?;
30
31 println!("Saved annotations.svg");
32 Ok(())
33}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate two overlapping distributions using deterministic pseudo-random values
6 let value: Vec<f64> = (0..200_u64)
7 .map(|i| {
8 let r = ((i.wrapping_mul(1103515245).wrapping_add(12345)) % (1 << 16)) as f64
9 / (1u64 << 16) as f64;
10 if i < 100 {
11 3.0 + r * 4.0
12 } else {
13 5.0 + r * 4.0
14 }
15 })
16 .collect();
17 let group: Vec<&str> = (0..200)
18 .map(|i| if i < 100 { "Group A" } else { "Group B" })
19 .collect();
20
21 let df = df! {
22 "value" => value,
23 "group" => group,
24 }?;
25
26 GGPlot::new(df)
27 .aes(Aes::new().x("value").color("group"))
28 .geom_density()
29 .title("Density Plot by Group")
30 .xlab("Value")
31 .ylab("Density")
32 .save("density.svg")?;
33
34 println!("Saved density.svg");
35 Ok(())
36}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let sepal_length: Vec<f64> = (0..50).map(|i| 4.5 + i as f64 * 0.05).collect();
6 let sepal_width: Vec<f64> = (0..50)
7 .map(|i| 2.0 + (i as f64 * 0.3).sin() + i as f64 * 0.02)
8 .collect();
9 let species: Vec<&str> = (0..50)
10 .map(|i| match i % 3 {
11 0 => "setosa",
12 1 => "versicolor",
13 _ => "virginica",
14 })
15 .collect();
16
17 let df = df! {
18 "sepal_length" => sepal_length,
19 "sepal_width" => sepal_width,
20 "species" => species,
21 }?;
22
23 GGPlot::new(df)
24 .aes(
25 Aes::new()
26 .x("sepal_length")
27 .y("sepal_width")
28 .color("species"),
29 )
30 .geom_point()
31 .title("Iris Scatter Plot")
32 .xlab("Sepal Length")
33 .ylab("Sepal Width")
34 .save("scatter.svg")?;
35
36 println!("Saved scatter.svg");
37 Ok(())
38}Sourcepub fn y(self, col: &str) -> Self
pub fn y(self, col: &str) -> Self
Examples found in repository?
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let df = df! {
6 "language" => ["Rust", "Python", "JavaScript", "Go", "TypeScript", "Java", "C++"],
7 "satisfaction" => [92.0, 88.0, 85.0, 78.0, 82.0, 70.0, 75.0],
8 }?;
9
10 // Horizontal bar chart using coord_flip
11 GGPlot::new(df)
12 .aes(Aes::new().x("language").y("satisfaction"))
13 .geom_col()
14 .coord_flip()
15 .title("Developer Satisfaction by Language")
16 .xlab("Language")
17 .ylab("Satisfaction Score")
18 .save("coord_flip.svg")?;
19
20 println!("Saved coord_flip.svg");
21 Ok(())
22}More examples
45fn scatter() -> Result<(), Box<dyn std::error::Error>> {
46 let n = 150;
47 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
48 let y: Vec<f64> = (0..n)
49 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
50 .collect();
51 let species: Vec<&str> = (0..n)
52 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
53 .collect();
54
55 let df = df! { "x" => x, "y" => y, "species" => species }?;
56 GGPlot::new(df)
57 .aes(Aes::new().x("x").y("y").color("species"))
58 .geom_point()
59 .scale_color_brewer(PaletteName::Set1)
60 .title("Grouped Scatter")
61 .xlab("Sepal Length")
62 .ylab("Sepal Width")
63 .theme_minimal()
64 .save_with_size(&out("scatter"), W, H)?;
65 Ok(())
66}
67
68/// Points overlaid with a LOESS trend line and confidence band.
69fn smooth() -> Result<(), Box<dyn std::error::Error>> {
70 let n = 120;
71 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
72 let y: Vec<f64> = (0..n)
73 .map(|i| {
74 let t = i as f64 * 0.1;
75 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
76 })
77 .collect();
78
79 let df = df! { "x" => x, "y" => y }?;
80 GGPlot::new(df)
81 .aes(Aes::new().x("x").y("y"))
82 .geom_point()
83 .geom_smooth_with(GeomSmooth {
84 method: SmoothMethod::Loess { span: 0.5 },
85 ..Default::default()
86 })
87 .title("LOESS Smoothing")
88 .xlab("x")
89 .ylab("y")
90 .theme_bw()
91 .save_with_size(&out("smooth"), W, H)?;
92 Ok(())
93}
94
95/// Histogram of an approximately-normal sample.
96fn histogram() -> Result<(), Box<dyn std::error::Error>> {
97 let values: Vec<f64> = (0..1500)
98 .map(|i: i32| {
99 let r: f64 = (0..6)
100 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
101 .sum();
102 (r - 3.0) * 2.0
103 })
104 .collect();
105
106 let df = df! { "measurement" => values }?;
107 GGPlot::new(df)
108 .aes(Aes::new().x("measurement"))
109 .geom_histogram_with(GeomHistogram {
110 bins: 30,
111 ..Default::default()
112 })
113 .title("Histogram")
114 .xlab("Value")
115 .ylab("Count")
116 .theme_minimal()
117 .save_with_size(&out("histogram"), W, H)?;
118 Ok(())
119}
120
121/// Bar chart of category counts with a fill palette.
122fn bar() -> Result<(), Box<dyn std::error::Error>> {
123 let mut fruit: Vec<&str> = Vec::new();
124 for (f, c) in [
125 ("Apple", 8),
126 ("Banana", 5),
127 ("Cherry", 11),
128 ("Date", 3),
129 ("Elder", 7),
130 ] {
131 for _ in 0..c {
132 fruit.push(f);
133 }
134 }
135 let df = df! { "fruit" => fruit }?;
136 GGPlot::new(df)
137 .aes(Aes::new().x("fruit").fill("fruit"))
138 .geom_bar()
139 .scale_fill_brewer(PaletteName::Set2)
140 .title("Bar Chart")
141 .xlab("Fruit")
142 .ylab("Count")
143 .theme_minimal()
144 .save_with_size(&out("bar"), W, H)?;
145 Ok(())
146}
147
148/// Grouped boxplots.
149fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
150 let n = 240;
151 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
152 let value: Vec<f64> = (0..n)
153 .map(|i| {
154 let base = (i % 4) as f64 * 1.5;
155 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
156 })
157 .collect();
158
159 let df = df! { "group" => group, "value" => value }?;
160 GGPlot::new(df)
161 .aes(Aes::new().x("group").y("value"))
162 .geom_boxplot_with(GeomBoxplot {
163 fill: (70, 130, 180),
164 ..Default::default()
165 })
166 .title("Boxplot")
167 .xlab("Group")
168 .ylab("Value")
169 .theme_bw()
170 .save_with_size(&out("boxplot"), W, H)?;
171 Ok(())
172}
173
174/// Violin plots of grouped distributions.
175fn violin() -> Result<(), Box<dyn std::error::Error>> {
176 let n = 360;
177 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
178 let value: Vec<f64> = (0..n)
179 .map(|i| {
180 let g = (i % 3) as f64;
181 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
182 })
183 .collect();
184
185 let df = df! { "group" => group, "value" => value }?;
186 GGPlot::new(df)
187 .aes(Aes::new().x("group").y("value").fill("group"))
188 .geom_violin()
189 .scale_fill_brewer(PaletteName::Accent)
190 .title("Violin")
191 .xlab("Group")
192 .ylab("Value")
193 .theme_minimal()
194 .save_with_size(&out("violin"), W, H)?;
195 Ok(())
196}
197
198/// Spiral scatter coloured by a continuous variable (viridis).
199fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
200 let n = 400;
201 let x: Vec<f64> = (0..n)
202 .map(|i| {
203 let t = i as f64 * 0.05;
204 t.cos() * (1.0 + t * 0.12)
205 })
206 .collect();
207 let y: Vec<f64> = (0..n)
208 .map(|i| {
209 let t = i as f64 * 0.05;
210 t.sin() * (1.0 + t * 0.12)
211 })
212 .collect();
213 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
214
215 let df = df! { "x" => x, "y" => y, "z" => z }?;
216 GGPlot::new(df)
217 .aes(Aes::new().x("x").y("y").color("z"))
218 .geom_point()
219 .scale_color_viridis_c()
220 .title("Continuous Color (viridis)")
221 .xlab("x")
222 .ylab("y")
223 .theme_minimal()
224 .save_with_size(&out("continuous_color"), W, H)?;
225 Ok(())
226}
227
228/// Faceted scatter, one panel per group.
229fn facet() -> Result<(), Box<dyn std::error::Error>> {
230 let n = 180;
231 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
232 let y: Vec<f64> = (0..n)
233 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
234 .collect();
235 let species: Vec<&str> = (0..n)
236 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
237 .collect();
238
239 let df = df! { "x" => x, "y" => y, "species" => species }?;
240 GGPlot::new(df)
241 .aes(Aes::new().x("x").y("y").color("species"))
242 .geom_point()
243 .facet_wrap("species", Some(3))
244 .scale_color_brewer(PaletteName::Set1)
245 .title("Facet Wrap")
246 .xlab("x")
247 .ylab("y")
248 .theme_bw()
249 .save_with_size(&out("facet"), W, H)?;
250 Ok(())
251}
252
253/// Overlapping density curves by group.
254fn density() -> Result<(), Box<dyn std::error::Error>> {
255 let n = 600;
256 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
257 let value: Vec<f64> = (0..n)
258 .map(|i| {
259 let shift = (i % 2) as f64 * 2.5;
260 let t = i as f64 * 0.05;
261 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
262 })
263 .collect();
264
265 let df = df! { "value" => value, "group" => group }?;
266 GGPlot::new(df)
267 .aes(Aes::new().x("value").fill("group").color("group"))
268 .geom_density()
269 .scale_fill_brewer(PaletteName::Set1)
270 .scale_color_brewer(PaletteName::Set1)
271 .title("Density by Group")
272 .xlab("Value")
273 .ylab("Density")
274 .theme_minimal()
275 .save_with_size(&out("density"), W, H)?;
276 Ok(())
277}
278
279/// Filled contour bands from a gridded surface.
280fn contour_filled() -> Result<(), Box<dyn std::error::Error>> {
281 let (mut x, mut y, mut z) = (Vec::new(), Vec::new(), Vec::new());
282 for i in 0..40 {
283 for j in 0..40 {
284 let xv = i as f64 * 0.25 - 5.0;
285 let yv = j as f64 * 0.25 - 5.0;
286 x.push(xv);
287 y.push(yv);
288 z.push((xv * 0.6).sin() * (yv * 0.6).cos() + (-(xv * xv + yv * yv) / 30.0).exp());
289 }
290 }
291 let df = df! { "x" => x, "y" => y, "z" => z }?;
292 GGPlot::new(df)
293 .aes(Aes::new().x("x").y("y"))
294 .geom_contour_filled()
295 .scale_fill_viridis_c()
296 .title("Filled Contours")
297 .theme_minimal()
298 .save_with_size(&out("contour_filled"), W, H)?;
299 Ok(())
300}
301
302/// Hexagonal binning of a 2-D point cloud.
303fn hexbin() -> Result<(), Box<dyn std::error::Error>> {
304 let n = 4000;
305 let x: Vec<f64> = (0..n)
306 .map(|i| {
307 let t = i as f64;
308 (t * 0.017).sin() * 2.0 + ((i * 7919 % 1000) as f64 / 1000.0 - 0.5) * 3.0
309 })
310 .collect();
311 let y: Vec<f64> = (0..n)
312 .map(|i| {
313 let t = i as f64;
314 (t * 0.017).cos() * 2.0 + ((i * 6323 % 1000) as f64 / 1000.0 - 0.5) * 3.0
315 })
316 .collect();
317 let df = df! { "x" => x, "y" => y }?;
318 GGPlot::new(df)
319 .aes(Aes::new().x("x").y("y"))
320 .geom_hex()
321 .scale_fill_viridis_c()
322 .title("Hex Binning")
323 .theme_minimal()
324 .save_with_size(&out("hexbin"), W, H)?;
325 Ok(())
326}
327
328/// Heatmap of a gridded value with `geom_tile`.
329fn heatmap() -> Result<(), Box<dyn std::error::Error>> {
330 let (mut x, mut y, mut fill) = (Vec::new(), Vec::new(), Vec::new());
331 for i in 0..14 {
332 for j in 0..14 {
333 x.push(i as f64);
334 y.push(j as f64);
335 fill.push((i as f64 * 0.5).sin() * (j as f64 * 0.5).cos());
336 }
337 }
338 let df = df! { "x" => x, "y" => y, "fill" => fill }?;
339 GGPlot::new(df)
340 .aes(Aes::new().x("x").y("y").fill("fill"))
341 .geom_tile()
342 .scale_fill_viridis_c()
343 .title("Heatmap")
344 .theme_minimal()
345 .save_with_size(&out("heatmap"), W, H)?;
346 Ok(())
347}
348
349/// Jittered categorical scatter (`geom_jitter`).
350fn jitter() -> Result<(), Box<dyn std::error::Error>> {
351 let n = 300;
352 let group: Vec<&str> = (0..n).map(|i| ["Control", "Low", "High"][i % 3]).collect();
353 let value: Vec<f64> = (0..n)
354 .map(|i| {
355 let base = (i % 3) as f64 * 1.5;
356 base + ((i * 5701 % 1000) as f64 / 1000.0 - 0.5) * 2.0
357 })
358 .collect();
359 let df = df! { "group" => group, "value" => value }?;
360 GGPlot::new(df)
361 .aes(Aes::new().x("group").y("value").color("group"))
362 .geom_jitter()
363 .scale_color_brewer(PaletteName::Dark2)
364 .title("Jittered Points")
365 .theme_minimal()
366 .save_with_size(&out("jitter"), W, H)?;
367 Ok(())
368}
369
370/// A confidence band (`geom_ribbon`) under a line.
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}
388
389/// Stacked areas by group.
390fn area_stack() -> Result<(), Box<dyn std::error::Error>> {
391 let n = 40;
392 let mut x = Vec::new();
393 let mut y = Vec::new();
394 let mut g = Vec::new();
395 for grp in ["North", "South", "East"] {
396 for i in 0..n {
397 x.push(i as f64);
398 let base = match grp {
399 "North" => 2.0,
400 "South" => 3.0,
401 _ => 1.5,
402 };
403 y.push(base + (i as f64 * 0.2).sin().abs() * base);
404 g.push(grp);
405 }
406 }
407 let df = df! { "x" => x, "y" => y, "g" => g }?;
408 GGPlot::new(df)
409 .aes(Aes::new().x("x").y("y").fill("g"))
410 .geom_area()
411 .scale_fill_brewer(PaletteName::Set2)
412 .title("Stacked Area")
413 .theme_minimal()
414 .save_with_size(&out("area"), W, H)?;
415 Ok(())
416}
417
418/// The same plot rendered under every built-in theme.
419fn themes() -> Result<(), Box<dyn std::error::Error>> {
420 let n = 90;
421 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
422 let y: Vec<f64> = (0..n)
423 .map(|i| (i as f64 * 0.1).sin() + (i % 3) as f64 * 0.5)
424 .collect();
425 let g: Vec<&str> = (0..n).map(|i| ["A", "B", "C"][i % 3]).collect();
426 let df = df! { "x" => x, "y" => y, "g" => g }?;
427
428 type ThemeFn = fn() -> Theme;
429 let variants: [(&str, ThemeFn); 8] = [
430 ("gray", theme_gray),
431 ("bw", theme_bw),
432 ("minimal", theme_minimal),
433 ("classic", theme_classic),
434 ("light", theme_light),
435 ("dark", theme_dark),
436 ("linedraw", theme_linedraw),
437 ("void", theme_void),
438 ];
439 for (name, make) in variants {
440 GGPlot::new(df.clone())
441 .aes(Aes::new().x("x").y("y").color("g"))
442 .geom_point()
443 .theme(make())
444 .scale_color_brewer(PaletteName::Dark2)
445 .title(&format!("theme_{name}"))
446 .save_with_size(&out(&format!("theme_{name}")), TW, TH)?;
447 }
448 Ok(())
449}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Sales data with a notable spike
6 let month: Vec<f64> = (1..=12).map(|i| i as f64).collect();
7 let sales = vec![
8 120.0, 135.0, 150.0, 180.0, 210.0, 310.0, 280.0, 250.0, 190.0, 170.0, 155.0, 140.0,
9 ];
10
11 let df = df! {
12 "month" => month,
13 "sales" => sales,
14 }?;
15
16 GGPlot::new(df)
17 .aes(Aes::new().x("month").y("sales"))
18 .geom_line()
19 .geom_point()
20 // Highlight the peak region
21 .annotate_rect(4.5, 7.5, 100.0, 320.0)
22 // Label the peak
23 .annotate_text("Summer Peak", 6.0, 330.0)
24 // Draw an arrow-like segment pointing to the max
25 .annotate_segment(7.5, 330.0, 6.2, 312.0)
26 .title("Monthly Sales with Annotations")
27 .xlab("Month")
28 .ylab("Sales ($)")
29 .save("annotations.svg")?;
30
31 println!("Saved annotations.svg");
32 Ok(())
33}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let sepal_length: Vec<f64> = (0..50).map(|i| 4.5 + i as f64 * 0.05).collect();
6 let sepal_width: Vec<f64> = (0..50)
7 .map(|i| 2.0 + (i as f64 * 0.3).sin() + i as f64 * 0.02)
8 .collect();
9 let species: Vec<&str> = (0..50)
10 .map(|i| match i % 3 {
11 0 => "setosa",
12 1 => "versicolor",
13 _ => "virginica",
14 })
15 .collect();
16
17 let df = df! {
18 "sepal_length" => sepal_length,
19 "sepal_width" => sepal_width,
20 "species" => species,
21 }?;
22
23 GGPlot::new(df)
24 .aes(
25 Aes::new()
26 .x("sepal_length")
27 .y("sepal_width")
28 .color("species"),
29 )
30 .geom_point()
31 .title("Iris Scatter Plot")
32 .xlab("Sepal Length")
33 .ylab("Sepal Width")
34 .save("scatter.svg")?;
35
36 println!("Saved scatter.svg");
37 Ok(())
38}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate noisy sine wave data
6 let x: Vec<f64> = (0..80).map(|i| (i as f64) * 0.1).collect();
7 let y: Vec<f64> = (0..80)
8 .map(|i| {
9 let xv = (i as f64) * 0.1;
10 let noise = ((i * 17 + 3) % 11) as f64 / 11.0 - 0.5; // deterministic pseudo-noise
11 (xv * 0.8).sin() * 2.0 + noise * 1.5
12 })
13 .collect();
14
15 let df = df! {
16 "x" => &x,
17 "y" => &y,
18 }?;
19
20 // Linear smooth (default)
21 GGPlot::new(df.clone())
22 .aes(Aes::new().x("x").y("y"))
23 .geom_point()
24 .geom_smooth()
25 .title("Linear Smooth (method = lm)")
26 .save("smooth_lm.svg")?;
27
28 println!("Saved smooth_lm.svg");
29
30 // LOESS smooth
31 GGPlot::new(df)
32 .aes(Aes::new().x("x").y("y"))
33 .geom_point()
34 .geom_smooth_with(GeomSmooth::default().loess(0.3))
35 .title("LOESS Smooth (span = 0.3)")
36 .save("smooth_loess.svg")?;
37
38 println!("Saved smooth_loess.svg");
39 Ok(())
40}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Exponential growth data (e.g., population, bacteria count)
6 let year: Vec<f64> = (0..30).map(|i| 1990.0 + i as f64).collect();
7 let count: Vec<f64> = (0..30)
8 .map(|i| {
9 let base = 100.0 * (1.15_f64).powi(i); // 15% growth per year
10 let noise = ((i * 37 + 7) % 13) as f64 / 13.0 * 0.2 + 0.9;
11 base * noise
12 })
13 .collect();
14
15 let df = df! {
16 "year" => &year,
17 "count" => &count,
18 }?;
19
20 // Linear scale — exponential curve
21 GGPlot::new(df.clone())
22 .aes(Aes::new().x("year").y("count"))
23 .geom_point()
24 .geom_line()
25 .title("Exponential Growth (Linear Scale)")
26 .xlab("Year")
27 .ylab("Count")
28 .save("log_scale_linear.svg")?;
29
30 println!("Saved log_scale_linear.svg");
31
32 // Log10 y-axis — should appear roughly linear
33 GGPlot::new(df)
34 .aes(Aes::new().x("year").y("count"))
35 .geom_point()
36 .geom_line()
37 .scale_y_log10()
38 .title("Exponential Growth (Log10 Y Scale)")
39 .xlab("Year")
40 .ylab("Count (log10)")
41 .save("log_scale_log10.svg")?;
42
43 println!("Saved log_scale_log10.svg");
44 Ok(())
45}Sourcepub fn color(self, col: &str) -> Self
pub fn color(self, col: &str) -> Self
Examples found in repository?
45fn scatter() -> Result<(), Box<dyn std::error::Error>> {
46 let n = 150;
47 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
48 let y: Vec<f64> = (0..n)
49 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
50 .collect();
51 let species: Vec<&str> = (0..n)
52 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
53 .collect();
54
55 let df = df! { "x" => x, "y" => y, "species" => species }?;
56 GGPlot::new(df)
57 .aes(Aes::new().x("x").y("y").color("species"))
58 .geom_point()
59 .scale_color_brewer(PaletteName::Set1)
60 .title("Grouped Scatter")
61 .xlab("Sepal Length")
62 .ylab("Sepal Width")
63 .theme_minimal()
64 .save_with_size(&out("scatter"), W, H)?;
65 Ok(())
66}
67
68/// Points overlaid with a LOESS trend line and confidence band.
69fn smooth() -> Result<(), Box<dyn std::error::Error>> {
70 let n = 120;
71 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
72 let y: Vec<f64> = (0..n)
73 .map(|i| {
74 let t = i as f64 * 0.1;
75 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
76 })
77 .collect();
78
79 let df = df! { "x" => x, "y" => y }?;
80 GGPlot::new(df)
81 .aes(Aes::new().x("x").y("y"))
82 .geom_point()
83 .geom_smooth_with(GeomSmooth {
84 method: SmoothMethod::Loess { span: 0.5 },
85 ..Default::default()
86 })
87 .title("LOESS Smoothing")
88 .xlab("x")
89 .ylab("y")
90 .theme_bw()
91 .save_with_size(&out("smooth"), W, H)?;
92 Ok(())
93}
94
95/// Histogram of an approximately-normal sample.
96fn histogram() -> Result<(), Box<dyn std::error::Error>> {
97 let values: Vec<f64> = (0..1500)
98 .map(|i: i32| {
99 let r: f64 = (0..6)
100 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
101 .sum();
102 (r - 3.0) * 2.0
103 })
104 .collect();
105
106 let df = df! { "measurement" => values }?;
107 GGPlot::new(df)
108 .aes(Aes::new().x("measurement"))
109 .geom_histogram_with(GeomHistogram {
110 bins: 30,
111 ..Default::default()
112 })
113 .title("Histogram")
114 .xlab("Value")
115 .ylab("Count")
116 .theme_minimal()
117 .save_with_size(&out("histogram"), W, H)?;
118 Ok(())
119}
120
121/// Bar chart of category counts with a fill palette.
122fn bar() -> Result<(), Box<dyn std::error::Error>> {
123 let mut fruit: Vec<&str> = Vec::new();
124 for (f, c) in [
125 ("Apple", 8),
126 ("Banana", 5),
127 ("Cherry", 11),
128 ("Date", 3),
129 ("Elder", 7),
130 ] {
131 for _ in 0..c {
132 fruit.push(f);
133 }
134 }
135 let df = df! { "fruit" => fruit }?;
136 GGPlot::new(df)
137 .aes(Aes::new().x("fruit").fill("fruit"))
138 .geom_bar()
139 .scale_fill_brewer(PaletteName::Set2)
140 .title("Bar Chart")
141 .xlab("Fruit")
142 .ylab("Count")
143 .theme_minimal()
144 .save_with_size(&out("bar"), W, H)?;
145 Ok(())
146}
147
148/// Grouped boxplots.
149fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
150 let n = 240;
151 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
152 let value: Vec<f64> = (0..n)
153 .map(|i| {
154 let base = (i % 4) as f64 * 1.5;
155 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
156 })
157 .collect();
158
159 let df = df! { "group" => group, "value" => value }?;
160 GGPlot::new(df)
161 .aes(Aes::new().x("group").y("value"))
162 .geom_boxplot_with(GeomBoxplot {
163 fill: (70, 130, 180),
164 ..Default::default()
165 })
166 .title("Boxplot")
167 .xlab("Group")
168 .ylab("Value")
169 .theme_bw()
170 .save_with_size(&out("boxplot"), W, H)?;
171 Ok(())
172}
173
174/// Violin plots of grouped distributions.
175fn violin() -> Result<(), Box<dyn std::error::Error>> {
176 let n = 360;
177 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
178 let value: Vec<f64> = (0..n)
179 .map(|i| {
180 let g = (i % 3) as f64;
181 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
182 })
183 .collect();
184
185 let df = df! { "group" => group, "value" => value }?;
186 GGPlot::new(df)
187 .aes(Aes::new().x("group").y("value").fill("group"))
188 .geom_violin()
189 .scale_fill_brewer(PaletteName::Accent)
190 .title("Violin")
191 .xlab("Group")
192 .ylab("Value")
193 .theme_minimal()
194 .save_with_size(&out("violin"), W, H)?;
195 Ok(())
196}
197
198/// Spiral scatter coloured by a continuous variable (viridis).
199fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
200 let n = 400;
201 let x: Vec<f64> = (0..n)
202 .map(|i| {
203 let t = i as f64 * 0.05;
204 t.cos() * (1.0 + t * 0.12)
205 })
206 .collect();
207 let y: Vec<f64> = (0..n)
208 .map(|i| {
209 let t = i as f64 * 0.05;
210 t.sin() * (1.0 + t * 0.12)
211 })
212 .collect();
213 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
214
215 let df = df! { "x" => x, "y" => y, "z" => z }?;
216 GGPlot::new(df)
217 .aes(Aes::new().x("x").y("y").color("z"))
218 .geom_point()
219 .scale_color_viridis_c()
220 .title("Continuous Color (viridis)")
221 .xlab("x")
222 .ylab("y")
223 .theme_minimal()
224 .save_with_size(&out("continuous_color"), W, H)?;
225 Ok(())
226}
227
228/// Faceted scatter, one panel per group.
229fn facet() -> Result<(), Box<dyn std::error::Error>> {
230 let n = 180;
231 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
232 let y: Vec<f64> = (0..n)
233 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
234 .collect();
235 let species: Vec<&str> = (0..n)
236 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
237 .collect();
238
239 let df = df! { "x" => x, "y" => y, "species" => species }?;
240 GGPlot::new(df)
241 .aes(Aes::new().x("x").y("y").color("species"))
242 .geom_point()
243 .facet_wrap("species", Some(3))
244 .scale_color_brewer(PaletteName::Set1)
245 .title("Facet Wrap")
246 .xlab("x")
247 .ylab("y")
248 .theme_bw()
249 .save_with_size(&out("facet"), W, H)?;
250 Ok(())
251}
252
253/// Overlapping density curves by group.
254fn density() -> Result<(), Box<dyn std::error::Error>> {
255 let n = 600;
256 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
257 let value: Vec<f64> = (0..n)
258 .map(|i| {
259 let shift = (i % 2) as f64 * 2.5;
260 let t = i as f64 * 0.05;
261 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
262 })
263 .collect();
264
265 let df = df! { "value" => value, "group" => group }?;
266 GGPlot::new(df)
267 .aes(Aes::new().x("value").fill("group").color("group"))
268 .geom_density()
269 .scale_fill_brewer(PaletteName::Set1)
270 .scale_color_brewer(PaletteName::Set1)
271 .title("Density by Group")
272 .xlab("Value")
273 .ylab("Density")
274 .theme_minimal()
275 .save_with_size(&out("density"), W, H)?;
276 Ok(())
277}
278
279/// Filled contour bands from a gridded surface.
280fn contour_filled() -> Result<(), Box<dyn std::error::Error>> {
281 let (mut x, mut y, mut z) = (Vec::new(), Vec::new(), Vec::new());
282 for i in 0..40 {
283 for j in 0..40 {
284 let xv = i as f64 * 0.25 - 5.0;
285 let yv = j as f64 * 0.25 - 5.0;
286 x.push(xv);
287 y.push(yv);
288 z.push((xv * 0.6).sin() * (yv * 0.6).cos() + (-(xv * xv + yv * yv) / 30.0).exp());
289 }
290 }
291 let df = df! { "x" => x, "y" => y, "z" => z }?;
292 GGPlot::new(df)
293 .aes(Aes::new().x("x").y("y"))
294 .geom_contour_filled()
295 .scale_fill_viridis_c()
296 .title("Filled Contours")
297 .theme_minimal()
298 .save_with_size(&out("contour_filled"), W, H)?;
299 Ok(())
300}
301
302/// Hexagonal binning of a 2-D point cloud.
303fn hexbin() -> Result<(), Box<dyn std::error::Error>> {
304 let n = 4000;
305 let x: Vec<f64> = (0..n)
306 .map(|i| {
307 let t = i as f64;
308 (t * 0.017).sin() * 2.0 + ((i * 7919 % 1000) as f64 / 1000.0 - 0.5) * 3.0
309 })
310 .collect();
311 let y: Vec<f64> = (0..n)
312 .map(|i| {
313 let t = i as f64;
314 (t * 0.017).cos() * 2.0 + ((i * 6323 % 1000) as f64 / 1000.0 - 0.5) * 3.0
315 })
316 .collect();
317 let df = df! { "x" => x, "y" => y }?;
318 GGPlot::new(df)
319 .aes(Aes::new().x("x").y("y"))
320 .geom_hex()
321 .scale_fill_viridis_c()
322 .title("Hex Binning")
323 .theme_minimal()
324 .save_with_size(&out("hexbin"), W, H)?;
325 Ok(())
326}
327
328/// Heatmap of a gridded value with `geom_tile`.
329fn heatmap() -> Result<(), Box<dyn std::error::Error>> {
330 let (mut x, mut y, mut fill) = (Vec::new(), Vec::new(), Vec::new());
331 for i in 0..14 {
332 for j in 0..14 {
333 x.push(i as f64);
334 y.push(j as f64);
335 fill.push((i as f64 * 0.5).sin() * (j as f64 * 0.5).cos());
336 }
337 }
338 let df = df! { "x" => x, "y" => y, "fill" => fill }?;
339 GGPlot::new(df)
340 .aes(Aes::new().x("x").y("y").fill("fill"))
341 .geom_tile()
342 .scale_fill_viridis_c()
343 .title("Heatmap")
344 .theme_minimal()
345 .save_with_size(&out("heatmap"), W, H)?;
346 Ok(())
347}
348
349/// Jittered categorical scatter (`geom_jitter`).
350fn jitter() -> Result<(), Box<dyn std::error::Error>> {
351 let n = 300;
352 let group: Vec<&str> = (0..n).map(|i| ["Control", "Low", "High"][i % 3]).collect();
353 let value: Vec<f64> = (0..n)
354 .map(|i| {
355 let base = (i % 3) as f64 * 1.5;
356 base + ((i * 5701 % 1000) as f64 / 1000.0 - 0.5) * 2.0
357 })
358 .collect();
359 let df = df! { "group" => group, "value" => value }?;
360 GGPlot::new(df)
361 .aes(Aes::new().x("group").y("value").color("group"))
362 .geom_jitter()
363 .scale_color_brewer(PaletteName::Dark2)
364 .title("Jittered Points")
365 .theme_minimal()
366 .save_with_size(&out("jitter"), W, H)?;
367 Ok(())
368}
369
370/// A confidence band (`geom_ribbon`) under a line.
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}
388
389/// Stacked areas by group.
390fn area_stack() -> Result<(), Box<dyn std::error::Error>> {
391 let n = 40;
392 let mut x = Vec::new();
393 let mut y = Vec::new();
394 let mut g = Vec::new();
395 for grp in ["North", "South", "East"] {
396 for i in 0..n {
397 x.push(i as f64);
398 let base = match grp {
399 "North" => 2.0,
400 "South" => 3.0,
401 _ => 1.5,
402 };
403 y.push(base + (i as f64 * 0.2).sin().abs() * base);
404 g.push(grp);
405 }
406 }
407 let df = df! { "x" => x, "y" => y, "g" => g }?;
408 GGPlot::new(df)
409 .aes(Aes::new().x("x").y("y").fill("g"))
410 .geom_area()
411 .scale_fill_brewer(PaletteName::Set2)
412 .title("Stacked Area")
413 .theme_minimal()
414 .save_with_size(&out("area"), W, H)?;
415 Ok(())
416}
417
418/// The same plot rendered under every built-in theme.
419fn themes() -> Result<(), Box<dyn std::error::Error>> {
420 let n = 90;
421 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
422 let y: Vec<f64> = (0..n)
423 .map(|i| (i as f64 * 0.1).sin() + (i % 3) as f64 * 0.5)
424 .collect();
425 let g: Vec<&str> = (0..n).map(|i| ["A", "B", "C"][i % 3]).collect();
426 let df = df! { "x" => x, "y" => y, "g" => g }?;
427
428 type ThemeFn = fn() -> Theme;
429 let variants: [(&str, ThemeFn); 8] = [
430 ("gray", theme_gray),
431 ("bw", theme_bw),
432 ("minimal", theme_minimal),
433 ("classic", theme_classic),
434 ("light", theme_light),
435 ("dark", theme_dark),
436 ("linedraw", theme_linedraw),
437 ("void", theme_void),
438 ];
439 for (name, make) in variants {
440 GGPlot::new(df.clone())
441 .aes(Aes::new().x("x").y("y").color("g"))
442 .geom_point()
443 .theme(make())
444 .scale_color_brewer(PaletteName::Dark2)
445 .title(&format!("theme_{name}"))
446 .save_with_size(&out(&format!("theme_{name}")), TW, TH)?;
447 }
448 Ok(())
449}More examples
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate two overlapping distributions using deterministic pseudo-random values
6 let value: Vec<f64> = (0..200_u64)
7 .map(|i| {
8 let r = ((i.wrapping_mul(1103515245).wrapping_add(12345)) % (1 << 16)) as f64
9 / (1u64 << 16) as f64;
10 if i < 100 {
11 3.0 + r * 4.0
12 } else {
13 5.0 + r * 4.0
14 }
15 })
16 .collect();
17 let group: Vec<&str> = (0..200)
18 .map(|i| if i < 100 { "Group A" } else { "Group B" })
19 .collect();
20
21 let df = df! {
22 "value" => value,
23 "group" => group,
24 }?;
25
26 GGPlot::new(df)
27 .aes(Aes::new().x("value").color("group"))
28 .geom_density()
29 .title("Density Plot by Group")
30 .xlab("Value")
31 .ylab("Density")
32 .save("density.svg")?;
33
34 println!("Saved density.svg");
35 Ok(())
36}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 let sepal_length: Vec<f64> = (0..50).map(|i| 4.5 + i as f64 * 0.05).collect();
6 let sepal_width: Vec<f64> = (0..50)
7 .map(|i| 2.0 + (i as f64 * 0.3).sin() + i as f64 * 0.02)
8 .collect();
9 let species: Vec<&str> = (0..50)
10 .map(|i| match i % 3 {
11 0 => "setosa",
12 1 => "versicolor",
13 _ => "virginica",
14 })
15 .collect();
16
17 let df = df! {
18 "sepal_length" => sepal_length,
19 "sepal_width" => sepal_width,
20 "species" => species,
21 }?;
22
23 GGPlot::new(df)
24 .aes(
25 Aes::new()
26 .x("sepal_length")
27 .y("sepal_width")
28 .color("species"),
29 )
30 .geom_point()
31 .title("Iris Scatter Plot")
32 .xlab("Sepal Length")
33 .ylab("Sepal Width")
34 .save("scatter.svg")?;
35
36 println!("Saved scatter.svg");
37 Ok(())
38}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate scatter data with a continuous variable for color
6 let x: Vec<f64> = (0..200)
7 .map(|i| {
8 let t = i as f64 * 0.05;
9 t.cos() * (1.0 + t * 0.3)
10 })
11 .collect();
12 let y: Vec<f64> = (0..200)
13 .map(|i| {
14 let t = i as f64 * 0.05;
15 t.sin() * (1.0 + t * 0.3)
16 })
17 .collect();
18 let z: Vec<f64> = (0..200).map(|i| i as f64 * 0.05).collect();
19
20 let df = df! {
21 "x" => &x,
22 "y" => &y,
23 "z" => &z,
24 }?;
25
26 // Default blue-to-red gradient
27 GGPlot::new(df.clone())
28 .aes(Aes::new().x("x").y("y").color("z"))
29 .geom_point()
30 .title("Continuous Color (default gradient)")
31 .xlab("X")
32 .ylab("Y")
33 .save("continuous_color.svg")?;
34
35 println!("Saved continuous_color.svg");
36
37 // Custom gradient: dark blue to yellow
38 GGPlot::new(df)
39 .aes(Aes::new().x("x").y("y").color("z"))
40 .geom_point()
41 .scale_color_gradient(RGBAColor::new(10, 30, 100), RGBAColor::new(255, 230, 50))
42 .title("Continuous Color (custom gradient)")
43 .xlab("X")
44 .ylab("Y")
45 .save("continuous_color_custom.svg")?;
46
47 println!("Saved continuous_color_custom.svg");
48 Ok(())
49}246fn compare(rows: &[Po]) -> Result<(), Box<dyn std::error::Error>> {
247 let lead: Vec<Value> = rows
248 .iter()
249 .filter(|p| p.attributable)
250 .map(|p| Value::Float(p.lead))
251 .collect();
252 let supplier: Vec<Value> = rows
253 .iter()
254 .filter(|p| p.attributable)
255 .map(|p| Value::Str(p.supplier.to_string()))
256 .collect();
257 let data: Vec<(String, Vec<Value>)> = vec![
258 ("lead".to_string(), lead),
259 ("supplier".to_string(), supplier),
260 ];
261
262 GGPlot::new(data)
263 .aes(Aes::new().x("lead").fill("supplier").color("supplier"))
264 .geom_density_with(GeomDensity {
265 alpha: 0.35,
266 line_width: 1.2,
267 ..Default::default()
268 })
269 .geom_vline_with(GeomVline {
270 xintercept: CONTRACT,
271 color: CONTRACT_RED,
272 width: 1.2,
273 linetype: Linetype::Dashed,
274 alpha: 1.0,
275 })
276 .scale_fill_brewer(PaletteName::Dark2)
277 .scale_color_brewer(PaletteName::Dark2)
278 .annotate_text("contract", CONTRACT + 1.0, 0.005)
279 .title("Lead-time distributions by supplier")
280 .subtitle("attributable deliveries; dashed line = contracted lead time")
281 .xlab("Actual lead time (days)")
282 .ylab("Density")
283 .theme_minimal()
284 .save_with_size(&out("supplier_leadtime_compare"), W, H)?;
285 Ok(())
286}4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 // Generate data with two grouping variables
6 let sepal_length: Vec<f64> = (0..120)
7 .map(|i| 4.0 + (i as f64) * 0.04 + (i as f64 * 0.5).sin() * 0.3)
8 .collect();
9 let sepal_width: Vec<f64> = (0..120)
10 .map(|i| 2.0 + (i as f64) * 0.015 + (i as f64 * 0.3).cos() * 0.4)
11 .collect();
12 let species: Vec<&str> = (0..120)
13 .map(|i| match i % 3 {
14 0 => "setosa",
15 1 => "versicolor",
16 _ => "virginica",
17 })
18 .collect();
19 let region: Vec<&str> = (0..120)
20 .map(|i| if i % 2 == 0 { "North" } else { "South" })
21 .collect();
22
23 let df = df! {
24 "sepal_length" => sepal_length,
25 "sepal_width" => sepal_width,
26 "species" => species,
27 "region" => region,
28 }?;
29
30 // facet_wrap: one variable, automatic grid layout
31 GGPlot::new(df.clone())
32 .aes(
33 Aes::new()
34 .x("sepal_length")
35 .y("sepal_width")
36 .color("species"),
37 )
38 .geom_point()
39 .facet_wrap("species", Some(2))
40 .title("Facet Wrap by Species")
41 .xlab("Sepal Length")
42 .ylab("Sepal Width")
43 .save("facet_wrap.svg")?;
44
45 println!("Saved facet_wrap.svg");
46
47 // facet_grid: two variables, row ~ col layout
48 GGPlot::new(df)
49 .aes(
50 Aes::new()
51 .x("sepal_length")
52 .y("sepal_width")
53 .color("species"),
54 )
55 .geom_point()
56 .facet_grid(Some("region"), Some("species"))
57 .title("Facet Grid: Region ~ Species")
58 .xlab("Sepal Length")
59 .ylab("Sepal Width")
60 .save("facet_grid.svg")?;
61
62 println!("Saved facet_grid.svg");
63 Ok(())
64}Sourcepub fn fill(self, col: &str) -> Self
pub fn fill(self, col: &str) -> Self
Examples found in repository?
122fn bar() -> Result<(), Box<dyn std::error::Error>> {
123 let mut fruit: Vec<&str> = Vec::new();
124 for (f, c) in [
125 ("Apple", 8),
126 ("Banana", 5),
127 ("Cherry", 11),
128 ("Date", 3),
129 ("Elder", 7),
130 ] {
131 for _ in 0..c {
132 fruit.push(f);
133 }
134 }
135 let df = df! { "fruit" => fruit }?;
136 GGPlot::new(df)
137 .aes(Aes::new().x("fruit").fill("fruit"))
138 .geom_bar()
139 .scale_fill_brewer(PaletteName::Set2)
140 .title("Bar Chart")
141 .xlab("Fruit")
142 .ylab("Count")
143 .theme_minimal()
144 .save_with_size(&out("bar"), W, H)?;
145 Ok(())
146}
147
148/// Grouped boxplots.
149fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
150 let n = 240;
151 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
152 let value: Vec<f64> = (0..n)
153 .map(|i| {
154 let base = (i % 4) as f64 * 1.5;
155 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
156 })
157 .collect();
158
159 let df = df! { "group" => group, "value" => value }?;
160 GGPlot::new(df)
161 .aes(Aes::new().x("group").y("value"))
162 .geom_boxplot_with(GeomBoxplot {
163 fill: (70, 130, 180),
164 ..Default::default()
165 })
166 .title("Boxplot")
167 .xlab("Group")
168 .ylab("Value")
169 .theme_bw()
170 .save_with_size(&out("boxplot"), W, H)?;
171 Ok(())
172}
173
174/// Violin plots of grouped distributions.
175fn violin() -> Result<(), Box<dyn std::error::Error>> {
176 let n = 360;
177 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
178 let value: Vec<f64> = (0..n)
179 .map(|i| {
180 let g = (i % 3) as f64;
181 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
182 })
183 .collect();
184
185 let df = df! { "group" => group, "value" => value }?;
186 GGPlot::new(df)
187 .aes(Aes::new().x("group").y("value").fill("group"))
188 .geom_violin()
189 .scale_fill_brewer(PaletteName::Accent)
190 .title("Violin")
191 .xlab("Group")
192 .ylab("Value")
193 .theme_minimal()
194 .save_with_size(&out("violin"), W, H)?;
195 Ok(())
196}
197
198/// Spiral scatter coloured by a continuous variable (viridis).
199fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
200 let n = 400;
201 let x: Vec<f64> = (0..n)
202 .map(|i| {
203 let t = i as f64 * 0.05;
204 t.cos() * (1.0 + t * 0.12)
205 })
206 .collect();
207 let y: Vec<f64> = (0..n)
208 .map(|i| {
209 let t = i as f64 * 0.05;
210 t.sin() * (1.0 + t * 0.12)
211 })
212 .collect();
213 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
214
215 let df = df! { "x" => x, "y" => y, "z" => z }?;
216 GGPlot::new(df)
217 .aes(Aes::new().x("x").y("y").color("z"))
218 .geom_point()
219 .scale_color_viridis_c()
220 .title("Continuous Color (viridis)")
221 .xlab("x")
222 .ylab("y")
223 .theme_minimal()
224 .save_with_size(&out("continuous_color"), W, H)?;
225 Ok(())
226}
227
228/// Faceted scatter, one panel per group.
229fn facet() -> Result<(), Box<dyn std::error::Error>> {
230 let n = 180;
231 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
232 let y: Vec<f64> = (0..n)
233 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
234 .collect();
235 let species: Vec<&str> = (0..n)
236 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
237 .collect();
238
239 let df = df! { "x" => x, "y" => y, "species" => species }?;
240 GGPlot::new(df)
241 .aes(Aes::new().x("x").y("y").color("species"))
242 .geom_point()
243 .facet_wrap("species", Some(3))
244 .scale_color_brewer(PaletteName::Set1)
245 .title("Facet Wrap")
246 .xlab("x")
247 .ylab("y")
248 .theme_bw()
249 .save_with_size(&out("facet"), W, H)?;
250 Ok(())
251}
252
253/// Overlapping density curves by group.
254fn density() -> Result<(), Box<dyn std::error::Error>> {
255 let n = 600;
256 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
257 let value: Vec<f64> = (0..n)
258 .map(|i| {
259 let shift = (i % 2) as f64 * 2.5;
260 let t = i as f64 * 0.05;
261 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
262 })
263 .collect();
264
265 let df = df! { "value" => value, "group" => group }?;
266 GGPlot::new(df)
267 .aes(Aes::new().x("value").fill("group").color("group"))
268 .geom_density()
269 .scale_fill_brewer(PaletteName::Set1)
270 .scale_color_brewer(PaletteName::Set1)
271 .title("Density by Group")
272 .xlab("Value")
273 .ylab("Density")
274 .theme_minimal()
275 .save_with_size(&out("density"), W, H)?;
276 Ok(())
277}
278
279/// Filled contour bands from a gridded surface.
280fn contour_filled() -> Result<(), Box<dyn std::error::Error>> {
281 let (mut x, mut y, mut z) = (Vec::new(), Vec::new(), Vec::new());
282 for i in 0..40 {
283 for j in 0..40 {
284 let xv = i as f64 * 0.25 - 5.0;
285 let yv = j as f64 * 0.25 - 5.0;
286 x.push(xv);
287 y.push(yv);
288 z.push((xv * 0.6).sin() * (yv * 0.6).cos() + (-(xv * xv + yv * yv) / 30.0).exp());
289 }
290 }
291 let df = df! { "x" => x, "y" => y, "z" => z }?;
292 GGPlot::new(df)
293 .aes(Aes::new().x("x").y("y"))
294 .geom_contour_filled()
295 .scale_fill_viridis_c()
296 .title("Filled Contours")
297 .theme_minimal()
298 .save_with_size(&out("contour_filled"), W, H)?;
299 Ok(())
300}
301
302/// Hexagonal binning of a 2-D point cloud.
303fn hexbin() -> Result<(), Box<dyn std::error::Error>> {
304 let n = 4000;
305 let x: Vec<f64> = (0..n)
306 .map(|i| {
307 let t = i as f64;
308 (t * 0.017).sin() * 2.0 + ((i * 7919 % 1000) as f64 / 1000.0 - 0.5) * 3.0
309 })
310 .collect();
311 let y: Vec<f64> = (0..n)
312 .map(|i| {
313 let t = i as f64;
314 (t * 0.017).cos() * 2.0 + ((i * 6323 % 1000) as f64 / 1000.0 - 0.5) * 3.0
315 })
316 .collect();
317 let df = df! { "x" => x, "y" => y }?;
318 GGPlot::new(df)
319 .aes(Aes::new().x("x").y("y"))
320 .geom_hex()
321 .scale_fill_viridis_c()
322 .title("Hex Binning")
323 .theme_minimal()
324 .save_with_size(&out("hexbin"), W, H)?;
325 Ok(())
326}
327
328/// Heatmap of a gridded value with `geom_tile`.
329fn heatmap() -> Result<(), Box<dyn std::error::Error>> {
330 let (mut x, mut y, mut fill) = (Vec::new(), Vec::new(), Vec::new());
331 for i in 0..14 {
332 for j in 0..14 {
333 x.push(i as f64);
334 y.push(j as f64);
335 fill.push((i as f64 * 0.5).sin() * (j as f64 * 0.5).cos());
336 }
337 }
338 let df = df! { "x" => x, "y" => y, "fill" => fill }?;
339 GGPlot::new(df)
340 .aes(Aes::new().x("x").y("y").fill("fill"))
341 .geom_tile()
342 .scale_fill_viridis_c()
343 .title("Heatmap")
344 .theme_minimal()
345 .save_with_size(&out("heatmap"), W, H)?;
346 Ok(())
347}
348
349/// Jittered categorical scatter (`geom_jitter`).
350fn jitter() -> Result<(), Box<dyn std::error::Error>> {
351 let n = 300;
352 let group: Vec<&str> = (0..n).map(|i| ["Control", "Low", "High"][i % 3]).collect();
353 let value: Vec<f64> = (0..n)
354 .map(|i| {
355 let base = (i % 3) as f64 * 1.5;
356 base + ((i * 5701 % 1000) as f64 / 1000.0 - 0.5) * 2.0
357 })
358 .collect();
359 let df = df! { "group" => group, "value" => value }?;
360 GGPlot::new(df)
361 .aes(Aes::new().x("group").y("value").color("group"))
362 .geom_jitter()
363 .scale_color_brewer(PaletteName::Dark2)
364 .title("Jittered Points")
365 .theme_minimal()
366 .save_with_size(&out("jitter"), W, H)?;
367 Ok(())
368}
369
370/// A confidence band (`geom_ribbon`) under a line.
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}
388
389/// Stacked areas by group.
390fn area_stack() -> Result<(), Box<dyn std::error::Error>> {
391 let n = 40;
392 let mut x = Vec::new();
393 let mut y = Vec::new();
394 let mut g = Vec::new();
395 for grp in ["North", "South", "East"] {
396 for i in 0..n {
397 x.push(i as f64);
398 let base = match grp {
399 "North" => 2.0,
400 "South" => 3.0,
401 _ => 1.5,
402 };
403 y.push(base + (i as f64 * 0.2).sin().abs() * base);
404 g.push(grp);
405 }
406 }
407 let df = df! { "x" => x, "y" => y, "g" => g }?;
408 GGPlot::new(df)
409 .aes(Aes::new().x("x").y("y").fill("g"))
410 .geom_area()
411 .scale_fill_brewer(PaletteName::Set2)
412 .title("Stacked Area")
413 .theme_minimal()
414 .save_with_size(&out("area"), W, H)?;
415 Ok(())
416}More examples
246fn compare(rows: &[Po]) -> Result<(), Box<dyn std::error::Error>> {
247 let lead: Vec<Value> = rows
248 .iter()
249 .filter(|p| p.attributable)
250 .map(|p| Value::Float(p.lead))
251 .collect();
252 let supplier: Vec<Value> = rows
253 .iter()
254 .filter(|p| p.attributable)
255 .map(|p| Value::Str(p.supplier.to_string()))
256 .collect();
257 let data: Vec<(String, Vec<Value>)> = vec![
258 ("lead".to_string(), lead),
259 ("supplier".to_string(), supplier),
260 ];
261
262 GGPlot::new(data)
263 .aes(Aes::new().x("lead").fill("supplier").color("supplier"))
264 .geom_density_with(GeomDensity {
265 alpha: 0.35,
266 line_width: 1.2,
267 ..Default::default()
268 })
269 .geom_vline_with(GeomVline {
270 xintercept: CONTRACT,
271 color: CONTRACT_RED,
272 width: 1.2,
273 linetype: Linetype::Dashed,
274 alpha: 1.0,
275 })
276 .scale_fill_brewer(PaletteName::Dark2)
277 .scale_color_brewer(PaletteName::Dark2)
278 .annotate_text("contract", CONTRACT + 1.0, 0.005)
279 .title("Lead-time distributions by supplier")
280 .subtitle("attributable deliveries; dashed line = contracted lead time")
281 .xlab("Actual lead time (days)")
282 .ylab("Density")
283 .theme_minimal()
284 .save_with_size(&out("supplier_leadtime_compare"), W, H)?;
285 Ok(())
286}pub fn size(self, col: &str) -> Self
pub fn shape(self, col: &str) -> Self
pub fn alpha(self, col: &str) -> Self
pub fn group(self, col: &str) -> Self
Sourcepub fn ymin(self, col: &str) -> Self
pub fn ymin(self, col: &str) -> Self
Examples found in repository?
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}Sourcepub fn ymax(self, col: &str) -> Self
pub fn ymax(self, col: &str) -> Self
Examples found in repository?
371fn ribbon() -> Result<(), Box<dyn std::error::Error>> {
372 let n = 80;
373 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.15).collect();
374 let y: Vec<f64> = x.iter().map(|v| v.sin() + v * 0.1).collect();
375 let ymin: Vec<f64> = y.iter().map(|v| v - 0.4).collect();
376 let ymax: Vec<f64> = y.iter().map(|v| v + 0.4).collect();
377 let df = df! { "x" => x, "y" => y, "ymin" => ymin, "ymax" => ymax }?;
378 GGPlot::new(df)
379 .aes(Aes::new().x("x").y("y").ymin("ymin").ymax("ymax"))
380 .geom_ribbon()
381 .geom_line()
382 .primary_color((49, 130, 189))
383 .title("Ribbon + Line")
384 .theme_minimal()
385 .save_with_size(&out("ribbon"), W, H)?;
386 Ok(())
387}pub fn label(self, col: &str) -> Self
pub fn weight(self, col: &str) -> Self
pub fn xend(self, col: &str) -> Self
pub fn yend(self, col: &str) -> Self
pub fn xmin(self, col: &str) -> Self
pub fn xmax(self, col: &str) -> Self
pub fn angle(self, col: &str) -> Self
pub fn radius(self, col: &str) -> Self
pub fn linetype(self, col: &str) -> Self
Sourcepub fn after_stat_y(self, col: &str) -> Self
pub fn after_stat_y(self, col: &str) -> Self
Map a stat-computed column to the y aesthetic (e.g., after_stat_y("density")).
Sourcepub fn after_stat_x(self, col: &str) -> Self
pub fn after_stat_x(self, col: &str) -> Self
Map a stat-computed column to the x aesthetic.
Sourcepub fn after_stat_fill(self, col: &str) -> Self
pub fn after_stat_fill(self, col: &str) -> Self
Map a stat-computed column to the fill aesthetic.
Sourcepub fn after_stat_color(self, col: &str) -> Self
pub fn after_stat_color(self, col: &str) -> Self
Map a stat-computed column to the color aesthetic.
Sourcepub fn after_stat_size(self, col: &str) -> Self
pub fn after_stat_size(self, col: &str) -> Self
Map a stat-computed column to the size aesthetic.
Sourcepub fn after_stat_alpha(self, col: &str) -> Self
pub fn after_stat_alpha(self, col: &str) -> Self
Map a stat-computed column to the alpha aesthetic.
Sourcepub fn get_mapping(&self, aes: &Aesthetic) -> Option<&str>
pub fn get_mapping(&self, aes: &Aesthetic) -> Option<&str>
Get the column mapped to a specific aesthetic.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Aes
impl RefUnwindSafe for Aes
impl Send for Aes
impl Sync for Aes
impl Unpin for Aes
impl UnsafeUnpin for Aes
impl UnwindSafe for Aes
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more