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}35fn scatter() -> Result<(), Box<dyn std::error::Error>> {
36 let n = 150;
37 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
38 let y: Vec<f64> = (0..n)
39 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
40 .collect();
41 let species: Vec<&str> = (0..n)
42 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
43 .collect();
44
45 let df = df! { "x" => x, "y" => y, "species" => species }?;
46 GGPlot::new(df)
47 .aes(Aes::new().x("x").y("y").color("species"))
48 .geom_point()
49 .scale_color_brewer(PaletteName::Set1)
50 .title("Grouped Scatter")
51 .xlab("Sepal Length")
52 .ylab("Sepal Width")
53 .theme_minimal()
54 .save_with_size(&out("scatter"), W, H)?;
55 Ok(())
56}
57
58/// Points overlaid with a LOESS trend line and confidence band.
59fn smooth() -> Result<(), Box<dyn std::error::Error>> {
60 let n = 120;
61 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
62 let y: Vec<f64> = (0..n)
63 .map(|i| {
64 let t = i as f64 * 0.1;
65 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
66 })
67 .collect();
68
69 let df = df! { "x" => x, "y" => y }?;
70 GGPlot::new(df)
71 .aes(Aes::new().x("x").y("y"))
72 .geom_point()
73 .geom_smooth_with(GeomSmooth {
74 method: SmoothMethod::Loess { span: 0.5 },
75 ..Default::default()
76 })
77 .title("LOESS Smoothing")
78 .xlab("x")
79 .ylab("y")
80 .theme_bw()
81 .save_with_size(&out("smooth"), W, H)?;
82 Ok(())
83}
84
85/// Histogram of an approximately-normal sample.
86fn histogram() -> Result<(), Box<dyn std::error::Error>> {
87 let values: Vec<f64> = (0..1500)
88 .map(|i: i32| {
89 let r: f64 = (0..6)
90 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
91 .sum();
92 (r - 3.0) * 2.0
93 })
94 .collect();
95
96 let df = df! { "measurement" => values }?;
97 GGPlot::new(df)
98 .aes(Aes::new().x("measurement"))
99 .geom_histogram_with(GeomHistogram {
100 bins: 30,
101 ..Default::default()
102 })
103 .title("Histogram")
104 .xlab("Value")
105 .ylab("Count")
106 .theme_minimal()
107 .save_with_size(&out("histogram"), W, H)?;
108 Ok(())
109}
110
111/// Bar chart of category counts with a fill palette.
112fn bar() -> Result<(), Box<dyn std::error::Error>> {
113 let mut fruit: Vec<&str> = Vec::new();
114 for (f, c) in [
115 ("Apple", 8),
116 ("Banana", 5),
117 ("Cherry", 11),
118 ("Date", 3),
119 ("Elder", 7),
120 ] {
121 for _ in 0..c {
122 fruit.push(f);
123 }
124 }
125 let df = df! { "fruit" => fruit }?;
126 GGPlot::new(df)
127 .aes(Aes::new().x("fruit").fill("fruit"))
128 .geom_bar()
129 .scale_fill_brewer(PaletteName::Set2)
130 .title("Bar Chart")
131 .xlab("Fruit")
132 .ylab("Count")
133 .theme_minimal()
134 .save_with_size(&out("bar"), W, H)?;
135 Ok(())
136}
137
138/// Grouped boxplots.
139fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
140 let n = 240;
141 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
142 let value: Vec<f64> = (0..n)
143 .map(|i| {
144 let base = (i % 4) as f64 * 1.5;
145 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
146 })
147 .collect();
148
149 let df = df! { "group" => group, "value" => value }?;
150 GGPlot::new(df)
151 .aes(Aes::new().x("group").y("value"))
152 .geom_boxplot_with(GeomBoxplot {
153 fill: (70, 130, 180),
154 ..Default::default()
155 })
156 .title("Boxplot")
157 .xlab("Group")
158 .ylab("Value")
159 .theme_bw()
160 .save_with_size(&out("boxplot"), W, H)?;
161 Ok(())
162}
163
164/// Violin plots of grouped distributions.
165fn violin() -> Result<(), Box<dyn std::error::Error>> {
166 let n = 360;
167 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
168 let value: Vec<f64> = (0..n)
169 .map(|i| {
170 let g = (i % 3) as f64;
171 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
172 })
173 .collect();
174
175 let df = df! { "group" => group, "value" => value }?;
176 GGPlot::new(df)
177 .aes(Aes::new().x("group").y("value").fill("group"))
178 .geom_violin()
179 .scale_fill_brewer(PaletteName::Accent)
180 .title("Violin")
181 .xlab("Group")
182 .ylab("Value")
183 .theme_minimal()
184 .save_with_size(&out("violin"), W, H)?;
185 Ok(())
186}
187
188/// Spiral scatter coloured by a continuous variable (viridis).
189fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
190 let n = 400;
191 let x: Vec<f64> = (0..n)
192 .map(|i| {
193 let t = i as f64 * 0.05;
194 t.cos() * (1.0 + t * 0.12)
195 })
196 .collect();
197 let y: Vec<f64> = (0..n)
198 .map(|i| {
199 let t = i as f64 * 0.05;
200 t.sin() * (1.0 + t * 0.12)
201 })
202 .collect();
203 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
204
205 let df = df! { "x" => x, "y" => y, "z" => z }?;
206 GGPlot::new(df)
207 .aes(Aes::new().x("x").y("y").color("z"))
208 .geom_point()
209 .scale_color_viridis_c()
210 .title("Continuous Color (viridis)")
211 .xlab("x")
212 .ylab("y")
213 .theme_minimal()
214 .save_with_size(&out("continuous_color"), W, H)?;
215 Ok(())
216}
217
218/// Faceted scatter, one panel per group.
219fn facet() -> Result<(), Box<dyn std::error::Error>> {
220 let n = 180;
221 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
222 let y: Vec<f64> = (0..n)
223 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
224 .collect();
225 let species: Vec<&str> = (0..n)
226 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
227 .collect();
228
229 let df = df! { "x" => x, "y" => y, "species" => species }?;
230 GGPlot::new(df)
231 .aes(Aes::new().x("x").y("y").color("species"))
232 .geom_point()
233 .facet_wrap("species", Some(3))
234 .scale_color_brewer(PaletteName::Set1)
235 .title("Facet Wrap")
236 .xlab("x")
237 .ylab("y")
238 .theme_bw()
239 .save_with_size(&out("facet"), W, H)?;
240 Ok(())
241}
242
243/// Overlapping density curves by group.
244fn density() -> Result<(), Box<dyn std::error::Error>> {
245 let n = 600;
246 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
247 let value: Vec<f64> = (0..n)
248 .map(|i| {
249 let shift = (i % 2) as f64 * 2.5;
250 let t = i as f64 * 0.05;
251 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
252 })
253 .collect();
254
255 let df = df! { "value" => value, "group" => group }?;
256 GGPlot::new(df)
257 .aes(Aes::new().x("value").fill("group").color("group"))
258 .geom_density()
259 .scale_fill_brewer(PaletteName::Set1)
260 .scale_color_brewer(PaletteName::Set1)
261 .title("Density by Group")
262 .xlab("Value")
263 .ylab("Density")
264 .theme_minimal()
265 .save_with_size(&out("density"), W, H)?;
266 Ok(())
267}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}35fn scatter() -> Result<(), Box<dyn std::error::Error>> {
36 let n = 150;
37 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
38 let y: Vec<f64> = (0..n)
39 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
40 .collect();
41 let species: Vec<&str> = (0..n)
42 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
43 .collect();
44
45 let df = df! { "x" => x, "y" => y, "species" => species }?;
46 GGPlot::new(df)
47 .aes(Aes::new().x("x").y("y").color("species"))
48 .geom_point()
49 .scale_color_brewer(PaletteName::Set1)
50 .title("Grouped Scatter")
51 .xlab("Sepal Length")
52 .ylab("Sepal Width")
53 .theme_minimal()
54 .save_with_size(&out("scatter"), W, H)?;
55 Ok(())
56}
57
58/// Points overlaid with a LOESS trend line and confidence band.
59fn smooth() -> Result<(), Box<dyn std::error::Error>> {
60 let n = 120;
61 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
62 let y: Vec<f64> = (0..n)
63 .map(|i| {
64 let t = i as f64 * 0.1;
65 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
66 })
67 .collect();
68
69 let df = df! { "x" => x, "y" => y }?;
70 GGPlot::new(df)
71 .aes(Aes::new().x("x").y("y"))
72 .geom_point()
73 .geom_smooth_with(GeomSmooth {
74 method: SmoothMethod::Loess { span: 0.5 },
75 ..Default::default()
76 })
77 .title("LOESS Smoothing")
78 .xlab("x")
79 .ylab("y")
80 .theme_bw()
81 .save_with_size(&out("smooth"), W, H)?;
82 Ok(())
83}
84
85/// Histogram of an approximately-normal sample.
86fn histogram() -> Result<(), Box<dyn std::error::Error>> {
87 let values: Vec<f64> = (0..1500)
88 .map(|i: i32| {
89 let r: f64 = (0..6)
90 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
91 .sum();
92 (r - 3.0) * 2.0
93 })
94 .collect();
95
96 let df = df! { "measurement" => values }?;
97 GGPlot::new(df)
98 .aes(Aes::new().x("measurement"))
99 .geom_histogram_with(GeomHistogram {
100 bins: 30,
101 ..Default::default()
102 })
103 .title("Histogram")
104 .xlab("Value")
105 .ylab("Count")
106 .theme_minimal()
107 .save_with_size(&out("histogram"), W, H)?;
108 Ok(())
109}
110
111/// Bar chart of category counts with a fill palette.
112fn bar() -> Result<(), Box<dyn std::error::Error>> {
113 let mut fruit: Vec<&str> = Vec::new();
114 for (f, c) in [
115 ("Apple", 8),
116 ("Banana", 5),
117 ("Cherry", 11),
118 ("Date", 3),
119 ("Elder", 7),
120 ] {
121 for _ in 0..c {
122 fruit.push(f);
123 }
124 }
125 let df = df! { "fruit" => fruit }?;
126 GGPlot::new(df)
127 .aes(Aes::new().x("fruit").fill("fruit"))
128 .geom_bar()
129 .scale_fill_brewer(PaletteName::Set2)
130 .title("Bar Chart")
131 .xlab("Fruit")
132 .ylab("Count")
133 .theme_minimal()
134 .save_with_size(&out("bar"), W, H)?;
135 Ok(())
136}
137
138/// Grouped boxplots.
139fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
140 let n = 240;
141 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
142 let value: Vec<f64> = (0..n)
143 .map(|i| {
144 let base = (i % 4) as f64 * 1.5;
145 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
146 })
147 .collect();
148
149 let df = df! { "group" => group, "value" => value }?;
150 GGPlot::new(df)
151 .aes(Aes::new().x("group").y("value"))
152 .geom_boxplot_with(GeomBoxplot {
153 fill: (70, 130, 180),
154 ..Default::default()
155 })
156 .title("Boxplot")
157 .xlab("Group")
158 .ylab("Value")
159 .theme_bw()
160 .save_with_size(&out("boxplot"), W, H)?;
161 Ok(())
162}
163
164/// Violin plots of grouped distributions.
165fn violin() -> Result<(), Box<dyn std::error::Error>> {
166 let n = 360;
167 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
168 let value: Vec<f64> = (0..n)
169 .map(|i| {
170 let g = (i % 3) as f64;
171 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
172 })
173 .collect();
174
175 let df = df! { "group" => group, "value" => value }?;
176 GGPlot::new(df)
177 .aes(Aes::new().x("group").y("value").fill("group"))
178 .geom_violin()
179 .scale_fill_brewer(PaletteName::Accent)
180 .title("Violin")
181 .xlab("Group")
182 .ylab("Value")
183 .theme_minimal()
184 .save_with_size(&out("violin"), W, H)?;
185 Ok(())
186}
187
188/// Spiral scatter coloured by a continuous variable (viridis).
189fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
190 let n = 400;
191 let x: Vec<f64> = (0..n)
192 .map(|i| {
193 let t = i as f64 * 0.05;
194 t.cos() * (1.0 + t * 0.12)
195 })
196 .collect();
197 let y: Vec<f64> = (0..n)
198 .map(|i| {
199 let t = i as f64 * 0.05;
200 t.sin() * (1.0 + t * 0.12)
201 })
202 .collect();
203 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
204
205 let df = df! { "x" => x, "y" => y, "z" => z }?;
206 GGPlot::new(df)
207 .aes(Aes::new().x("x").y("y").color("z"))
208 .geom_point()
209 .scale_color_viridis_c()
210 .title("Continuous Color (viridis)")
211 .xlab("x")
212 .ylab("y")
213 .theme_minimal()
214 .save_with_size(&out("continuous_color"), W, H)?;
215 Ok(())
216}
217
218/// Faceted scatter, one panel per group.
219fn facet() -> Result<(), Box<dyn std::error::Error>> {
220 let n = 180;
221 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
222 let y: Vec<f64> = (0..n)
223 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
224 .collect();
225 let species: Vec<&str> = (0..n)
226 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
227 .collect();
228
229 let df = df! { "x" => x, "y" => y, "species" => species }?;
230 GGPlot::new(df)
231 .aes(Aes::new().x("x").y("y").color("species"))
232 .geom_point()
233 .facet_wrap("species", Some(3))
234 .scale_color_brewer(PaletteName::Set1)
235 .title("Facet Wrap")
236 .xlab("x")
237 .ylab("y")
238 .theme_bw()
239 .save_with_size(&out("facet"), W, H)?;
240 Ok(())
241}
242
243/// Overlapping density curves by group.
244fn density() -> Result<(), Box<dyn std::error::Error>> {
245 let n = 600;
246 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
247 let value: Vec<f64> = (0..n)
248 .map(|i| {
249 let shift = (i % 2) as f64 * 2.5;
250 let t = i as f64 * 0.05;
251 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
252 })
253 .collect();
254
255 let df = df! { "value" => value, "group" => group }?;
256 GGPlot::new(df)
257 .aes(Aes::new().x("value").fill("group").color("group"))
258 .geom_density()
259 .scale_fill_brewer(PaletteName::Set1)
260 .scale_color_brewer(PaletteName::Set1)
261 .title("Density by Group")
262 .xlab("Value")
263 .ylab("Density")
264 .theme_minimal()
265 .save_with_size(&out("density"), W, H)?;
266 Ok(())
267}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
35fn scatter() -> Result<(), Box<dyn std::error::Error>> {
36 let n = 150;
37 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
38 let y: Vec<f64> = (0..n)
39 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
40 .collect();
41 let species: Vec<&str> = (0..n)
42 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
43 .collect();
44
45 let df = df! { "x" => x, "y" => y, "species" => species }?;
46 GGPlot::new(df)
47 .aes(Aes::new().x("x").y("y").color("species"))
48 .geom_point()
49 .scale_color_brewer(PaletteName::Set1)
50 .title("Grouped Scatter")
51 .xlab("Sepal Length")
52 .ylab("Sepal Width")
53 .theme_minimal()
54 .save_with_size(&out("scatter"), W, H)?;
55 Ok(())
56}
57
58/// Points overlaid with a LOESS trend line and confidence band.
59fn smooth() -> Result<(), Box<dyn std::error::Error>> {
60 let n = 120;
61 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
62 let y: Vec<f64> = (0..n)
63 .map(|i| {
64 let t = i as f64 * 0.1;
65 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
66 })
67 .collect();
68
69 let df = df! { "x" => x, "y" => y }?;
70 GGPlot::new(df)
71 .aes(Aes::new().x("x").y("y"))
72 .geom_point()
73 .geom_smooth_with(GeomSmooth {
74 method: SmoothMethod::Loess { span: 0.5 },
75 ..Default::default()
76 })
77 .title("LOESS Smoothing")
78 .xlab("x")
79 .ylab("y")
80 .theme_bw()
81 .save_with_size(&out("smooth"), W, H)?;
82 Ok(())
83}
84
85/// Histogram of an approximately-normal sample.
86fn histogram() -> Result<(), Box<dyn std::error::Error>> {
87 let values: Vec<f64> = (0..1500)
88 .map(|i: i32| {
89 let r: f64 = (0..6)
90 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
91 .sum();
92 (r - 3.0) * 2.0
93 })
94 .collect();
95
96 let df = df! { "measurement" => values }?;
97 GGPlot::new(df)
98 .aes(Aes::new().x("measurement"))
99 .geom_histogram_with(GeomHistogram {
100 bins: 30,
101 ..Default::default()
102 })
103 .title("Histogram")
104 .xlab("Value")
105 .ylab("Count")
106 .theme_minimal()
107 .save_with_size(&out("histogram"), W, H)?;
108 Ok(())
109}
110
111/// Bar chart of category counts with a fill palette.
112fn bar() -> Result<(), Box<dyn std::error::Error>> {
113 let mut fruit: Vec<&str> = Vec::new();
114 for (f, c) in [
115 ("Apple", 8),
116 ("Banana", 5),
117 ("Cherry", 11),
118 ("Date", 3),
119 ("Elder", 7),
120 ] {
121 for _ in 0..c {
122 fruit.push(f);
123 }
124 }
125 let df = df! { "fruit" => fruit }?;
126 GGPlot::new(df)
127 .aes(Aes::new().x("fruit").fill("fruit"))
128 .geom_bar()
129 .scale_fill_brewer(PaletteName::Set2)
130 .title("Bar Chart")
131 .xlab("Fruit")
132 .ylab("Count")
133 .theme_minimal()
134 .save_with_size(&out("bar"), W, H)?;
135 Ok(())
136}
137
138/// Grouped boxplots.
139fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
140 let n = 240;
141 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
142 let value: Vec<f64> = (0..n)
143 .map(|i| {
144 let base = (i % 4) as f64 * 1.5;
145 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
146 })
147 .collect();
148
149 let df = df! { "group" => group, "value" => value }?;
150 GGPlot::new(df)
151 .aes(Aes::new().x("group").y("value"))
152 .geom_boxplot_with(GeomBoxplot {
153 fill: (70, 130, 180),
154 ..Default::default()
155 })
156 .title("Boxplot")
157 .xlab("Group")
158 .ylab("Value")
159 .theme_bw()
160 .save_with_size(&out("boxplot"), W, H)?;
161 Ok(())
162}
163
164/// Violin plots of grouped distributions.
165fn violin() -> Result<(), Box<dyn std::error::Error>> {
166 let n = 360;
167 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
168 let value: Vec<f64> = (0..n)
169 .map(|i| {
170 let g = (i % 3) as f64;
171 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
172 })
173 .collect();
174
175 let df = df! { "group" => group, "value" => value }?;
176 GGPlot::new(df)
177 .aes(Aes::new().x("group").y("value").fill("group"))
178 .geom_violin()
179 .scale_fill_brewer(PaletteName::Accent)
180 .title("Violin")
181 .xlab("Group")
182 .ylab("Value")
183 .theme_minimal()
184 .save_with_size(&out("violin"), W, H)?;
185 Ok(())
186}
187
188/// Spiral scatter coloured by a continuous variable (viridis).
189fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
190 let n = 400;
191 let x: Vec<f64> = (0..n)
192 .map(|i| {
193 let t = i as f64 * 0.05;
194 t.cos() * (1.0 + t * 0.12)
195 })
196 .collect();
197 let y: Vec<f64> = (0..n)
198 .map(|i| {
199 let t = i as f64 * 0.05;
200 t.sin() * (1.0 + t * 0.12)
201 })
202 .collect();
203 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
204
205 let df = df! { "x" => x, "y" => y, "z" => z }?;
206 GGPlot::new(df)
207 .aes(Aes::new().x("x").y("y").color("z"))
208 .geom_point()
209 .scale_color_viridis_c()
210 .title("Continuous Color (viridis)")
211 .xlab("x")
212 .ylab("y")
213 .theme_minimal()
214 .save_with_size(&out("continuous_color"), W, H)?;
215 Ok(())
216}
217
218/// Faceted scatter, one panel per group.
219fn facet() -> Result<(), Box<dyn std::error::Error>> {
220 let n = 180;
221 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
222 let y: Vec<f64> = (0..n)
223 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
224 .collect();
225 let species: Vec<&str> = (0..n)
226 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
227 .collect();
228
229 let df = df! { "x" => x, "y" => y, "species" => species }?;
230 GGPlot::new(df)
231 .aes(Aes::new().x("x").y("y").color("species"))
232 .geom_point()
233 .facet_wrap("species", Some(3))
234 .scale_color_brewer(PaletteName::Set1)
235 .title("Facet Wrap")
236 .xlab("x")
237 .ylab("y")
238 .theme_bw()
239 .save_with_size(&out("facet"), W, H)?;
240 Ok(())
241}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?
35fn scatter() -> Result<(), Box<dyn std::error::Error>> {
36 let n = 150;
37 let x: Vec<f64> = (0..n).map(|i| 4.5 + i as f64 * 0.02).collect();
38 let y: Vec<f64> = (0..n)
39 .map(|i| 2.5 + (i as f64 * 0.15).sin() + (i % 3) as f64 * 0.6)
40 .collect();
41 let species: Vec<&str> = (0..n)
42 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
43 .collect();
44
45 let df = df! { "x" => x, "y" => y, "species" => species }?;
46 GGPlot::new(df)
47 .aes(Aes::new().x("x").y("y").color("species"))
48 .geom_point()
49 .scale_color_brewer(PaletteName::Set1)
50 .title("Grouped Scatter")
51 .xlab("Sepal Length")
52 .ylab("Sepal Width")
53 .theme_minimal()
54 .save_with_size(&out("scatter"), W, H)?;
55 Ok(())
56}
57
58/// Points overlaid with a LOESS trend line and confidence band.
59fn smooth() -> Result<(), Box<dyn std::error::Error>> {
60 let n = 120;
61 let x: Vec<f64> = (0..n).map(|i| i as f64 * 0.1).collect();
62 let y: Vec<f64> = (0..n)
63 .map(|i| {
64 let t = i as f64 * 0.1;
65 (t * 0.6).sin() * 3.0 + t * 0.2 + ((i * 7919 % 100) as f64 / 100.0 - 0.5) * 1.5
66 })
67 .collect();
68
69 let df = df! { "x" => x, "y" => y }?;
70 GGPlot::new(df)
71 .aes(Aes::new().x("x").y("y"))
72 .geom_point()
73 .geom_smooth_with(GeomSmooth {
74 method: SmoothMethod::Loess { span: 0.5 },
75 ..Default::default()
76 })
77 .title("LOESS Smoothing")
78 .xlab("x")
79 .ylab("y")
80 .theme_bw()
81 .save_with_size(&out("smooth"), W, H)?;
82 Ok(())
83}
84
85/// Histogram of an approximately-normal sample.
86fn histogram() -> Result<(), Box<dyn std::error::Error>> {
87 let values: Vec<f64> = (0..1500)
88 .map(|i: i32| {
89 let r: f64 = (0..6)
90 .map(|k| ((i * (1237 + k * 311) + 5678) % 1000) as f64 / 1000.0)
91 .sum();
92 (r - 3.0) * 2.0
93 })
94 .collect();
95
96 let df = df! { "measurement" => values }?;
97 GGPlot::new(df)
98 .aes(Aes::new().x("measurement"))
99 .geom_histogram_with(GeomHistogram {
100 bins: 30,
101 ..Default::default()
102 })
103 .title("Histogram")
104 .xlab("Value")
105 .ylab("Count")
106 .theme_minimal()
107 .save_with_size(&out("histogram"), W, H)?;
108 Ok(())
109}
110
111/// Bar chart of category counts with a fill palette.
112fn bar() -> Result<(), Box<dyn std::error::Error>> {
113 let mut fruit: Vec<&str> = Vec::new();
114 for (f, c) in [
115 ("Apple", 8),
116 ("Banana", 5),
117 ("Cherry", 11),
118 ("Date", 3),
119 ("Elder", 7),
120 ] {
121 for _ in 0..c {
122 fruit.push(f);
123 }
124 }
125 let df = df! { "fruit" => fruit }?;
126 GGPlot::new(df)
127 .aes(Aes::new().x("fruit").fill("fruit"))
128 .geom_bar()
129 .scale_fill_brewer(PaletteName::Set2)
130 .title("Bar Chart")
131 .xlab("Fruit")
132 .ylab("Count")
133 .theme_minimal()
134 .save_with_size(&out("bar"), W, H)?;
135 Ok(())
136}
137
138/// Grouped boxplots.
139fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
140 let n = 240;
141 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
142 let value: Vec<f64> = (0..n)
143 .map(|i| {
144 let base = (i % 4) as f64 * 1.5;
145 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
146 })
147 .collect();
148
149 let df = df! { "group" => group, "value" => value }?;
150 GGPlot::new(df)
151 .aes(Aes::new().x("group").y("value"))
152 .geom_boxplot_with(GeomBoxplot {
153 fill: (70, 130, 180),
154 ..Default::default()
155 })
156 .title("Boxplot")
157 .xlab("Group")
158 .ylab("Value")
159 .theme_bw()
160 .save_with_size(&out("boxplot"), W, H)?;
161 Ok(())
162}
163
164/// Violin plots of grouped distributions.
165fn violin() -> Result<(), Box<dyn std::error::Error>> {
166 let n = 360;
167 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
168 let value: Vec<f64> = (0..n)
169 .map(|i| {
170 let g = (i % 3) as f64;
171 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
172 })
173 .collect();
174
175 let df = df! { "group" => group, "value" => value }?;
176 GGPlot::new(df)
177 .aes(Aes::new().x("group").y("value").fill("group"))
178 .geom_violin()
179 .scale_fill_brewer(PaletteName::Accent)
180 .title("Violin")
181 .xlab("Group")
182 .ylab("Value")
183 .theme_minimal()
184 .save_with_size(&out("violin"), W, H)?;
185 Ok(())
186}
187
188/// Spiral scatter coloured by a continuous variable (viridis).
189fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
190 let n = 400;
191 let x: Vec<f64> = (0..n)
192 .map(|i| {
193 let t = i as f64 * 0.05;
194 t.cos() * (1.0 + t * 0.12)
195 })
196 .collect();
197 let y: Vec<f64> = (0..n)
198 .map(|i| {
199 let t = i as f64 * 0.05;
200 t.sin() * (1.0 + t * 0.12)
201 })
202 .collect();
203 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
204
205 let df = df! { "x" => x, "y" => y, "z" => z }?;
206 GGPlot::new(df)
207 .aes(Aes::new().x("x").y("y").color("z"))
208 .geom_point()
209 .scale_color_viridis_c()
210 .title("Continuous Color (viridis)")
211 .xlab("x")
212 .ylab("y")
213 .theme_minimal()
214 .save_with_size(&out("continuous_color"), W, H)?;
215 Ok(())
216}
217
218/// Faceted scatter, one panel per group.
219fn facet() -> Result<(), Box<dyn std::error::Error>> {
220 let n = 180;
221 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
222 let y: Vec<f64> = (0..n)
223 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
224 .collect();
225 let species: Vec<&str> = (0..n)
226 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
227 .collect();
228
229 let df = df! { "x" => x, "y" => y, "species" => species }?;
230 GGPlot::new(df)
231 .aes(Aes::new().x("x").y("y").color("species"))
232 .geom_point()
233 .facet_wrap("species", Some(3))
234 .scale_color_brewer(PaletteName::Set1)
235 .title("Facet Wrap")
236 .xlab("x")
237 .ylab("y")
238 .theme_bw()
239 .save_with_size(&out("facet"), W, H)?;
240 Ok(())
241}
242
243/// Overlapping density curves by group.
244fn density() -> Result<(), Box<dyn std::error::Error>> {
245 let n = 600;
246 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
247 let value: Vec<f64> = (0..n)
248 .map(|i| {
249 let shift = (i % 2) as f64 * 2.5;
250 let t = i as f64 * 0.05;
251 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
252 })
253 .collect();
254
255 let df = df! { "value" => value, "group" => group }?;
256 GGPlot::new(df)
257 .aes(Aes::new().x("value").fill("group").color("group"))
258 .geom_density()
259 .scale_fill_brewer(PaletteName::Set1)
260 .scale_color_brewer(PaletteName::Set1)
261 .title("Density by Group")
262 .xlab("Value")
263 .ylab("Density")
264 .theme_minimal()
265 .save_with_size(&out("density"), W, H)?;
266 Ok(())
267}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?
112fn bar() -> Result<(), Box<dyn std::error::Error>> {
113 let mut fruit: Vec<&str> = Vec::new();
114 for (f, c) in [
115 ("Apple", 8),
116 ("Banana", 5),
117 ("Cherry", 11),
118 ("Date", 3),
119 ("Elder", 7),
120 ] {
121 for _ in 0..c {
122 fruit.push(f);
123 }
124 }
125 let df = df! { "fruit" => fruit }?;
126 GGPlot::new(df)
127 .aes(Aes::new().x("fruit").fill("fruit"))
128 .geom_bar()
129 .scale_fill_brewer(PaletteName::Set2)
130 .title("Bar Chart")
131 .xlab("Fruit")
132 .ylab("Count")
133 .theme_minimal()
134 .save_with_size(&out("bar"), W, H)?;
135 Ok(())
136}
137
138/// Grouped boxplots.
139fn boxplot() -> Result<(), Box<dyn std::error::Error>> {
140 let n = 240;
141 let group: Vec<&str> = (0..n).map(|i| ["A", "B", "C", "D"][i % 4]).collect();
142 let value: Vec<f64> = (0..n)
143 .map(|i| {
144 let base = (i % 4) as f64 * 1.5;
145 base + (i as f64 * 0.4).sin() * 1.2 + ((i * 6151 % 100) as f64 / 100.0 - 0.5) * 2.0
146 })
147 .collect();
148
149 let df = df! { "group" => group, "value" => value }?;
150 GGPlot::new(df)
151 .aes(Aes::new().x("group").y("value"))
152 .geom_boxplot_with(GeomBoxplot {
153 fill: (70, 130, 180),
154 ..Default::default()
155 })
156 .title("Boxplot")
157 .xlab("Group")
158 .ylab("Value")
159 .theme_bw()
160 .save_with_size(&out("boxplot"), W, H)?;
161 Ok(())
162}
163
164/// Violin plots of grouped distributions.
165fn violin() -> Result<(), Box<dyn std::error::Error>> {
166 let n = 360;
167 let group: Vec<&str> = (0..n).map(|i| ["X", "Y", "Z"][i % 3]).collect();
168 let value: Vec<f64> = (0..n)
169 .map(|i| {
170 let g = (i % 3) as f64;
171 g * 2.0 + (i as f64 * 0.5).sin() * 1.5 + ((i * 4231 % 100) as f64 / 100.0 - 0.5) * 2.5
172 })
173 .collect();
174
175 let df = df! { "group" => group, "value" => value }?;
176 GGPlot::new(df)
177 .aes(Aes::new().x("group").y("value").fill("group"))
178 .geom_violin()
179 .scale_fill_brewer(PaletteName::Accent)
180 .title("Violin")
181 .xlab("Group")
182 .ylab("Value")
183 .theme_minimal()
184 .save_with_size(&out("violin"), W, H)?;
185 Ok(())
186}
187
188/// Spiral scatter coloured by a continuous variable (viridis).
189fn continuous_color() -> Result<(), Box<dyn std::error::Error>> {
190 let n = 400;
191 let x: Vec<f64> = (0..n)
192 .map(|i| {
193 let t = i as f64 * 0.05;
194 t.cos() * (1.0 + t * 0.12)
195 })
196 .collect();
197 let y: Vec<f64> = (0..n)
198 .map(|i| {
199 let t = i as f64 * 0.05;
200 t.sin() * (1.0 + t * 0.12)
201 })
202 .collect();
203 let z: Vec<f64> = (0..n).map(|i| i as f64 * 0.05).collect();
204
205 let df = df! { "x" => x, "y" => y, "z" => z }?;
206 GGPlot::new(df)
207 .aes(Aes::new().x("x").y("y").color("z"))
208 .geom_point()
209 .scale_color_viridis_c()
210 .title("Continuous Color (viridis)")
211 .xlab("x")
212 .ylab("y")
213 .theme_minimal()
214 .save_with_size(&out("continuous_color"), W, H)?;
215 Ok(())
216}
217
218/// Faceted scatter, one panel per group.
219fn facet() -> Result<(), Box<dyn std::error::Error>> {
220 let n = 180;
221 let x: Vec<f64> = (0..n).map(|i| (i as f64 * 0.1).cos() * 3.0).collect();
222 let y: Vec<f64> = (0..n)
223 .map(|i| (i as f64 * 0.1).sin() * 3.0 + (i % 3) as f64)
224 .collect();
225 let species: Vec<&str> = (0..n)
226 .map(|i| ["setosa", "versicolor", "virginica"][i % 3])
227 .collect();
228
229 let df = df! { "x" => x, "y" => y, "species" => species }?;
230 GGPlot::new(df)
231 .aes(Aes::new().x("x").y("y").color("species"))
232 .geom_point()
233 .facet_wrap("species", Some(3))
234 .scale_color_brewer(PaletteName::Set1)
235 .title("Facet Wrap")
236 .xlab("x")
237 .ylab("y")
238 .theme_bw()
239 .save_with_size(&out("facet"), W, H)?;
240 Ok(())
241}
242
243/// Overlapping density curves by group.
244fn density() -> Result<(), Box<dyn std::error::Error>> {
245 let n = 600;
246 let group: Vec<&str> = (0..n).map(|i| ["Group 1", "Group 2"][i % 2]).collect();
247 let value: Vec<f64> = (0..n)
248 .map(|i| {
249 let shift = (i % 2) as f64 * 2.5;
250 let t = i as f64 * 0.05;
251 shift + (t.sin() + (t * 1.7).cos()) + ((i * 3319 % 100) as f64 / 100.0 - 0.5) * PI
252 })
253 .collect();
254
255 let df = df! { "value" => value, "group" => group }?;
256 GGPlot::new(df)
257 .aes(Aes::new().x("value").fill("group").color("group"))
258 .geom_density()
259 .scale_fill_brewer(PaletteName::Set1)
260 .scale_color_brewer(PaletteName::Set1)
261 .title("Density by Group")
262 .xlab("Value")
263 .ylab("Density")
264 .theme_minimal()
265 .save_with_size(&out("density"), W, H)?;
266 Ok(())
267}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
pub fn ymin(self, col: &str) -> Self
pub fn ymax(self, col: &str) -> Self
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