11# Charts
22
3- Data visualization with Chart widget .
3+ Comprehensive data visualization with Chart widgets. Presentar provides a rich set of chart types with full test coverage .
44
55## Chart Types
66
7- | Type | Use Case |
8- | ------| ----------|
9- | Line | Trends over time |
10- | Bar | Category comparison |
11- | Pie | Part of whole |
12- | Scatter | Correlation |
13- | Area | Cumulative values |
7+ | Type | Use Case | Example |
8+ | ------| ----------| ---------|
9+ | Line | Trends over time | ` cht_sparkline ` |
10+ | Bar | Category comparison | ` cht_boxplot ` |
11+ | Pie/Donut | Part of whole | ` cht_donut ` |
12+ | Scatter/Bubble | Correlation | ` cht_scatter_bubble ` |
13+ | Area | Cumulative values | ` cht_area_stacked ` |
14+ | Heatmap | 2D density | ` cht_heatmap_basic ` |
15+ | Multi-Axis | Dual metrics | ` cht_multi_axis ` |
1416
15- ## Basic Line Chart
17+ ## Scatter Plot with Size (CHT-004)
1618
17- ``` yaml
18- widgets :
19- - type : Chart
20- chart_type : line
21- data :
22- - [0, 10]
23- - [1, 20]
24- - [2, 15]
25- - [3, 30]
26- x_label : " Time"
27- y_label : " Value"
19+ Bubble charts map a third dimension to point radius:
20+
21+ ``` rust
22+ // From cht_scatter_bubble.rs
23+ pub struct BubbleChart {
24+ points : Vec <BubblePoint >,
25+ min_radius : f32 ,
26+ max_radius : f32 ,
27+ }
28+
29+ impl BubbleChart {
30+ pub fn size_to_radius (& self , size : f32 ) -> f32 {
31+ let (min_size , max_size ) = self . size_range ();
32+ if (max_size - min_size ). abs () < 0.0001 {
33+ return (self . min_radius + self . max_radius) / 2.0 ;
34+ }
35+ let normalized = (size - min_size ) / (max_size - min_size );
36+ self . min_radius + normalized * (self . max_radius - self . min_radius)
37+ }
38+ }
39+ ```
40+
41+ Run: ` cargo run --example cht_scatter_bubble `
42+
43+ ## Heatmap (CHT-005)
44+
45+ 2D heatmaps with colormap support:
46+
47+ ``` rust
48+ // From cht_heatmap_basic.rs
49+ pub enum Colormap {
50+ Viridis , Plasma , Inferno , Blues , Reds , Greens , Grayscale
51+ }
52+
53+ impl Colormap {
54+ pub fn map (& self , t : f32 ) -> Color {
55+ let t = t . clamp (0.0 , 1.0 );
56+ match self {
57+ Colormap :: Viridis => {
58+ let r = 0.267 + t * (0.993 - 0.267 );
59+ let g = 0.004 + t * (0.906 - 0.004 );
60+ let b = 0.329 + t * (0.143 - 0.329 );
61+ Color :: new (r , g , b , 1.0 )
62+ }
63+ // ... other colormaps
64+ }
65+ }
66+ }
67+ ```
68+
69+ Run: ` cargo run --example cht_heatmap_basic `
70+
71+ ## Box Plot (CHT-006)
72+
73+ Statistical box plots with quartile calculation:
74+
75+ ``` rust
76+ // From cht_boxplot.rs
77+ pub struct BoxPlotStats {
78+ pub min : f32 ,
79+ pub q1 : f32 ,
80+ pub median : f32 ,
81+ pub q3 : f32 ,
82+ pub max : f32 ,
83+ pub mean : f32 ,
84+ pub outliers : Vec <f32 >,
85+ }
86+
87+ impl BoxPlotStats {
88+ pub fn from_data (data : & [f32 ]) -> Option <Self > {
89+ // Calculates quartiles, IQR, and detects outliers
90+ // using 1.5 * IQR fence rule
91+ }
92+
93+ pub fn iqr (& self ) -> f32 {
94+ self . q3 - self . q1
95+ }
96+ }
97+ ```
98+
99+ Run: ` cargo run --example cht_boxplot `
100+
101+ ## Stacked Area Chart (CHT-007)
102+
103+ Area charts with proper stacking order:
104+
105+ ``` rust
106+ // From cht_area_stacked.rs
107+ impl StackedAreaChart {
108+ pub fn stacked_values (& self ) -> Vec <Vec <f32 >> {
109+ let n = self . data_points ();
110+ let mut result = Vec :: with_capacity (self . series. len ());
111+ let mut cumulative = vec! [0.0f32 ; n ];
112+
113+ for series in & self . series {
114+ let mut stacked = Vec :: with_capacity (n );
115+ for (i , & val ) in series . values. iter (). enumerate () {
116+ cumulative [i ] += val ;
117+ stacked . push (cumulative [i ]);
118+ }
119+ result . push (stacked );
120+ }
121+ result
122+ }
123+ }
28124```
29125
30- ## Bar Chart
126+ Run: ` cargo run --example cht_area_stacked `
127+
128+ ## Donut Chart (CHT-008)
129+
130+ Pie charts with configurable inner radius and center metric:
131+
132+ ``` rust
133+ // From cht_donut.rs
134+ pub struct DonutChart {
135+ segments : Vec <DonutSegment >,
136+ inner_radius_ratio : f32 , // 0.0 = pie, 0.6 = donut
137+ center_label : Option <String >,
138+ center_value : Option <String >,
139+ }
140+
141+ impl DonutChart {
142+ pub fn segment_angles (& self , index : usize ) -> Option <(f32 , f32 )> {
143+ // Returns (start_angle, end_angle) in radians
144+ // Starting at 12 o'clock (-π/2)
145+ }
146+ }
147+ ```
148+
149+ Run: ` cargo run --example cht_donut `
150+
151+ ## Sparkline (CHT-009)
152+
153+ Compact inline charts for dashboards:
154+
155+ ``` rust
156+ // From cht_sparkline.rs
157+ impl Sparkline {
158+ pub fn render_inline (& self ) -> String {
159+ let blocks = ['▁' , '▂' , '▃' , '▄' , '▅' , '▆' , '▇' , '█' ];
160+ self . values
161+ . iter ()
162+ . map (| & v | {
163+ let normalized = self . normalize (v );
164+ let idx = ((normalized * 7.0 ). round () as usize ). min (7 );
165+ blocks [idx ]
166+ })
167+ . collect ()
168+ }
169+
170+ pub fn trend_percentage (& self ) -> f32 {
171+ // Calculate percentage change from first to last value
172+ }
173+ }
174+ ```
175+
176+ Run: ` cargo run --example cht_sparkline `
177+
178+ ## Multi-Axis Chart (CHT-010)
179+
180+ Dual y-axis for correlation visualization:
181+
182+ ``` rust
183+ // From cht_multi_axis.rs
184+ impl MultiAxisChart {
185+ pub fn correlation (& self ) -> Option <f32 > {
186+ // Calculates Pearson correlation coefficient
187+ // between left and right axis data
188+ }
189+
190+ pub fn normalize (& self , value : f32 , axis : AxisSide ) -> f32 {
191+ // Normalizes value to 0-1 range for specific axis
192+ }
193+ }
194+ ```
195+
196+ Run: ` cargo run --example cht_multi_axis `
197+
198+ ## YAML Configuration
31199
32200``` yaml
33201widgets :
34202 - type : Chart
35- chart_type : bar
36- data :
37- - { label: "A", value: 30 }
38- - { label: "B", value: 50 }
39- - { label: "C", value: 20 }
40- colors :
41- - " #4285f4"
42- - " #ea4335"
43- - " #fbbc05"
203+ chart_type : line
204+ data : " {{ data.timeseries }}"
205+ x_label : " Time"
206+ y_label : " Value"
44207` ` `
45208
46209## Data Binding
@@ -56,47 +219,44 @@ widgets:
56219 data : " {{ sales | select('date', 'revenue') }}"
57220` ` `
58221
59- ## Styling
222+ ## Styling Options
60223
61224| Property | Description |
62225|----------|-------------|
63226| ` colors` | Series colors |
64227| `grid` | Show grid lines |
65228| `legend` | Legend position |
66229| `axis_*` | Axis configuration |
230+ | `colormap` | Heatmap colormap |
67231
68- # # Responsive
232+ # # Test Coverage
69233
70- ` ` ` yaml
71- widgets:
72- - type: Chart
73- responsive: true
74- aspect_ratio: 16:9
75- ` ` `
234+ All chart examples include comprehensive tests :
235+
236+ | Example | Tests | Coverage |
237+ |---------|-------|----------|
238+ | cht_scatter_bubble | 6 | Bounds, sizing, transform |
239+ | cht_heatmap_basic | 7 | Colormap, normalization |
240+ | cht_boxplot | 7 | Quartiles, outliers |
241+ | cht_area_stacked | 8 | Stacking, percentages |
242+ | cht_donut | 9 | Angles, segments |
243+ | cht_sparkline | 11 | Trends, rendering |
244+ | cht_multi_axis | 8 | Correlation, normalization |
76245
77246# # Verified Test
78247
79248` ` ` rust
80249#[test]
81- fn test_charts_data_point() {
82- // Chart data point structure
83- #[derive(Debug, PartialEq)]
84- struct DataPoint {
85- x: f32,
86- y: f32,
87- }
88-
89- let points = vec![
90- DataPoint { x: 0.0, y: 10.0 },
91- DataPoint { x: 1.0, y: 20.0 },
92- DataPoint { x: 2.0, y: 15.0 },
93- ];
94-
95- assert_eq!(points.len(), 3);
96- assert_eq!(points[1].y, 20.0);
250+ fn test_bubble_chart_radius() {
251+ let mut chart = BubbleChart::new(5.0, 25.0);
252+ chart.add_point(0.0, 0.0, 10.0, None);
253+ chart.add_point(100.0, 100.0, 50.0, None);
97254
98- // Find min/max for axis scaling
99- let max_y = points.iter().map(|p| p.y).fold(f32::MIN, f32::max);
100- assert_eq!(max_y, 20.0);
255+ // Size 10 is minimum -> min radius
256+ assert_eq!(chart.size_to_radius(10.0), 5.0);
257+ // Size 50 is maximum -> max radius
258+ assert_eq!(chart.size_to_radius(50.0), 25.0);
259+ // Size 30 is middle -> middle radius
260+ assert_eq!(chart.size_to_radius(30.0), 15.0);
101261}
102262` ` `
0 commit comments