rect.0[Axis2::Y].1 -= font_height;
}
+ let facet_levels = graph.facet_levels();
let faceting = graph
.faceting()
- .map(|f| f.decode(&series))
+ .map(|f| f.decode(&series, &facet_levels))
.unwrap_or_default();
let x_facets = FacetIterator::new(&faceting[Axis2::X]);
}
let label = zip(&y_facet, &faceting[Axis2::Y])
- .map(|(value, series)| {
+ .map(|(value, facet)| {
if let Some(label) = &value.label {
label.clone()
} else {
- series.formatter.display(&value.value).to_string()
+ facet.series.formatter.display(&value.value).to_string()
}
})
.join(", ");
let mut grouped_data = BTreeMap::<_, Vec<_>>::new();
'values: for i in 0.. {
- for (index, variable) in faceting[Axis2::X].iter().enumerate() {
- let Some(value) = variable.values.get(i) else {
+ for (index, facet) in faceting[Axis2::X].iter().enumerate() {
+ let Some(value) = facet.series.values.get(i) else {
break 'values;
};
let expected = x_facet[index];
continue 'values;
}
}
- for (index, variable) in faceting[Axis2::Y].iter().enumerate() {
- let Some(value) = variable.values.get(i) else {
+ for (index, facet) in faceting[Axis2::Y].iter().enumerate() {
+ let Some(value) = facet.series.values.get(i) else {
break 'values;
};
let expected = y_facet[index];
fn decode_faceting<'a>(
&self,
series: &'a BTreeMap<&str, Series>,
- faceting: &mut EnumMap<Axis2, Vec<&'a Series>>,
- index: usize,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ faceting: &mut EnumMap<Axis2, Vec<Facet<'a>>>,
+ axis_index: usize,
+ variable_index: &mut usize,
) {
- let axis = if index % 2 == 0 { Axis2::X } else { Axis2::Y };
+ let axis = if axis_index % 2 == 0 {
+ Axis2::X
+ } else {
+ Axis2::Y
+ };
+ *variable_index += 1;
let series = series.get(self.reference.as_str()).unwrap(); // XXX
assert!(series.categorical); // XXX
- faceting[axis].push(series);
+ faceting[axis].push(Facet {
+ series,
+ facet_level: facet_levels.get(&*variable_index).map(|v| &**v),
+ });
}
}
fn faceting(&self) -> Option<&Faceting> {
self.children.iter().find_map(|child| child.faceting())
}
+
+ fn facet_levels(&self) -> HashMap<usize, &FacetLevel> {
+ self.children
+ .iter()
+ .flat_map(|child| child.facet_layout())
+ .flat_map(|facet_layout| facet_layout.facet_levels())
+ .map(|facet_level| (facet_level.level, facet_level))
+ .collect()
+ }
}
impl Locations for Graph {
}
}
+ fn facet_layout(&self) -> Option<&FacetLayout> {
+ match self {
+ Self::FacetLayout(facet_layout) => Some(facet_layout),
+ _ => None,
+ }
+ }
+
fn location(&self) -> Option<&Location> {
match self {
Self::Location(location) => Some(location),
children: Vec<FacetingChild>,
}
+#[derive(Clone, Debug)]
+struct Facet<'a> {
+ series: &'a Series,
+ facet_level: Option<&'a FacetLevel>,
+}
+
impl Faceting {
/// Returns the faceting for each axis, as variable names from innermost to
/// outermost.
///
/// This could decode layering into Z-axis faceting but the corpus doesn't
/// contain any examples of layering.
- fn decode<'a>(&self, series: &'a BTreeMap<&str, Series>) -> EnumMap<Axis2, Vec<&'a Series>> {
+ fn decode<'a>(
+ &self,
+ series: &'a BTreeMap<&str, Series>,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ ) -> EnumMap<Axis2, Vec<Facet<'a>>> {
let mut faceting = EnumMap::default();
+ let mut variable_index = 0;
for child in &self.children {
- child.decode(series, &mut faceting);
+ child.decode(series, facet_levels, &mut faceting, &mut variable_index);
}
faceting
}
fn decode<'a>(
&self,
series: &'a BTreeMap<&str, Series>,
- faceting: &mut EnumMap<Axis2, Vec<&'a Series>>,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ faceting: &mut EnumMap<Axis2, Vec<Facet<'a>>>,
+ variable_index: &mut usize,
) {
match self {
FacetingChild::Cross(cross) | FacetingChild::Dot(cross) => {
- cross.decode(series, faceting, 0)
+ cross.decode(series, facet_levels, faceting, 0, variable_index)
}
FacetingChild::Layer(_layer) => { // XXX warn
}
fn decode<'a>(
&self,
series: &'a BTreeMap<&str, Series>,
- faceting: &mut EnumMap<Axis2, Vec<&'a Series>>,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ faceting: &mut EnumMap<Axis2, Vec<Facet<'a>>>,
start_index: usize,
+ variable_index: &mut usize,
) {
for (child, index) in self.children.iter().zip(start_index..) {
- child.decode(series, faceting, index);
+ child.decode(series, facet_levels, faceting, index, variable_index);
}
}
}
fn decode<'a>(
&self,
series: &'a BTreeMap<&str, Series>,
- faceting: &mut EnumMap<Axis2, Vec<&'a Series>>,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ faceting: &mut EnumMap<Axis2, Vec<Facet<'a>>>,
index: usize,
+ variable_index: &mut usize,
) {
match self {
CrossChild::Unity => (),
- CrossChild::Nest(nest) => nest.decode(series, faceting, index),
+ CrossChild::Nest(nest) => {
+ nest.decode(series, facet_levels, faceting, index, variable_index)
+ }
CrossChild::VariableReference(variable_reference) => {
- variable_reference.decode_faceting(series, faceting, index);
+ variable_reference.decode_faceting(
+ series,
+ facet_levels,
+ faceting,
+ index,
+ variable_index,
+ );
+ }
+ CrossChild::Cross(cross) => {
+ cross.decode(series, facet_levels, faceting, index, variable_index)
}
- CrossChild::Cross(cross) => cross.decode(series, faceting, index),
}
}
}
fn decode<'a>(
&self,
series: &'a BTreeMap<&'a str, Series>,
- faceting: &mut EnumMap<Axis2, Vec<&'a Series>>,
+ facet_levels: &HashMap<usize, &'a FacetLevel>,
+ faceting: &mut EnumMap<Axis2, Vec<Facet<'a>>>,
index: usize,
+ variable_index: &mut usize,
) {
for variable_reference in &self.variable_references {
- variable_reference.decode_faceting(series, faceting, index);
+ variable_reference.decode_faceting(
+ series,
+ facet_levels,
+ faceting,
+ index,
+ variable_index,
+ );
}
}
}
children: Vec<FacetLayoutChild>,
}
+impl FacetLayout {
+ fn facet_levels(&self) -> impl Iterator<Item = &FacetLevel> {
+ self.children.iter().flat_map(|child| child.facet_level())
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
enum FacetLayoutChild {
Other,
}
+impl FacetLayoutChild {
+ fn facet_level(&self) -> Option<&FacetLevel> {
+ match self {
+ FacetLayoutChild::FacetLevel(facet_level) => Some(facet_level),
+ _ => None,
+ }
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct SetCellProperties {
#[derive(Clone, Debug)]
struct FacetIterator<'a> {
- series: &'a [&'a Series],
+ facets: &'a [Facet<'a>],
next: SmallVec<[usize; 2]>,
remaining: usize,
}
impl<'a> FacetIterator<'a> {
- fn new(series: &'a [&'a Series]) -> Self {
+ fn new(facets: &'a [Facet<'a>]) -> Self {
Self {
- series,
- next: smallvec![0; series.len()],
- remaining: if series.is_empty() {
+ facets,
+ next: smallvec![0; facets.len()],
+ remaining: if facets.is_empty() {
1
} else {
- series
+ facets
.into_iter()
- .map(|series| series.unique_values.len())
+ .map(|facet| facet.series.unique_values.len())
.product()
},
}
.next
.iter()
.copied()
- .zip(self.series)
- .map(|(index, series)| &series.unique_values[index])
+ .zip(self.facets)
+ .map(|(index, facet)| &facet.series.unique_values[index])
.collect();
- for (index, series) in self.next.iter_mut().zip(self.series) {
+ for (index, facet) in self.next.iter_mut().zip(self.facets) {
*index += 1;
- if *index < series.unique_values.len() {
+ if *index < facet.series.unique_values.len() {
break;
}
*index = 0;