pub struct TreemapBuilder { /* private fields */ }Expand description
Builder for treemap charts.
Implementations§
Source§impl TreemapBuilder
impl TreemapBuilder
Sourcepub fn title(self, title: impl Into<String>) -> Self
pub fn title(self, title: impl Into<String>) -> Self
Set title.
Examples found in repository?
examples/basic_treemap.rs (line 24)
4fn main() -> esoc_chart::error::Result<()> {
5 let labels = vec![
6 "Electronics",
7 "Clothing",
8 "Food & Beverage",
9 "Home & Garden",
10 "Books",
11 "Sports",
12 "Toys",
13 "Automotive",
14 ];
15 let values = vec![320.0, 180.0, 150.0, 120.0, 80.0, 60.0, 45.0, 30.0];
16
17 let mut theme = esoc_chart::new_theme::NewTheme::light();
18 theme.base_font_size = 13.0;
19 theme.title_font_size = 18.0;
20 theme.legend_font_size = 11.0;
21 theme.font_family = "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif".into();
22
23 let svg = esoc_chart::express::treemap(&labels, &values)
24 .title("Sales by Category ($M)")
25 .theme(theme)
26 .size(900.0, 600.0)
27 .to_svg()?;
28
29 std::fs::write("treemap.svg", &svg)?;
30 println!("Wrote treemap.svg ({} bytes)", svg.len());
31 Ok(())
32}More examples
examples/readme_charts.rs (line 249)
15fn main() -> esoc_chart::error::Result<()> {
16 // Simple deterministic RNG
17 struct Rng(u64);
18 impl Rng {
19 fn uniform(&mut self) -> f64 {
20 self.0 = self
21 .0
22 .wrapping_mul(6_364_136_223_846_793_005)
23 .wrapping_add(1);
24 (self.0 >> 11) as f64 / (1u64 << 53) as f64
25 }
26 fn normal(&mut self) -> f64 {
27 let u1 = self.uniform().max(1e-15);
28 let u2 = self.uniform();
29 (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos()
30 }
31 }
32 let mut rng = Rng(42);
33
34 let dir = "crates/esoc-chart/images";
35 std::fs::create_dir_all(dir).unwrap();
36
37 // ── 1. Scatter ──────────────────────────────────────────────────
38 {
39 let n = 80;
40 let x: Vec<f64> = (0..n).map(|_| rng.uniform() * 10.0).collect();
41 let y: Vec<f64> = x
42 .iter()
43 .map(|&xi| 0.4 * xi * xi - 2.0 * xi + 3.0 + rng.normal() * 2.0)
44 .collect();
45 scatter(&x, &y)
46 .title("Quadratic Trend")
47 .x_label("x")
48 .y_label("y")
49 .size(560.0, 380.0)
50 .save_svg(format!("{dir}/scatter.svg"))?;
51 }
52
53 // ── 2. Scatter with categories ──────────────────────────────────
54 {
55 let mut x = Vec::new();
56 let mut y = Vec::new();
57 let mut cats = Vec::new();
58 for (label, cx, cy) in [("Setosa", 5.0, 3.4), ("Versicolor", 5.9, 2.8), ("Virginica", 6.6, 3.0)] {
59 for _ in 0..40 {
60 x.push(cx + rng.normal() * 0.4);
61 y.push(cy + rng.normal() * 0.3);
62 cats.push(label);
63 }
64 }
65 scatter(&x, &y)
66 .color_by(&cats)
67 .title("Iris Clusters")
68 .x_label("Sepal Length")
69 .y_label("Sepal Width")
70 .size(560.0, 380.0)
71 .save_svg(format!("{dir}/scatter_categories.svg"))?;
72 }
73
74 // ── 3. Line chart ───────────────────────────────────────────────
75 {
76 let x: Vec<f64> = (0..50).map(|i| f64::from(i) * 0.2).collect();
77 let y: Vec<f64> = x.iter().map(|&v| (v * 0.8).sin() * 3.0 + v * 0.5).collect();
78 line(&x, &y)
79 .title("Signal + Trend")
80 .x_label("Time (s)")
81 .y_label("Amplitude")
82 .size(560.0, 380.0)
83 .save_svg(format!("{dir}/line.svg"))?;
84 }
85
86 // ── 4. Multi-line (grammar API) ─────────────────────────────────
87 {
88 let epochs: Vec<f64> = (1..=30).map(f64::from).collect();
89 let train_loss: Vec<f64> = epochs.iter().map(|&e| 2.5 * (-e / 8.0).exp() + 0.1).collect();
90 let val_loss: Vec<f64> = epochs
91 .iter()
92 .map(|&e| 2.5 * (-e / 10.0).exp() + 0.25 + rng.normal() * 0.05)
93 .collect();
94
95 let chart = Chart::new()
96 .layer(
97 Layer::new(MarkType::Line)
98 .with_x(epochs.clone())
99 .with_y(train_loss)
100 .with_label("Train"),
101 )
102 .layer(
103 Layer::new(MarkType::Line)
104 .with_x(epochs)
105 .with_y(val_loss)
106 .with_label("Validation"),
107 )
108 .title("Training Curves")
109 .x_label("Epoch")
110 .y_label("Loss")
111 .size(560.0, 380.0);
112 chart.save_svg_to(format!("{dir}/multi_line.svg"))?;
113 }
114
115 // ── 5. Bar chart ────────────────────────────────────────────────
116 {
117 let cats = ["Rust", "Python", "Go", "TypeScript", "Java"];
118 let vals = [92.0, 87.0, 79.0, 73.0, 68.0];
119 bar(&cats, &vals)
120 .title("Developer Satisfaction")
121 .x_label("Language")
122 .y_label("Score (%)")
123 .size(560.0, 380.0)
124 .save_svg(format!("{dir}/bar.svg"))?;
125 }
126
127 // ── 6. Grouped bar ──────────────────────────────────────────────
128 {
129 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
130 let groups = ["2024", "2024", "2024", "2024", "2025", "2025", "2025", "2025"];
131 let vals = [12.0, 18.0, 22.0, 15.0, 14.0, 20.0, 28.0, 19.0];
132 grouped_bar(&cats, &groups, &vals)
133 .title("Quarterly Revenue")
134 .x_label("Quarter")
135 .y_label("Revenue ($M)")
136 .size(560.0, 380.0)
137 .save_svg(format!("{dir}/grouped_bar.svg"))?;
138 }
139
140 // ── 7. Stacked bar ──────────────────────────────────────────────
141 {
142 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
143 let groups = [
144 "Product", "Product", "Product", "Product",
145 "Service", "Service", "Service", "Service",
146 ];
147 let vals = [10.0, 15.0, 20.0, 18.0, 5.0, 8.0, 12.0, 10.0];
148 stacked_bar(&cats, &groups, &vals)
149 .title("Revenue by Segment")
150 .x_label("Quarter")
151 .y_label("Revenue ($M)")
152 .size(560.0, 380.0)
153 .save_svg(format!("{dir}/stacked_bar.svg"))?;
154 }
155
156 // ── 8. Histogram ────────────────────────────────────────────────
157 {
158 let data: Vec<f64> = (0..500).map(|_| rng.normal() * 1.5 + 10.0).collect();
159 histogram(&data)
160 .bins(25)
161 .title("Feature Distribution")
162 .x_label("Value")
163 .y_label("Count")
164 .size(560.0, 380.0)
165 .save_svg(format!("{dir}/histogram.svg"))?;
166 }
167
168 // ── 9. Area chart ───────────────────────────────────────────────
169 {
170 let x: Vec<f64> = (0..40).map(f64::from).collect();
171 let y: Vec<f64> = x
172 .iter()
173 .map(|&v| (v * 0.2).sin().abs() * 25.0 + 8.0 + rng.normal() * 1.5)
174 .collect();
175 area(&x, &y)
176 .title("Daily Active Users")
177 .x_label("Day")
178 .y_label("Users (k)")
179 .size(560.0, 380.0)
180 .save_svg(format!("{dir}/area.svg"))?;
181 }
182
183 // ── 10. Pie chart ───────────────────────────────────────────────
184 {
185 let labels = ["Chrome", "Firefox", "Safari", "Edge", "Other"];
186 let vals = [64.0, 12.0, 10.0, 8.0, 6.0];
187 pie_labeled(&labels, &vals)
188 .title("Browser Market Share")
189 .size(420.0, 420.0)
190 .save_svg(format!("{dir}/pie.svg"))?;
191 }
192
193 // ── 11. Donut chart ─────────────────────────────────────────────
194 {
195 let labels = ["Pass", "Warn", "Fail"];
196 let vals = [72.0, 18.0, 10.0];
197 pie_labeled(&labels, &vals)
198 .donut(0.5)
199 .title("Test Suite Results")
200 .size(420.0, 420.0)
201 .save_svg(format!("{dir}/donut.svg"))?;
202 }
203
204 // ── 12. Box plot ────────────────────────────────────────────────
205 {
206 let mut cats = Vec::new();
207 let mut vals = Vec::new();
208 for (label, center, spread) in [
209 ("Control", 50.0, 12.0),
210 ("Treatment A", 62.0, 10.0),
211 ("Treatment B", 71.0, 8.0),
212 ] {
213 for _ in 0..40 {
214 vals.push(center + rng.normal() * spread);
215 cats.push(label);
216 }
217 }
218 boxplot(&cats, &vals)
219 .title("Treatment Comparison")
220 .x_label("Group")
221 .y_label("Response")
222 .size(560.0, 380.0)
223 .save_svg(format!("{dir}/boxplot.svg"))?;
224 }
225
226 // ── 13. Heatmap ─────────────────────────────────────────────────
227 {
228 let data = vec![
229 vec![0.92, 0.05, 0.03],
230 vec![0.04, 0.88, 0.08],
231 vec![0.02, 0.06, 0.92],
232 ];
233 heatmap(data)
234 .annotate()
235 .with_row_labels(&["Cat", "Dog", "Bird"])
236 .with_col_labels(&["Cat", "Dog", "Bird"])
237 .title("Confusion Matrix")
238 .x_label("Predicted")
239 .y_label("Actual")
240 .size(420.0, 420.0)
241 .save_svg(format!("{dir}/heatmap.svg"))?;
242 }
243
244 // ── 14. Treemap ─────────────────────────────────────────────────
245 {
246 let labels = ["AWS", "Azure", "GCP", "Alibaba", "Oracle", "IBM"];
247 let vals = [32.0, 23.0, 11.0, 5.0, 3.0, 2.0];
248 treemap(&labels, &vals)
249 .title("Cloud Market Share (%)")
250 .size(560.0, 380.0)
251 .save_svg(format!("{dir}/treemap.svg"))?;
252 }
253
254 // ── 15. LOESS smooth ────────────────────────────────────────────
255 {
256 let x: Vec<f64> = (0..60).map(|i| f64::from(i) * 0.15).collect();
257 let y: Vec<f64> = x
258 .iter()
259 .map(|&v| (v * 0.5).sin() * 3.0 + rng.normal() * 0.8)
260 .collect();
261 let chart = Chart::new()
262 .layer(
263 Layer::new(MarkType::Point)
264 .with_x(x.clone())
265 .with_y(y.clone())
266 .with_label("Raw"),
267 )
268 .layer(
269 Layer::new(MarkType::Line)
270 .with_x(x)
271 .with_y(y)
272 .stat(Stat::Smooth { bandwidth: 0.3 })
273 .with_label("LOESS"),
274 )
275 .title("LOESS Smoothing")
276 .x_label("x")
277 .y_label("y")
278 .size(560.0, 380.0);
279 chart.save_svg_to(format!("{dir}/loess.svg"))?;
280 }
281
282 // ── 16. Annotations ─────────────────────────────────────────────
283 {
284 let x: Vec<f64> = (0..30).map(f64::from).collect();
285 let y: Vec<f64> = x
286 .iter()
287 .map(|&v| v * 1.2 + rng.normal() * 3.0 + 5.0)
288 .collect();
289 let chart = scatter(&x, &y)
290 .title("Annotated Scatter")
291 .x_label("Day")
292 .y_label("Metric")
293 .size(560.0, 380.0)
294 .build()
295 .annotate(Annotation::hline(25.0).with_label("Target"))
296 .annotate(Annotation::band(15.0, 25.0));
297 chart.save_svg_to(format!("{dir}/annotations.svg"))?;
298 }
299
300 // ── 17. Dark theme ──────────────────────────────────────────────
301 {
302 let epochs: Vec<f64> = (1..=25).map(f64::from).collect();
303 let loss: Vec<f64> = epochs.iter().map(|&e| 3.0 * (-e / 6.0).exp() + 0.15).collect();
304 let acc: Vec<f64> = epochs
305 .iter()
306 .map(|&e| 0.95 * (1.0 - (-e / 5.0).exp()))
307 .collect();
308
309 let chart = Chart::new()
310 .layer(
311 Layer::new(MarkType::Line)
312 .with_x(epochs.clone())
313 .with_y(loss)
314 .with_label("Loss"),
315 )
316 .layer(
317 Layer::new(MarkType::Line)
318 .with_x(epochs)
319 .with_y(acc)
320 .with_label("Accuracy"),
321 )
322 .title("Model Training")
323 .x_label("Epoch")
324 .y_label("Value")
325 .theme(NewTheme::dark())
326 .size(560.0, 380.0);
327 chart.save_svg_to(format!("{dir}/dark_theme.svg"))?;
328 }
329
330 // ── 18. Horizontal bar ──────────────────────────────────────────
331 {
332 let chart = Chart::new()
333 .layer(
334 Layer::new(MarkType::Bar)
335 .with_x(vec![0.0, 1.0, 2.0, 3.0, 4.0])
336 .with_y(vec![92.0, 87.0, 79.0, 73.0, 68.0])
337 .with_categories(vec![
338 "Rust".into(),
339 "Python".into(),
340 "Go".into(),
341 "TypeScript".into(),
342 "Java".into(),
343 ]),
344 )
345 .coord(CoordSystem::Flipped)
346 .title("Satisfaction Scores")
347 .x_label("Score (%)")
348 .y_label("Language")
349 .size(560.0, 380.0);
350 chart.save_svg_to(format!("{dir}/horizontal_bar.svg"))?;
351 }
352
353 println!("Generated 18 SVGs in {dir}/");
354 Ok(())
355}Sourcepub fn theme(self, theme: NewTheme) -> Self
pub fn theme(self, theme: NewTheme) -> Self
Set theme.
Examples found in repository?
examples/basic_treemap.rs (line 25)
4fn main() -> esoc_chart::error::Result<()> {
5 let labels = vec![
6 "Electronics",
7 "Clothing",
8 "Food & Beverage",
9 "Home & Garden",
10 "Books",
11 "Sports",
12 "Toys",
13 "Automotive",
14 ];
15 let values = vec![320.0, 180.0, 150.0, 120.0, 80.0, 60.0, 45.0, 30.0];
16
17 let mut theme = esoc_chart::new_theme::NewTheme::light();
18 theme.base_font_size = 13.0;
19 theme.title_font_size = 18.0;
20 theme.legend_font_size = 11.0;
21 theme.font_family = "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif".into();
22
23 let svg = esoc_chart::express::treemap(&labels, &values)
24 .title("Sales by Category ($M)")
25 .theme(theme)
26 .size(900.0, 600.0)
27 .to_svg()?;
28
29 std::fs::write("treemap.svg", &svg)?;
30 println!("Wrote treemap.svg ({} bytes)", svg.len());
31 Ok(())
32}Sourcepub fn size(self, width: f32, height: f32) -> Self
pub fn size(self, width: f32, height: f32) -> Self
Set dimensions.
Examples found in repository?
examples/basic_treemap.rs (line 26)
4fn main() -> esoc_chart::error::Result<()> {
5 let labels = vec![
6 "Electronics",
7 "Clothing",
8 "Food & Beverage",
9 "Home & Garden",
10 "Books",
11 "Sports",
12 "Toys",
13 "Automotive",
14 ];
15 let values = vec![320.0, 180.0, 150.0, 120.0, 80.0, 60.0, 45.0, 30.0];
16
17 let mut theme = esoc_chart::new_theme::NewTheme::light();
18 theme.base_font_size = 13.0;
19 theme.title_font_size = 18.0;
20 theme.legend_font_size = 11.0;
21 theme.font_family = "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif".into();
22
23 let svg = esoc_chart::express::treemap(&labels, &values)
24 .title("Sales by Category ($M)")
25 .theme(theme)
26 .size(900.0, 600.0)
27 .to_svg()?;
28
29 std::fs::write("treemap.svg", &svg)?;
30 println!("Wrote treemap.svg ({} bytes)", svg.len());
31 Ok(())
32}More examples
examples/readme_charts.rs (line 250)
15fn main() -> esoc_chart::error::Result<()> {
16 // Simple deterministic RNG
17 struct Rng(u64);
18 impl Rng {
19 fn uniform(&mut self) -> f64 {
20 self.0 = self
21 .0
22 .wrapping_mul(6_364_136_223_846_793_005)
23 .wrapping_add(1);
24 (self.0 >> 11) as f64 / (1u64 << 53) as f64
25 }
26 fn normal(&mut self) -> f64 {
27 let u1 = self.uniform().max(1e-15);
28 let u2 = self.uniform();
29 (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos()
30 }
31 }
32 let mut rng = Rng(42);
33
34 let dir = "crates/esoc-chart/images";
35 std::fs::create_dir_all(dir).unwrap();
36
37 // ── 1. Scatter ──────────────────────────────────────────────────
38 {
39 let n = 80;
40 let x: Vec<f64> = (0..n).map(|_| rng.uniform() * 10.0).collect();
41 let y: Vec<f64> = x
42 .iter()
43 .map(|&xi| 0.4 * xi * xi - 2.0 * xi + 3.0 + rng.normal() * 2.0)
44 .collect();
45 scatter(&x, &y)
46 .title("Quadratic Trend")
47 .x_label("x")
48 .y_label("y")
49 .size(560.0, 380.0)
50 .save_svg(format!("{dir}/scatter.svg"))?;
51 }
52
53 // ── 2. Scatter with categories ──────────────────────────────────
54 {
55 let mut x = Vec::new();
56 let mut y = Vec::new();
57 let mut cats = Vec::new();
58 for (label, cx, cy) in [("Setosa", 5.0, 3.4), ("Versicolor", 5.9, 2.8), ("Virginica", 6.6, 3.0)] {
59 for _ in 0..40 {
60 x.push(cx + rng.normal() * 0.4);
61 y.push(cy + rng.normal() * 0.3);
62 cats.push(label);
63 }
64 }
65 scatter(&x, &y)
66 .color_by(&cats)
67 .title("Iris Clusters")
68 .x_label("Sepal Length")
69 .y_label("Sepal Width")
70 .size(560.0, 380.0)
71 .save_svg(format!("{dir}/scatter_categories.svg"))?;
72 }
73
74 // ── 3. Line chart ───────────────────────────────────────────────
75 {
76 let x: Vec<f64> = (0..50).map(|i| f64::from(i) * 0.2).collect();
77 let y: Vec<f64> = x.iter().map(|&v| (v * 0.8).sin() * 3.0 + v * 0.5).collect();
78 line(&x, &y)
79 .title("Signal + Trend")
80 .x_label("Time (s)")
81 .y_label("Amplitude")
82 .size(560.0, 380.0)
83 .save_svg(format!("{dir}/line.svg"))?;
84 }
85
86 // ── 4. Multi-line (grammar API) ─────────────────────────────────
87 {
88 let epochs: Vec<f64> = (1..=30).map(f64::from).collect();
89 let train_loss: Vec<f64> = epochs.iter().map(|&e| 2.5 * (-e / 8.0).exp() + 0.1).collect();
90 let val_loss: Vec<f64> = epochs
91 .iter()
92 .map(|&e| 2.5 * (-e / 10.0).exp() + 0.25 + rng.normal() * 0.05)
93 .collect();
94
95 let chart = Chart::new()
96 .layer(
97 Layer::new(MarkType::Line)
98 .with_x(epochs.clone())
99 .with_y(train_loss)
100 .with_label("Train"),
101 )
102 .layer(
103 Layer::new(MarkType::Line)
104 .with_x(epochs)
105 .with_y(val_loss)
106 .with_label("Validation"),
107 )
108 .title("Training Curves")
109 .x_label("Epoch")
110 .y_label("Loss")
111 .size(560.0, 380.0);
112 chart.save_svg_to(format!("{dir}/multi_line.svg"))?;
113 }
114
115 // ── 5. Bar chart ────────────────────────────────────────────────
116 {
117 let cats = ["Rust", "Python", "Go", "TypeScript", "Java"];
118 let vals = [92.0, 87.0, 79.0, 73.0, 68.0];
119 bar(&cats, &vals)
120 .title("Developer Satisfaction")
121 .x_label("Language")
122 .y_label("Score (%)")
123 .size(560.0, 380.0)
124 .save_svg(format!("{dir}/bar.svg"))?;
125 }
126
127 // ── 6. Grouped bar ──────────────────────────────────────────────
128 {
129 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
130 let groups = ["2024", "2024", "2024", "2024", "2025", "2025", "2025", "2025"];
131 let vals = [12.0, 18.0, 22.0, 15.0, 14.0, 20.0, 28.0, 19.0];
132 grouped_bar(&cats, &groups, &vals)
133 .title("Quarterly Revenue")
134 .x_label("Quarter")
135 .y_label("Revenue ($M)")
136 .size(560.0, 380.0)
137 .save_svg(format!("{dir}/grouped_bar.svg"))?;
138 }
139
140 // ── 7. Stacked bar ──────────────────────────────────────────────
141 {
142 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
143 let groups = [
144 "Product", "Product", "Product", "Product",
145 "Service", "Service", "Service", "Service",
146 ];
147 let vals = [10.0, 15.0, 20.0, 18.0, 5.0, 8.0, 12.0, 10.0];
148 stacked_bar(&cats, &groups, &vals)
149 .title("Revenue by Segment")
150 .x_label("Quarter")
151 .y_label("Revenue ($M)")
152 .size(560.0, 380.0)
153 .save_svg(format!("{dir}/stacked_bar.svg"))?;
154 }
155
156 // ── 8. Histogram ────────────────────────────────────────────────
157 {
158 let data: Vec<f64> = (0..500).map(|_| rng.normal() * 1.5 + 10.0).collect();
159 histogram(&data)
160 .bins(25)
161 .title("Feature Distribution")
162 .x_label("Value")
163 .y_label("Count")
164 .size(560.0, 380.0)
165 .save_svg(format!("{dir}/histogram.svg"))?;
166 }
167
168 // ── 9. Area chart ───────────────────────────────────────────────
169 {
170 let x: Vec<f64> = (0..40).map(f64::from).collect();
171 let y: Vec<f64> = x
172 .iter()
173 .map(|&v| (v * 0.2).sin().abs() * 25.0 + 8.0 + rng.normal() * 1.5)
174 .collect();
175 area(&x, &y)
176 .title("Daily Active Users")
177 .x_label("Day")
178 .y_label("Users (k)")
179 .size(560.0, 380.0)
180 .save_svg(format!("{dir}/area.svg"))?;
181 }
182
183 // ── 10. Pie chart ───────────────────────────────────────────────
184 {
185 let labels = ["Chrome", "Firefox", "Safari", "Edge", "Other"];
186 let vals = [64.0, 12.0, 10.0, 8.0, 6.0];
187 pie_labeled(&labels, &vals)
188 .title("Browser Market Share")
189 .size(420.0, 420.0)
190 .save_svg(format!("{dir}/pie.svg"))?;
191 }
192
193 // ── 11. Donut chart ─────────────────────────────────────────────
194 {
195 let labels = ["Pass", "Warn", "Fail"];
196 let vals = [72.0, 18.0, 10.0];
197 pie_labeled(&labels, &vals)
198 .donut(0.5)
199 .title("Test Suite Results")
200 .size(420.0, 420.0)
201 .save_svg(format!("{dir}/donut.svg"))?;
202 }
203
204 // ── 12. Box plot ────────────────────────────────────────────────
205 {
206 let mut cats = Vec::new();
207 let mut vals = Vec::new();
208 for (label, center, spread) in [
209 ("Control", 50.0, 12.0),
210 ("Treatment A", 62.0, 10.0),
211 ("Treatment B", 71.0, 8.0),
212 ] {
213 for _ in 0..40 {
214 vals.push(center + rng.normal() * spread);
215 cats.push(label);
216 }
217 }
218 boxplot(&cats, &vals)
219 .title("Treatment Comparison")
220 .x_label("Group")
221 .y_label("Response")
222 .size(560.0, 380.0)
223 .save_svg(format!("{dir}/boxplot.svg"))?;
224 }
225
226 // ── 13. Heatmap ─────────────────────────────────────────────────
227 {
228 let data = vec![
229 vec![0.92, 0.05, 0.03],
230 vec![0.04, 0.88, 0.08],
231 vec![0.02, 0.06, 0.92],
232 ];
233 heatmap(data)
234 .annotate()
235 .with_row_labels(&["Cat", "Dog", "Bird"])
236 .with_col_labels(&["Cat", "Dog", "Bird"])
237 .title("Confusion Matrix")
238 .x_label("Predicted")
239 .y_label("Actual")
240 .size(420.0, 420.0)
241 .save_svg(format!("{dir}/heatmap.svg"))?;
242 }
243
244 // ── 14. Treemap ─────────────────────────────────────────────────
245 {
246 let labels = ["AWS", "Azure", "GCP", "Alibaba", "Oracle", "IBM"];
247 let vals = [32.0, 23.0, 11.0, 5.0, 3.0, 2.0];
248 treemap(&labels, &vals)
249 .title("Cloud Market Share (%)")
250 .size(560.0, 380.0)
251 .save_svg(format!("{dir}/treemap.svg"))?;
252 }
253
254 // ── 15. LOESS smooth ────────────────────────────────────────────
255 {
256 let x: Vec<f64> = (0..60).map(|i| f64::from(i) * 0.15).collect();
257 let y: Vec<f64> = x
258 .iter()
259 .map(|&v| (v * 0.5).sin() * 3.0 + rng.normal() * 0.8)
260 .collect();
261 let chart = Chart::new()
262 .layer(
263 Layer::new(MarkType::Point)
264 .with_x(x.clone())
265 .with_y(y.clone())
266 .with_label("Raw"),
267 )
268 .layer(
269 Layer::new(MarkType::Line)
270 .with_x(x)
271 .with_y(y)
272 .stat(Stat::Smooth { bandwidth: 0.3 })
273 .with_label("LOESS"),
274 )
275 .title("LOESS Smoothing")
276 .x_label("x")
277 .y_label("y")
278 .size(560.0, 380.0);
279 chart.save_svg_to(format!("{dir}/loess.svg"))?;
280 }
281
282 // ── 16. Annotations ─────────────────────────────────────────────
283 {
284 let x: Vec<f64> = (0..30).map(f64::from).collect();
285 let y: Vec<f64> = x
286 .iter()
287 .map(|&v| v * 1.2 + rng.normal() * 3.0 + 5.0)
288 .collect();
289 let chart = scatter(&x, &y)
290 .title("Annotated Scatter")
291 .x_label("Day")
292 .y_label("Metric")
293 .size(560.0, 380.0)
294 .build()
295 .annotate(Annotation::hline(25.0).with_label("Target"))
296 .annotate(Annotation::band(15.0, 25.0));
297 chart.save_svg_to(format!("{dir}/annotations.svg"))?;
298 }
299
300 // ── 17. Dark theme ──────────────────────────────────────────────
301 {
302 let epochs: Vec<f64> = (1..=25).map(f64::from).collect();
303 let loss: Vec<f64> = epochs.iter().map(|&e| 3.0 * (-e / 6.0).exp() + 0.15).collect();
304 let acc: Vec<f64> = epochs
305 .iter()
306 .map(|&e| 0.95 * (1.0 - (-e / 5.0).exp()))
307 .collect();
308
309 let chart = Chart::new()
310 .layer(
311 Layer::new(MarkType::Line)
312 .with_x(epochs.clone())
313 .with_y(loss)
314 .with_label("Loss"),
315 )
316 .layer(
317 Layer::new(MarkType::Line)
318 .with_x(epochs)
319 .with_y(acc)
320 .with_label("Accuracy"),
321 )
322 .title("Model Training")
323 .x_label("Epoch")
324 .y_label("Value")
325 .theme(NewTheme::dark())
326 .size(560.0, 380.0);
327 chart.save_svg_to(format!("{dir}/dark_theme.svg"))?;
328 }
329
330 // ── 18. Horizontal bar ──────────────────────────────────────────
331 {
332 let chart = Chart::new()
333 .layer(
334 Layer::new(MarkType::Bar)
335 .with_x(vec![0.0, 1.0, 2.0, 3.0, 4.0])
336 .with_y(vec![92.0, 87.0, 79.0, 73.0, 68.0])
337 .with_categories(vec![
338 "Rust".into(),
339 "Python".into(),
340 "Go".into(),
341 "TypeScript".into(),
342 "Java".into(),
343 ]),
344 )
345 .coord(CoordSystem::Flipped)
346 .title("Satisfaction Scores")
347 .x_label("Score (%)")
348 .y_label("Language")
349 .size(560.0, 380.0);
350 chart.save_svg_to(format!("{dir}/horizontal_bar.svg"))?;
351 }
352
353 println!("Generated 18 SVGs in {dir}/");
354 Ok(())
355}Sourcepub fn to_svg(self) -> Result<String>
pub fn to_svg(self) -> Result<String>
Build and render to SVG.
Examples found in repository?
examples/basic_treemap.rs (line 27)
4fn main() -> esoc_chart::error::Result<()> {
5 let labels = vec![
6 "Electronics",
7 "Clothing",
8 "Food & Beverage",
9 "Home & Garden",
10 "Books",
11 "Sports",
12 "Toys",
13 "Automotive",
14 ];
15 let values = vec![320.0, 180.0, 150.0, 120.0, 80.0, 60.0, 45.0, 30.0];
16
17 let mut theme = esoc_chart::new_theme::NewTheme::light();
18 theme.base_font_size = 13.0;
19 theme.title_font_size = 18.0;
20 theme.legend_font_size = 11.0;
21 theme.font_family = "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif".into();
22
23 let svg = esoc_chart::express::treemap(&labels, &values)
24 .title("Sales by Category ($M)")
25 .theme(theme)
26 .size(900.0, 600.0)
27 .to_svg()?;
28
29 std::fs::write("treemap.svg", &svg)?;
30 println!("Wrote treemap.svg ({} bytes)", svg.len());
31 Ok(())
32}Sourcepub fn save_svg(self, path: impl AsRef<Path>) -> Result<()>
pub fn save_svg(self, path: impl AsRef<Path>) -> Result<()>
Build and save as SVG file.
Examples found in repository?
examples/readme_charts.rs (line 251)
15fn main() -> esoc_chart::error::Result<()> {
16 // Simple deterministic RNG
17 struct Rng(u64);
18 impl Rng {
19 fn uniform(&mut self) -> f64 {
20 self.0 = self
21 .0
22 .wrapping_mul(6_364_136_223_846_793_005)
23 .wrapping_add(1);
24 (self.0 >> 11) as f64 / (1u64 << 53) as f64
25 }
26 fn normal(&mut self) -> f64 {
27 let u1 = self.uniform().max(1e-15);
28 let u2 = self.uniform();
29 (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos()
30 }
31 }
32 let mut rng = Rng(42);
33
34 let dir = "crates/esoc-chart/images";
35 std::fs::create_dir_all(dir).unwrap();
36
37 // ── 1. Scatter ──────────────────────────────────────────────────
38 {
39 let n = 80;
40 let x: Vec<f64> = (0..n).map(|_| rng.uniform() * 10.0).collect();
41 let y: Vec<f64> = x
42 .iter()
43 .map(|&xi| 0.4 * xi * xi - 2.0 * xi + 3.0 + rng.normal() * 2.0)
44 .collect();
45 scatter(&x, &y)
46 .title("Quadratic Trend")
47 .x_label("x")
48 .y_label("y")
49 .size(560.0, 380.0)
50 .save_svg(format!("{dir}/scatter.svg"))?;
51 }
52
53 // ── 2. Scatter with categories ──────────────────────────────────
54 {
55 let mut x = Vec::new();
56 let mut y = Vec::new();
57 let mut cats = Vec::new();
58 for (label, cx, cy) in [("Setosa", 5.0, 3.4), ("Versicolor", 5.9, 2.8), ("Virginica", 6.6, 3.0)] {
59 for _ in 0..40 {
60 x.push(cx + rng.normal() * 0.4);
61 y.push(cy + rng.normal() * 0.3);
62 cats.push(label);
63 }
64 }
65 scatter(&x, &y)
66 .color_by(&cats)
67 .title("Iris Clusters")
68 .x_label("Sepal Length")
69 .y_label("Sepal Width")
70 .size(560.0, 380.0)
71 .save_svg(format!("{dir}/scatter_categories.svg"))?;
72 }
73
74 // ── 3. Line chart ───────────────────────────────────────────────
75 {
76 let x: Vec<f64> = (0..50).map(|i| f64::from(i) * 0.2).collect();
77 let y: Vec<f64> = x.iter().map(|&v| (v * 0.8).sin() * 3.0 + v * 0.5).collect();
78 line(&x, &y)
79 .title("Signal + Trend")
80 .x_label("Time (s)")
81 .y_label("Amplitude")
82 .size(560.0, 380.0)
83 .save_svg(format!("{dir}/line.svg"))?;
84 }
85
86 // ── 4. Multi-line (grammar API) ─────────────────────────────────
87 {
88 let epochs: Vec<f64> = (1..=30).map(f64::from).collect();
89 let train_loss: Vec<f64> = epochs.iter().map(|&e| 2.5 * (-e / 8.0).exp() + 0.1).collect();
90 let val_loss: Vec<f64> = epochs
91 .iter()
92 .map(|&e| 2.5 * (-e / 10.0).exp() + 0.25 + rng.normal() * 0.05)
93 .collect();
94
95 let chart = Chart::new()
96 .layer(
97 Layer::new(MarkType::Line)
98 .with_x(epochs.clone())
99 .with_y(train_loss)
100 .with_label("Train"),
101 )
102 .layer(
103 Layer::new(MarkType::Line)
104 .with_x(epochs)
105 .with_y(val_loss)
106 .with_label("Validation"),
107 )
108 .title("Training Curves")
109 .x_label("Epoch")
110 .y_label("Loss")
111 .size(560.0, 380.0);
112 chart.save_svg_to(format!("{dir}/multi_line.svg"))?;
113 }
114
115 // ── 5. Bar chart ────────────────────────────────────────────────
116 {
117 let cats = ["Rust", "Python", "Go", "TypeScript", "Java"];
118 let vals = [92.0, 87.0, 79.0, 73.0, 68.0];
119 bar(&cats, &vals)
120 .title("Developer Satisfaction")
121 .x_label("Language")
122 .y_label("Score (%)")
123 .size(560.0, 380.0)
124 .save_svg(format!("{dir}/bar.svg"))?;
125 }
126
127 // ── 6. Grouped bar ──────────────────────────────────────────────
128 {
129 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
130 let groups = ["2024", "2024", "2024", "2024", "2025", "2025", "2025", "2025"];
131 let vals = [12.0, 18.0, 22.0, 15.0, 14.0, 20.0, 28.0, 19.0];
132 grouped_bar(&cats, &groups, &vals)
133 .title("Quarterly Revenue")
134 .x_label("Quarter")
135 .y_label("Revenue ($M)")
136 .size(560.0, 380.0)
137 .save_svg(format!("{dir}/grouped_bar.svg"))?;
138 }
139
140 // ── 7. Stacked bar ──────────────────────────────────────────────
141 {
142 let cats = ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"];
143 let groups = [
144 "Product", "Product", "Product", "Product",
145 "Service", "Service", "Service", "Service",
146 ];
147 let vals = [10.0, 15.0, 20.0, 18.0, 5.0, 8.0, 12.0, 10.0];
148 stacked_bar(&cats, &groups, &vals)
149 .title("Revenue by Segment")
150 .x_label("Quarter")
151 .y_label("Revenue ($M)")
152 .size(560.0, 380.0)
153 .save_svg(format!("{dir}/stacked_bar.svg"))?;
154 }
155
156 // ── 8. Histogram ────────────────────────────────────────────────
157 {
158 let data: Vec<f64> = (0..500).map(|_| rng.normal() * 1.5 + 10.0).collect();
159 histogram(&data)
160 .bins(25)
161 .title("Feature Distribution")
162 .x_label("Value")
163 .y_label("Count")
164 .size(560.0, 380.0)
165 .save_svg(format!("{dir}/histogram.svg"))?;
166 }
167
168 // ── 9. Area chart ───────────────────────────────────────────────
169 {
170 let x: Vec<f64> = (0..40).map(f64::from).collect();
171 let y: Vec<f64> = x
172 .iter()
173 .map(|&v| (v * 0.2).sin().abs() * 25.0 + 8.0 + rng.normal() * 1.5)
174 .collect();
175 area(&x, &y)
176 .title("Daily Active Users")
177 .x_label("Day")
178 .y_label("Users (k)")
179 .size(560.0, 380.0)
180 .save_svg(format!("{dir}/area.svg"))?;
181 }
182
183 // ── 10. Pie chart ───────────────────────────────────────────────
184 {
185 let labels = ["Chrome", "Firefox", "Safari", "Edge", "Other"];
186 let vals = [64.0, 12.0, 10.0, 8.0, 6.0];
187 pie_labeled(&labels, &vals)
188 .title("Browser Market Share")
189 .size(420.0, 420.0)
190 .save_svg(format!("{dir}/pie.svg"))?;
191 }
192
193 // ── 11. Donut chart ─────────────────────────────────────────────
194 {
195 let labels = ["Pass", "Warn", "Fail"];
196 let vals = [72.0, 18.0, 10.0];
197 pie_labeled(&labels, &vals)
198 .donut(0.5)
199 .title("Test Suite Results")
200 .size(420.0, 420.0)
201 .save_svg(format!("{dir}/donut.svg"))?;
202 }
203
204 // ── 12. Box plot ────────────────────────────────────────────────
205 {
206 let mut cats = Vec::new();
207 let mut vals = Vec::new();
208 for (label, center, spread) in [
209 ("Control", 50.0, 12.0),
210 ("Treatment A", 62.0, 10.0),
211 ("Treatment B", 71.0, 8.0),
212 ] {
213 for _ in 0..40 {
214 vals.push(center + rng.normal() * spread);
215 cats.push(label);
216 }
217 }
218 boxplot(&cats, &vals)
219 .title("Treatment Comparison")
220 .x_label("Group")
221 .y_label("Response")
222 .size(560.0, 380.0)
223 .save_svg(format!("{dir}/boxplot.svg"))?;
224 }
225
226 // ── 13. Heatmap ─────────────────────────────────────────────────
227 {
228 let data = vec![
229 vec![0.92, 0.05, 0.03],
230 vec![0.04, 0.88, 0.08],
231 vec![0.02, 0.06, 0.92],
232 ];
233 heatmap(data)
234 .annotate()
235 .with_row_labels(&["Cat", "Dog", "Bird"])
236 .with_col_labels(&["Cat", "Dog", "Bird"])
237 .title("Confusion Matrix")
238 .x_label("Predicted")
239 .y_label("Actual")
240 .size(420.0, 420.0)
241 .save_svg(format!("{dir}/heatmap.svg"))?;
242 }
243
244 // ── 14. Treemap ─────────────────────────────────────────────────
245 {
246 let labels = ["AWS", "Azure", "GCP", "Alibaba", "Oracle", "IBM"];
247 let vals = [32.0, 23.0, 11.0, 5.0, 3.0, 2.0];
248 treemap(&labels, &vals)
249 .title("Cloud Market Share (%)")
250 .size(560.0, 380.0)
251 .save_svg(format!("{dir}/treemap.svg"))?;
252 }
253
254 // ── 15. LOESS smooth ────────────────────────────────────────────
255 {
256 let x: Vec<f64> = (0..60).map(|i| f64::from(i) * 0.15).collect();
257 let y: Vec<f64> = x
258 .iter()
259 .map(|&v| (v * 0.5).sin() * 3.0 + rng.normal() * 0.8)
260 .collect();
261 let chart = Chart::new()
262 .layer(
263 Layer::new(MarkType::Point)
264 .with_x(x.clone())
265 .with_y(y.clone())
266 .with_label("Raw"),
267 )
268 .layer(
269 Layer::new(MarkType::Line)
270 .with_x(x)
271 .with_y(y)
272 .stat(Stat::Smooth { bandwidth: 0.3 })
273 .with_label("LOESS"),
274 )
275 .title("LOESS Smoothing")
276 .x_label("x")
277 .y_label("y")
278 .size(560.0, 380.0);
279 chart.save_svg_to(format!("{dir}/loess.svg"))?;
280 }
281
282 // ── 16. Annotations ─────────────────────────────────────────────
283 {
284 let x: Vec<f64> = (0..30).map(f64::from).collect();
285 let y: Vec<f64> = x
286 .iter()
287 .map(|&v| v * 1.2 + rng.normal() * 3.0 + 5.0)
288 .collect();
289 let chart = scatter(&x, &y)
290 .title("Annotated Scatter")
291 .x_label("Day")
292 .y_label("Metric")
293 .size(560.0, 380.0)
294 .build()
295 .annotate(Annotation::hline(25.0).with_label("Target"))
296 .annotate(Annotation::band(15.0, 25.0));
297 chart.save_svg_to(format!("{dir}/annotations.svg"))?;
298 }
299
300 // ── 17. Dark theme ──────────────────────────────────────────────
301 {
302 let epochs: Vec<f64> = (1..=25).map(f64::from).collect();
303 let loss: Vec<f64> = epochs.iter().map(|&e| 3.0 * (-e / 6.0).exp() + 0.15).collect();
304 let acc: Vec<f64> = epochs
305 .iter()
306 .map(|&e| 0.95 * (1.0 - (-e / 5.0).exp()))
307 .collect();
308
309 let chart = Chart::new()
310 .layer(
311 Layer::new(MarkType::Line)
312 .with_x(epochs.clone())
313 .with_y(loss)
314 .with_label("Loss"),
315 )
316 .layer(
317 Layer::new(MarkType::Line)
318 .with_x(epochs)
319 .with_y(acc)
320 .with_label("Accuracy"),
321 )
322 .title("Model Training")
323 .x_label("Epoch")
324 .y_label("Value")
325 .theme(NewTheme::dark())
326 .size(560.0, 380.0);
327 chart.save_svg_to(format!("{dir}/dark_theme.svg"))?;
328 }
329
330 // ── 18. Horizontal bar ──────────────────────────────────────────
331 {
332 let chart = Chart::new()
333 .layer(
334 Layer::new(MarkType::Bar)
335 .with_x(vec![0.0, 1.0, 2.0, 3.0, 4.0])
336 .with_y(vec![92.0, 87.0, 79.0, 73.0, 68.0])
337 .with_categories(vec![
338 "Rust".into(),
339 "Python".into(),
340 "Go".into(),
341 "TypeScript".into(),
342 "Java".into(),
343 ]),
344 )
345 .coord(CoordSystem::Flipped)
346 .title("Satisfaction Scores")
347 .x_label("Score (%)")
348 .y_label("Language")
349 .size(560.0, 380.0);
350 chart.save_svg_to(format!("{dir}/horizontal_bar.svg"))?;
351 }
352
353 println!("Generated 18 SVGs in {dir}/");
354 Ok(())
355}Auto Trait Implementations§
impl Freeze for TreemapBuilder
impl RefUnwindSafe for TreemapBuilder
impl Send for TreemapBuilder
impl Sync for TreemapBuilder
impl Unpin for TreemapBuilder
impl UnsafeUnpin for TreemapBuilder
impl UnwindSafe for TreemapBuilder
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
Mutably borrows from an owned value. Read more