1use std::fmt::Write;
5
6use esoc_chart::express::{bar, heatmap, histogram, line, pie_labeled, scatter};
7use esoc_chart::new_theme::NewTheme;
8
9fn try_chart(
10 name: &str,
11 f: impl FnOnce() -> esoc_chart::error::Result<String>,
12) -> Option<(String, String)> {
13 match f() {
14 Ok(svg) => Some((name.to_string(), svg)),
15 Err(e) => {
16 eprintln!("FAIL [{name}]: {e}");
17 None
18 }
19 }
20}
21
22fn main() {
23 let mut sections: Vec<(String, String)> = Vec::new();
24
25 if let Some(s) = try_chart("Single Point", || {
27 scatter(&[5.0], &[10.0])
28 .title("Single Point")
29 .size(400.0, 300.0)
30 .to_svg()
31 }) {
32 sections.push(s);
33 }
34
35 if let Some(s) = try_chart("Two Points", || {
37 scatter(&[0.0, 100.0], &[0.0, 100.0])
38 .title("Two Points")
39 .size(400.0, 300.0)
40 .to_svg()
41 }) {
42 sections.push(s);
43 }
44
45 if let Some(s) = try_chart("Long Labels", || {
47 let cats = vec![
48 "This is an extremely long category label",
49 "Another very very long label here",
50 "Short",
51 "Medium length label",
52 "Yet another verbose category name",
53 ];
54 bar(&cats, &[10.0, 25.0, 15.0, 30.0, 20.0])
55 .title("Long Category Labels")
56 .x_label("Categories")
57 .y_label("Value")
58 .size(600.0, 400.0)
59 .to_svg()
60 }) {
61 sections.push(s);
62 }
63
64 if let Some(s) = try_chart("Large Numbers", || {
66 let x: Vec<f64> = (0..10).map(|i| f64::from(i) * 1_000_000.0).collect();
67 let y: Vec<f64> = (0..10).map(|i| f64::from(i).powi(2) * 500_000.0).collect();
68 scatter(&x, &y)
69 .title("Large Numbers (Millions)")
70 .x_label("Revenue ($)")
71 .y_label("Profit ($)")
72 .size(600.0, 350.0)
73 .to_svg()
74 }) {
75 sections.push(s);
76 }
77
78 if let Some(s) = try_chart("Small Numbers", || {
80 let x: Vec<f64> = (0..10).map(|i| f64::from(i) * 0.0001).collect();
81 let y: Vec<f64> = (0..10).map(|i| f64::from(i) * 0.00005).collect();
82 scatter(&x, &y)
83 .title("Small Numbers")
84 .size(600.0, 350.0)
85 .to_svg()
86 }) {
87 sections.push(s);
88 }
89
90 if let Some(s) = try_chart("Negative Bars", || {
92 bar(&["A", "B", "C", "D"], &[-10.0, -25.0, -5.0, -30.0])
93 .title("All-Negative Bars")
94 .y_label("Loss")
95 .size(500.0, 350.0)
96 .to_svg()
97 }) {
98 sections.push(s);
99 }
100
101 if let Some(s) = try_chart("Mixed Bars", || {
103 bar(&["Q1", "Q2", "Q3", "Q4"], &[15.0, -10.0, 25.0, -5.0])
104 .title("Mixed +/- Bars")
105 .y_label("P&L")
106 .size(500.0, 350.0)
107 .to_svg()
108 }) {
109 sections.push(s);
110 }
111
112 if let Some(s) = try_chart("Dense Scatter", || {
114 struct Rng(u64);
115 impl Rng {
116 fn next(&mut self) -> f64 {
117 self.0 = self
118 .0
119 .wrapping_mul(6_364_136_223_846_793_005)
120 .wrapping_add(1);
121 (self.0 >> 11) as f64 / (1u64 << 53) as f64
122 }
123 }
124 let mut rng = Rng(123);
125 let x: Vec<f64> = (0..1000).map(|_| rng.next() * 100.0).collect();
126 let y: Vec<f64> = (0..1000).map(|_| rng.next() * 100.0).collect();
127 scatter(&x, &y)
128 .title("Dense Scatter (n=1000)")
129 .size(500.0, 400.0)
130 .to_svg()
131 }) {
132 sections.push(s);
133 }
134
135 if let Some(s) = try_chart("Single Bar", || {
137 bar(&["Only One"], &[42.0])
138 .title("Single Bar")
139 .size(500.0, 350.0)
140 .to_svg()
141 }) {
142 sections.push(s);
143 }
144
145 if let Some(s) = try_chart("Many Categories", || {
147 let cats: Vec<String> = (0..20).map(|i| format!("Cat_{i}")).collect();
148 let cats_ref: Vec<&str> = cats.iter().map(|s| s.as_str()).collect();
149 let vals: Vec<f64> = (0..20).map(|i| (f64::from(i) * 7.0) % 50.0 + 5.0).collect();
150 bar(&cats_ref, &vals)
151 .title("Many Categories (20)")
152 .size(700.0, 400.0)
153 .to_svg()
154 }) {
155 sections.push(s);
156 }
157
158 if let Some(s) = try_chart("Narrow Chart", || {
160 let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
161 let y = vec![10.0, 20.0, 15.0, 25.0, 30.0];
162 line(&x, &y)
163 .title("Narrow Chart")
164 .x_label("X")
165 .y_label("Y")
166 .size(300.0, 400.0)
167 .to_svg()
168 }) {
169 sections.push(s);
170 }
171
172 if let Some(s) = try_chart("Wide Chart", || {
174 let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
175 let y = vec![10.0, 20.0, 15.0, 25.0, 30.0];
176 line(&x, &y)
177 .title("Wide Chart")
178 .x_label("X")
179 .y_label("Y")
180 .size(1000.0, 250.0)
181 .to_svg()
182 }) {
183 sections.push(s);
184 }
185
186 if let Some(s) = try_chart("Few Bins", || {
188 histogram(&[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0])
189 .bins(3)
190 .title("Histogram (3 bins)")
191 .size(400.0, 300.0)
192 .to_svg()
193 }) {
194 sections.push(s);
195 }
196
197 if let Some(s) = try_chart("Dark Scatter", || {
199 let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
200 let y = vec![2.3, 4.1, 3.0, 5.8, 4.9, 7.2, 6.5, 8.1];
201 let cats = vec!["A", "B", "A", "B", "A", "B", "A", "B"];
202 scatter(&x, &y)
203 .color_by(&cats)
204 .title("Dark Theme Scatter")
205 .x_label("X")
206 .y_label("Y")
207 .theme(NewTheme::dark())
208 .size(500.0, 350.0)
209 .to_svg()
210 }) {
211 sections.push(s);
212 }
213
214 if let Some(s) = try_chart("Dark Bars", || {
216 bar(&["A", "B", "C", "D"], &[10.0, 25.0, 15.0, 30.0])
217 .title("Dark Theme Bars")
218 .theme(NewTheme::dark())
219 .size(500.0, 350.0)
220 .to_svg()
221 }) {
222 sections.push(s);
223 }
224
225 if let Some(s) = try_chart("Flat Line", || {
227 let x: Vec<f64> = (0..10).map(f64::from).collect();
228 line(&x, &[5.0; 10])
229 .title("Constant Y")
230 .size(400.0, 300.0)
231 .to_svg()
232 }) {
233 sections.push(s);
234 }
235
236 if let Some(s) = try_chart("Many Pie Slices", || {
238 let mut vals = vec![50.0, 30.0, 15.0];
239 vals.extend(std::iter::repeat_n(0.5, 10));
240 let labels: Vec<String> = (0..vals.len()).map(|i| format!("Slice {i}")).collect();
241 let labels_ref: Vec<&str> = labels.iter().map(|s| s.as_str()).collect();
242 pie_labeled(&labels_ref, &vals)
243 .title("Pie: Many Slices")
244 .size(500.0, 400.0)
245 .to_svg()
246 }) {
247 sections.push(s);
248 }
249
250 if let Some(s) = try_chart("Heatmap", || {
252 let data = vec![
253 vec![1.0, 2.0, 3.0, 4.0],
254 vec![5.0, 6.0, 7.0, 8.0],
255 vec![9.0, 10.0, 11.0, 12.0],
256 ];
257 heatmap(data)
258 .title("Basic Heatmap")
259 .with_row_labels(&["R1", "R2", "R3"])
260 .with_col_labels(&["C1", "C2", "C3", "C4"])
261 .size(500.0, 350.0)
262 .to_svg()
263 }) {
264 sections.push(s);
265 }
266
267 let mut html = String::from(
269 r#"<!DOCTYPE html><html><head><meta charset="utf-8">
270<title>Audit Edge Cases</title>
271<style>
272body { font-family: system-ui; background: #f5f5f5; padding: 20px; }
273.chart-card { background: white; border-radius: 8px; padding: 16px; margin: 16px 0;
274 box-shadow: 0 1px 3px rgba(0,0,0,0.12); display: inline-block; vertical-align: top; }
275h2 { color: #333; font-size: 14px; margin: 0 0 8px 0; }
276.fail { background: #fff0f0; border: 1px solid #fcc; }
277</style></head><body>
278<h1>Audit Edge Cases</h1>"#,
279 );
280 for (title, svg) in §ions {
281 writeln!(
282 html,
283 "<div class=\"chart-card\"><h2>{title}</h2>{svg}</div>"
284 )
285 .unwrap();
286 }
287 html.push_str("</body></html>");
288 std::fs::write("audit_edge_cases.html", &html).unwrap();
289 println!("Saved audit_edge_cases.html ({} charts)", sections.len());
290}