1use esoc_chart::express::{
5 area, bar, boxplot, grouped_bar, heatmap, histogram, line, pie_labeled, scatter, stacked_bar,
6 treemap,
7};
8use esoc_chart::grammar::annotation::Annotation;
9use esoc_chart::grammar::chart::Chart;
10use esoc_chart::grammar::coord::CoordSystem;
11use esoc_chart::grammar::layer::{Layer, MarkType};
12use esoc_chart::grammar::stat::Stat;
13use esoc_chart::new_theme::NewTheme;
14
15fn main() -> esoc_chart::error::Result<()> {
16 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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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}