vegafusion_core/spec/
scale.rs

1use crate::spec::transform::aggregate::AggregateOpSpec;
2use crate::spec::values::{SignalExpressionSpec, SortOrderSpec};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct ScaleSpec {
9    pub name: String,
10
11    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
12    pub type_: Option<ScaleTypeSpec>,
13
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub domain: Option<ScaleDomainSpec>,
16
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub range: Option<ScaleRangeSpec>,
19
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub bins: Option<ScaleBinsSpec>,
22
23    #[serde(flatten)]
24    pub extra: HashMap<String, Value>,
25}
26
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
28#[serde(rename_all = "lowercase")]
29pub enum ScaleTypeSpec {
30    // Quantitative Scales
31    Linear,
32    Log,
33    Pow,
34    Sqrt,
35    Symlog,
36    Time,
37    Utc,
38    Sequential,
39
40    // Discrete Scales
41    Ordinal,
42    Band,
43    Point,
44
45    // Discretizing Scales
46    Quantile,
47    Quantize,
48    Threshold,
49    #[serde(rename = "bin-ordinal")]
50    BinOrdinal,
51}
52
53impl Default for ScaleTypeSpec {
54    fn default() -> Self {
55        Self::Linear
56    }
57}
58
59impl ScaleTypeSpec {
60    pub fn is_discrete(&self) -> bool {
61        use ScaleTypeSpec::*;
62        matches!(self, Ordinal | Band | Point)
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67#[serde(untagged)]
68pub enum ScaleDomainSpec {
69    Array(Vec<ScaleArrayElementSpec>),
70    FieldReference(ScaleFieldReferenceSpec),
71    FieldsVecStrings(ScaleVecStringsSpec),
72    FieldsReference(ScaleFieldsReferenceSpec),
73    FieldsReferences(ScaleFieldsReferencesSpec),
74    FieldsSignals(ScaleSignalsSpec),
75    Signal(SignalExpressionSpec),
76    Value(Value),
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct ScaleFieldsReferencesSpec {
81    pub fields: Vec<ScaleDataReferenceOrSignalSpec>,
82
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub sort: Option<ScaleDataReferenceSort>,
85
86    #[serde(flatten)]
87    pub extra: HashMap<String, Value>,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91pub struct ScaleVecStringsSpec {
92    pub fields: Vec<Vec<String>>,
93
94    #[serde(flatten)]
95    pub extra: HashMap<String, Value>,
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(untagged)]
100pub enum ScaleDataReferenceOrSignalSpec {
101    Reference(ScaleFieldReferenceSpec),
102    Signal(SignalExpressionSpec),
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub struct ScaleFieldReferenceSpec {
107    pub data: String,
108    pub field: String,
109
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub sort: Option<ScaleDataReferenceSort>,
112
113    // Need to support sort objects as well as booleans
114    // #[serde(skip_serializing_if = "Option::is_none")]
115    // pub sort: Option<bool>,
116    #[serde(flatten)]
117    pub extra: HashMap<String, Value>,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct ScaleFieldsReferenceSpec {
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub data: Option<String>,
124
125    pub fields: Vec<String>,
126
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub sort: Option<ScaleDataReferenceSort>,
129
130    #[serde(flatten)]
131    pub extra: HashMap<String, Value>,
132}
133
134impl ScaleFieldsReferenceSpec {
135    pub fn to_field_references(&self) -> Vec<ScaleFieldReferenceSpec> {
136        if let Some(data) = &self.data.clone() {
137            self.fields
138                .iter()
139                .map(|f| ScaleFieldReferenceSpec {
140                    data: data.clone(),
141                    field: f.clone(),
142                    sort: self.sort.clone(),
143                    extra: Default::default(),
144                })
145                .collect::<Vec<_>>()
146        } else {
147            Vec::new()
148        }
149    }
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
153pub struct ScaleSignalsSpec {
154    pub fields: Vec<SignalExpressionSpec>,
155
156    #[serde(flatten)]
157    pub extra: HashMap<String, Value>,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161#[serde(untagged)]
162pub enum ScaleDataReferenceSort {
163    Bool(bool),
164    Parameters(ScaleDataReferenceSortParameters),
165}
166
167impl Default for ScaleDataReferenceSort {
168    fn default() -> Self {
169        Self::Bool(false)
170    }
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
174pub struct ScaleDataReferenceSortParameters {
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub op: Option<AggregateOpSpec>,
177
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub field: Option<String>,
180
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub order: Option<SortOrderSpec>,
183}
184
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186#[serde(untagged)]
187pub enum ScaleArrayElementSpec {
188    Signal(SignalExpressionSpec),
189    Value(Value),
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
193#[serde(untagged)]
194pub enum ScaleBinsSpec {
195    Signal(SignalExpressionSpec),
196    Array(Vec<ScaleArrayElementSpec>),
197    Value(Value),
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
201#[serde(untagged)]
202pub enum ScaleRangeSpec {
203    Array(Vec<ScaleArrayElementSpec>),
204    Reference(ScaleFieldReferenceSpec),
205    Signal(SignalExpressionSpec),
206    Value(Value),
207}