]> pintos-os.org Git - pspp/commitdiff
work on ticks
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 27 Jun 2026 22:59:45 +0000 (15:59 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 27 Jun 2026 22:59:45 +0000 (15:59 -0700)
rust/pspp/src/spv/read/graph.rs
rust/pspp/src/spv/testdata/graph5.xml

index bf548778910b7e6485ebf813ec380fabd534c755..32536e699a86f705bb50c66c63640bd16c48b287 100644 (file)
@@ -512,6 +512,7 @@ impl Visualization {
             axis_domains[axis] = AxisDomain {
                 domain,
                 formatter: formatter.unwrap_or_else(|| Formatter::default_for_locale(locale)),
+                axis: axis2,
                 label: dbg!(axis2.and_then(|axis| axis.label.as_ref())),
                 major_ticks: axis2.and_then(|axis| axis.major_ticks.as_ref()),
             };
@@ -733,6 +734,7 @@ impl Visualization {
                 let heading = FacetHeadings::new(
                     Side::default_for_axis(axis),
                     &faceting[axis],
+                    &axis_domains[axis.into()],
                     rect.0[axis].length() - heading_heights[!axis],
                     graph.axis_dimension(axis),
                     &mut font_metrics,
@@ -788,77 +790,6 @@ impl Visualization {
                 format!("rotate(90 {x} {y}) translate({x} {y})")
             });
 
-        for (x_index, _x_facet) in x_facets.clone().enumerate() {
-            {
-                let rect = inner.subrect(x_index, nx_facets, ny_facets - 1, ny_facets);
-                // X axis.
-                let y = rect.0[Axis2::Y].1;
-                let x_span = rect.0[Axis2::X];
-                /*graph_svg.append(
-                    Line::new()
-                        .set("x1", x_span.0)
-                        .set("x2", x_span.1)
-                        .set("y1", y)
-                        .set("y2", y)
-                        .set("stroke", "black"),
-                );*/
-                for (frac, label) in axis_domains[Axis3::X].ticks() {
-                    let svg_x = rect.0[Axis2::X].frac(frac);
-                    graph_svg = graph_svg
-                        .add(
-                            Line::new()
-                                .set("x1", svg_x)
-                                .set("x2", svg_x)
-                                .set("y1", y)
-                                .set("y2", y + 10.0)
-                                .set("stroke", "black"),
-                        )
-                        .add(
-                            svg::node::element::Text::new(dbg!(&label))
-                                .set("x", svg_x)
-                                .set("y", y + 10.0)
-                                .set("dominant-baseline", "hanging")
-                                .set("text-anchor", "middle"),
-                        );
-                }
-            }
-        }
-
-        for (y_index, _y_facet) in y_facets.clone().enumerate() {
-            let subrect = inner.subrect(0, nx_facets, y_index, ny_facets);
-            // Y axis.
-            let x = subrect.0[Axis2::X].0;
-            let y_span = subrect.0[Axis2::Y];
-            /*graph_svg.append(
-                Line::new()
-                    .set("y1", y_span.0)
-                    .set("y2", y_span.1)
-                    .set("x1", x)
-                    .set("x2", x)
-                    .set("stroke", "black")
-                    .set("c:description", format!("Y axis {y_index}")),
-            );*/
-            for (frac, label) in axis_domains[Axis3::Y].ticks() {
-                let svg_y = subrect.0[Axis2::Y].frac(1.0 - frac);
-                graph_svg = graph_svg
-                    .add(
-                        Line::new()
-                            .set("y1", svg_y)
-                            .set("y2", svg_y)
-                            .set("x1", x)
-                            .set("x2", x - 10.0)
-                            .set("stroke", "black"),
-                    )
-                    .add(
-                        svg::node::element::Text::new(label)
-                            .set("y", svg_y)
-                            .set("x", x - 10.0)
-                            .set("dominant-baseline", "middle")
-                            .set("text-anchor", "end"),
-                    );
-            }
-        }
-
         for (x_index, x_facet) in x_facets.enumerate() {
             for (y_index, y_facet) in y_facets.clone().enumerate() {
                 let rect = inner.subrect(x_index, nx_facets, y_index, ny_facets);
@@ -1226,8 +1157,8 @@ impl Visualization {
         graph_svg.append(bottom);
         graph_svg.append(left);
         graph_svg.append(right);
-        //graph_svg.append(rect.as_svg().set("fill", "none").set("stroke", "red"));
-        //graph_svg.append(inner.as_svg().set("fill", "none").set("stroke", "green"));
+        graph_svg.append(rect.as_svg().set("fill", "none").set("stroke", "red"));
+        graph_svg.append(inner.as_svg().set("fill", "none").set("stroke", "green"));
         Ok(graph_svg)
     }
 }
@@ -1732,6 +1663,7 @@ impl Variable for DerivedVariable {
 struct AxisDomain<'a> {
     domain: Domain,
     formatter: Formatter,
+    axis: Option<&'a Axis>,
     label: Option<&'a Label>,
     major_ticks: Option<&'a MajorTicks>,
 }
@@ -1741,6 +1673,7 @@ impl<'a> AxisDomain<'a> {
         Self {
             domain: Domain::default(),
             formatter: Formatter::default_for_locale(locale),
+            axis: None,
             label: None,
             major_ticks: None,
         }
@@ -4970,21 +4903,33 @@ struct FacetHeadings<'a> {
     /// Width, fixed by the caller.
     width: f64,
 
-    /// Axes and their labels.
+    /// Axis labels (e.g. X-axis or Y-axis label).
     ///
     /// Ordinarily there is at most one axis on each side; if there happens to
     /// be more than one then these go from innermost to outermost.  `axes`
     /// appear inside `facets` if both are present on the same side.
     axes: Vec<FacetAxisHeight<'a>>,
 
+    /// Hierarchical facet labels (e.g. the value for each facet, stacked if
+    /// there is more than one level of facets on an axis).
+    ///
     /// Per-row heights on the default (left or top) side and the opposite side,
     /// calculated based on `axis_facets` and `width`.
     ///
     /// From innermost to outermost.
     facets: Vec<FacetRowHeight<'a>>,
 
+    /// Axis tick marks.
+    ticks: Option<(Side, Vec<(f64, String)>, f64)>,
+
     /// Number of facets.
     n_facets: usize,
+
+    /// [AxisDomain] for X or Y axis.
+    ///
+    /// Currently there's always exactly one of these for an axis, although
+    /// perhaps there should be up to 2.
+    axis_domain: &'a AxisDomain<'a>,
 }
 
 struct FacetAxisHeight<'a> {
@@ -5024,11 +4969,19 @@ impl<'a> FacetHeadings<'a> {
                 .filter(|row_height| row_height.side == side)
                 .map(|row_height| row_height.height())
                 .sum::<f64>()
+            + if let Some((ticks_side, _, height)) = &self.ticks
+                && *ticks_side == side
+            {
+                *height
+            } else {
+                0.0
+            }
     }
 
     fn new(
         default_side: Side,
         facets: &'a [Facet<'a>],
+        axis_domain: &'a AxisDomain<'a>,
         width: f64,
         dimension: Option<&'a Dimension>,
         font_metrics: &mut FontMetrics,
@@ -5099,9 +5052,22 @@ impl<'a> FacetHeadings<'a> {
                 }
             })
             .collect();
+        let ticks = axis_domain.axis.map(|axis| {
+            (
+                if axis.opposite {
+                    !default_side
+                } else {
+                    default_side
+                },
+                axis_domain.ticks(),
+                10.0,
+            )
+        });
         Self {
             width,
             axes,
+            axis_domain,
+            ticks,
             facets,
             n_facets,
         }
@@ -5111,6 +5077,43 @@ impl<'a> FacetHeadings<'a> {
         let span = Span(0.0, self.width).subdivide(self.n_facets, 5.0);
         let mut group = Group::new();
 
+        fn render_ticks(
+            this: &FacetHeadings,
+            ticks: &[(f64, String)],
+            group: &mut Group,
+            span: &DividedSpan,
+            y: f64,
+        ) {
+            for facet_span in (0..this.n_facets).map(|index| span.nth(index)) {
+                for (frac, label) in ticks {
+                    let x = facet_span.frac(*frac);
+                    group.append(
+                        Line::new()
+                            .set("x1", x)
+                            .set("x2", x)
+                            .set("y1", y)
+                            .set("y2", y + 10.0)
+                            .set("stroke", "black"),
+                    );
+                    group.append(
+                        svg::node::element::Text::new(dbg!(label))
+                            .set("x", x)
+                            .set("y", y + 10.0)
+                            .set("dominant-baseline", "hanging")
+                            .set("text-anchor", "middle"),
+                    );
+                }
+            }
+        }
+
+        let mut y = 0.0;
+        if let Some((ticks_side, ticks, height)) = &self.ticks
+            && side == *ticks_side
+            && side == Side::Bottom
+        {
+            render_ticks(self, ticks, &mut group, &span, y);
+            y += height;
+        }
         /*
         group.append(
             Rect(enum_map! {
@@ -5121,7 +5124,6 @@ impl<'a> FacetHeadings<'a> {
             .set("fill", "none")
             .set("stroke", "red"),
         );*/
-        let mut y = 0.0;
         for axis in self.axes.iter().filter(|axis| axis.side == side) {
             if dbg!(axis.axis.combine_axis_labels) {
                 group.append(
@@ -5205,6 +5207,13 @@ impl<'a> FacetHeadings<'a> {
             }
             y += height.facet_label_height;
         }
+        if let Some((ticks_side, ticks, height)) = &self.ticks
+            && *ticks_side == side
+            && side == Side::Top
+        {
+            render_ticks(self, ticks, &mut group, &span, y);
+            y += height;
+        }
         group
     }
 }
index cdb2240507aac3ad57f56cd5473060867f34d75c..4f06ca6e33dafb770fd5b0ba0b37ca44fc374d7a 100644 (file)
@@ -46,7 +46,7 @@
     <location method="fixed" part="right" value="99%" />
     <coordinates id="coordinates_1305">
       <dimension id="dimension_1306" lowerMargin="5%" upperMargin="5%">
-        <axis opposite="true" combineAxisLabels="true" id="axis_axisx_1" repeat="never" style="axis_axisx_1s">
+        <axis combineAxisLabels="true" id="axis_axisx_1" repeat="never" style="axis_axisx_1s">
           <label id="label_axisx_1" style="style_1312" textFrameStyle="style_1310">
             <text id="text_1309">Variable 4</text>
           </label>