Skip to main content

esoc_chart/grammar/
layer.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! A chart layer: mark type + encodings + optional stat.
3
4use crate::grammar::encoding::Encoding;
5use crate::grammar::position::Position;
6use crate::grammar::stat::Stat;
7
8/// Mark type for a layer.
9#[derive(Clone, Copy, Debug)]
10pub enum MarkType {
11    /// Points/scatter.
12    Point,
13    /// Lines.
14    Line,
15    /// Bars.
16    Bar,
17    /// Area fill.
18    Area,
19    /// Text labels.
20    Text,
21    /// Arc/pie.
22    Arc,
23    /// Rules (reference lines).
24    Rule,
25    /// Heatmap (2D matrix visualization).
26    Heatmap,
27    /// Treemap (hierarchical area chart).
28    Treemap,
29}
30
31/// A single chart layer: a mark type with visual encodings.
32#[derive(Clone, Debug)]
33#[non_exhaustive]
34pub struct Layer {
35    /// The mark type.
36    pub mark: MarkType,
37    /// Encodings (visual channels mapped to data).
38    pub encodings: Vec<Encoding>,
39    /// Statistical transform.
40    pub stat: Stat,
41    /// X data (pre-resolved for express API).
42    pub x_data: Option<Vec<f64>>,
43    /// Y data (pre-resolved for express API).
44    pub y_data: Option<Vec<f64>>,
45    /// Category labels (for color encoding).
46    pub categories: Option<Vec<String>>,
47    /// Inner radius fraction for donut charts (0.0 = pie, >0 = donut).
48    pub inner_radius_fraction: f32,
49    /// Position adjustment.
50    pub position: Position,
51    /// Facet assignment per data row.
52    pub facet_values: Option<Vec<String>>,
53    /// Heatmap data (row-major 2D matrix).
54    pub heatmap_data: Option<Vec<Vec<f64>>>,
55    /// Row labels for heatmap.
56    pub row_labels: Option<Vec<String>>,
57    /// Column labels for heatmap.
58    pub col_labels: Option<Vec<String>>,
59    /// Whether to annotate heatmap cells with values.
60    pub annotate_cells: bool,
61    /// Human-readable label for this layer (used in legends).
62    pub label: Option<String>,
63    /// Symmetric error bar values (±err per data point).
64    pub error_bars: Option<Vec<f64>>,
65}
66
67impl Layer {
68    /// Create a new layer with a mark type.
69    pub fn new(mark: MarkType) -> Self {
70        Self {
71            mark,
72            encodings: Vec::new(),
73            stat: Stat::Identity,
74            x_data: None,
75            y_data: None,
76            categories: None,
77            inner_radius_fraction: 0.0,
78            position: Position::default(),
79            facet_values: None,
80            heatmap_data: None,
81            row_labels: None,
82            col_labels: None,
83            annotate_cells: false,
84            label: None,
85            error_bars: None,
86        }
87    }
88
89    /// Set a human-readable label for this layer (used in legends).
90    pub fn with_label(mut self, label: impl Into<String>) -> Self {
91        self.label = Some(label.into());
92        self
93    }
94
95    /// Add an X encoding.
96    #[deprecated(
97        note = "Encoding-based API is not yet wired into the compile pipeline. Use with_x/with_y/with_categories instead."
98    )]
99    pub fn encode_x(mut self, mut enc: Encoding) -> Self {
100        enc.channel = crate::grammar::encoding::Channel::X;
101        self.encodings.push(enc);
102        self
103    }
104
105    /// Add a Y encoding.
106    #[deprecated(
107        note = "Encoding-based API is not yet wired into the compile pipeline. Use with_x/with_y/with_categories instead."
108    )]
109    pub fn encode_y(mut self, mut enc: Encoding) -> Self {
110        enc.channel = crate::grammar::encoding::Channel::Y;
111        self.encodings.push(enc);
112        self
113    }
114
115    /// Add a color encoding.
116    #[deprecated(
117        note = "Encoding-based API is not yet wired into the compile pipeline. Use with_x/with_y/with_categories instead."
118    )]
119    pub fn encode_color(mut self, mut enc: Encoding) -> Self {
120        enc.channel = crate::grammar::encoding::Channel::Color;
121        self.encodings.push(enc);
122        self
123    }
124
125    /// Add a size encoding.
126    #[deprecated(
127        note = "Encoding-based API is not yet wired into the compile pipeline. Use with_x/with_y/with_categories instead."
128    )]
129    pub fn encode_size(mut self, mut enc: Encoding) -> Self {
130        enc.channel = crate::grammar::encoding::Channel::Size;
131        self.encodings.push(enc);
132        self
133    }
134
135    /// Set the statistical transform.
136    pub fn stat(mut self, stat: Stat) -> Self {
137        self.stat = stat;
138        self
139    }
140
141    /// Set pre-resolved X data.
142    pub fn with_x(mut self, x: Vec<f64>) -> Self {
143        self.x_data = Some(x);
144        self
145    }
146
147    /// Set pre-resolved Y data.
148    pub fn with_y(mut self, y: Vec<f64>) -> Self {
149        self.y_data = Some(y);
150        self
151    }
152
153    /// Set category labels.
154    pub fn with_categories(mut self, cats: Vec<String>) -> Self {
155        self.categories = Some(cats);
156        self
157    }
158
159    /// Set inner radius fraction for donut charts.
160    pub fn with_inner_radius_fraction(mut self, fraction: f32) -> Self {
161        self.inner_radius_fraction = fraction;
162        self
163    }
164
165    /// Set position adjustment.
166    pub fn position(mut self, position: Position) -> Self {
167        self.position = position;
168        self
169    }
170
171    /// Set facet values (per-row facet assignment).
172    pub fn with_facet_values(mut self, facet_values: Vec<String>) -> Self {
173        self.facet_values = Some(facet_values);
174        self
175    }
176
177    /// Set heatmap data (row-major 2D matrix).
178    pub fn with_heatmap_data(mut self, data: Vec<Vec<f64>>) -> Self {
179        self.heatmap_data = Some(data);
180        self
181    }
182
183    /// Set row labels for heatmap.
184    pub fn with_row_labels(mut self, labels: Vec<String>) -> Self {
185        self.row_labels = Some(labels);
186        self
187    }
188
189    /// Set column labels for heatmap.
190    pub fn with_col_labels(mut self, labels: Vec<String>) -> Self {
191        self.col_labels = Some(labels);
192        self
193    }
194
195    /// Enable cell value annotations for heatmap.
196    pub fn annotate_cells(mut self) -> Self {
197        self.annotate_cells = true;
198        self
199    }
200
201    /// Set symmetric error bar values (±err per data point).
202    pub fn with_error_bars(mut self, errors: Vec<f64>) -> Self {
203        self.error_bars = Some(errors);
204        self
205    }
206}