/// Graph has no `coordinates` element.
NoCoordinates,
+ /// Graph has multiple `{0}` child elements.
+ DuplicateGraphChild(&'static str),
+
/// Graph references missing variable `{0}`.
MissingVariable(String),
}
styles: &'a HashMap<String, Style>,
) -> Result<Vec<Element<'a>>, GraphError> {
let elements = graph
- .elements()
+ .elements
+ .iter()
.map(|(raw, graphic)| {
Element::new(
raw,
locale,
- graphic,
+ *graphic,
series,
bin_widths,
axis_domains,
)
})
.collect::<Result<Vec<_>, _>>()?;
- let coordinates = graph
- .coordinates()
- .next()
- .ok_or(GraphError::NoCoordinates)?;
- let dimensions = coordinates.dimensions().collect_vec();
+ let dimensions = graph.coordinates.dimensions().collect_vec();
for (index, axis) in [Axis3::X, Axis3::Y, Axis3::Z].into_iter().enumerate() {
let mut domain = if let Some(dimension) = dimensions.get(index)
&& let Some(domain_name) = &dimension.domain
let facet_levels = graph.facet_levels();
let faceting = graph
- .faceting()
+ .faceting
+ .as_ref()
.map(|f| f.decode(&series, &facet_levels))
.unwrap_or_default();
}
}
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
+#[derive(Debug)]
struct Graph {
- #[serde(rename = "@id")]
id: Option<String>,
-
- #[serde(rename = "@cellStyle")]
cell_style: Option<String>,
-
- #[serde(rename = "$value")]
- children: Vec<GraphChild>,
+ locations: Vec<Location>,
+ faceting: Option<Faceting>,
+ facet_layout: Option<FacetLayout>,
+ coordinates: Coordinates,
+ elements: Vec<(RawElement, Graphic)>,
}
impl Graph {
- fn coordinates(&self) -> impl Iterator<Item = &Coordinates> {
- self.children.iter().filter_map(|child| match child {
- GraphChild::Coordinates(coordinates) => Some(coordinates),
- _ => None,
- })
+ fn facet_levels(&self) -> HashMap<usize, &FacetLevel> {
+ self.facet_layout
+ .iter()
+ .flat_map(|facet_layout| facet_layout.facet_levels())
+ .map(|facet_level| (facet_level.level, facet_level))
+ .collect()
}
fn x_dimension(&self) -> Option<&Dimension> {
- self.coordinates().next()?.dimensions().next()
+ self.coordinates.dimensions().next()
}
fn y_dimension(&self) -> Option<&Dimension> {
- self.coordinates().next()?.dimensions().skip(1).next()
+ self.coordinates.dimensions().skip(1).next()
}
fn axis_dimension(&self, axis: Axis2) -> Option<&Dimension> {
Axis2::Y => self.y_dimension(),
}
}
+}
+
+impl<'de> Deserialize<'de> for Graph {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let raw_graph = RawGraph::deserialize(deserializer)?;
+ let mut locations = Vec::new();
+ let mut faceting = None;
+ let mut facet_layout = None;
+ let mut coordinates = None;
+ let mut elements = Vec::new();
+ for child in raw_graph.children {
+ match child {
+ GraphChild::Interval(interval) => elements.push((interval, Graphic::Interval)),
+ GraphChild::Point(point) => elements.push((point, Graphic::Point)),
+ GraphChild::Line(line) => elements.push((line, Graphic::Line)),
+ GraphChild::Polygon(polygon) => elements.push((polygon, Graphic::Polygon)),
+ GraphChild::Area(area) => elements.push((area, Graphic::Area)),
+ GraphChild::Schema(schema) => elements.push((schema, Graphic::Schema)),
+ GraphChild::Edge(edge) => elements.push((edge, Graphic::Edge)),
+ GraphChild::Path(path) => elements.push((path, Graphic::Path)),
+ GraphChild::Location(location) => locations.push(location),
+ GraphChild::Faceting(value) => {
+ if faceting.replace(value).is_some() {
+ return Err(D::Error::duplicate_field("faceting"));
+ }
+ }
+ GraphChild::FacetLayout(value) => {
+ if facet_layout.replace(value).is_some() {
+ return Err(D::Error::duplicate_field("facetLayout"));
+ }
+ }
+ GraphChild::Coordinates(value) => {
+ if coordinates.replace(value).is_some() {
+ return Err(D::Error::duplicate_field("coordinates"));
+ }
+ }
+ GraphChild::LineGuide => (),
+ };
+ }
+ Ok(Self {
+ id: raw_graph.id,
+ cell_style: raw_graph.cell_style,
+ locations,
+ faceting,
+ facet_layout,
+ coordinates: coordinates.ok_or_else(|| D::Error::missing_field("coordinates"))?,
+ elements,
+ })
+ }
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct RawGraph {
+ #[serde(rename = "@id")]
+ id: Option<String>,
+
+ #[serde(rename = "@cellStyle")]
+ cell_style: Option<String>,
+
+ #[serde(rename = "$value")]
+ children: Vec<GraphChild>,
+}
+
+impl RawGraph {
+ fn coordinates(&self) -> impl Iterator<Item = &Coordinates> {
+ self.children.iter().filter_map(|child| match child {
+ GraphChild::Coordinates(coordinates) => Some(coordinates),
+ _ => None,
+ })
+ }
fn elements(&self) -> impl Iterator<Item = (&RawElement, Graphic)> {
self.children.iter().filter_map(|child| child.element())
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 {
+impl Locations for RawGraph {
fn locations(&self) -> Vec<&Location> {
self.children
.iter()
match self {
FrameType::Visualization(visualization) => visualization.locations(),
FrameType::Container(container) => container.locations(),
- FrameType::Graph(graph) => graph.locations(),
+ FrameType::Graph(graph) => graph.locations.iter().collect(),
FrameType::LabelFrame(label_frame) => label_frame.locations(),
FrameType::Legend(legend) => legend.locations(),
}