From: Ben Pfaff Date: Fri, 15 May 2026 20:52:59 +0000 (-0700) Subject: work on labeling X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=420b9e5acb603317a70e9d3878823a0bc4702439;p=pspp work on labeling --- diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2e386e7ac3..4f11c99691 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -284,6 +284,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "btree_monstrousity" version = "0.0.5" @@ -2521,6 +2531,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", + "similar", "smallstr", "smallvec", "svg", @@ -2981,6 +2992,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "similar" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d93e861ede2e497b47833469b8ec9d5c07fa4c78ce7a00f6eb7dd8168b4b3f" +dependencies = [ + "bstr", +] + [[package]] name = "siphasher" version = "1.0.2" diff --git a/rust/doc/src/spv/graphs.md b/rust/doc/src/spv/graphs.md index 909db531d0..bfc0d75348 100644 --- a/rust/doc/src/spv/graphs.md +++ b/rust/doc/src/spv/graphs.md @@ -932,3 +932,7 @@ Rotated weird text chart with multiple facetLevels: Normal-ish barchart with multiple facetLevels: /home/blp/pspp/spv/spv/9538e0d28ff95b21336ea19a551affca/00000000072_2564001948504162306_chart.xml + +# To-Do + +* Weighting with `weight="true"` diff --git a/rust/pspp/Cargo.toml b/rust/pspp/Cargo.toml index 09100e97f5..d3fbf3159b 100644 --- a/rust/pspp/Cargo.toml +++ b/rust/pspp/Cargo.toml @@ -88,3 +88,4 @@ path = "src/lib.rs" approx = "0.5.1" diff = "0.1.13" rand = "0.9.0" +similar = "3.1.0" diff --git a/rust/pspp/src/output/pivot/tests.rs b/rust/pspp/src/output/pivot/tests.rs index ea56516202..e772191da6 100644 --- a/rust/pspp/src/output/pivot/tests.rs +++ b/rust/pspp/src/output/pivot/tests.rs @@ -17,6 +17,7 @@ use std::{fmt::Display, fs::File, path::Path, sync::Arc}; use enum_map::EnumMap; +use similar::TextDiff; use crate::{ format::{DOLLAR40_2, F40_2, Format, PCT40_1}, @@ -131,20 +132,14 @@ where A: Display, { if expected != actual { - eprintln!("Unexpected output:\n--- {expected_name}\n+++ {actual_name}"); - for result in diff::lines(expected, &actual) { - let (prefix, line) = match result { - diff::Result::Left(line) => ('-', line), - diff::Result::Both(line, _) => (' ', line), - diff::Result::Right(line) => ('+', line), - }; - let suffix = if line.trim_end().len() != line.len() { - "$" - } else { - "" - }; - eprintln!("{prefix}{line}{suffix}"); - } + eprintln!("Unexpected output:\n"); + let diff = TextDiff::from_lines(expected, actual); + eprint!( + "{}", + diff.unified_diff() + .context_radius(5) + .header(&expected_name.to_string(), &actual_name.to_string()) + ); panic!(); } } diff --git a/rust/pspp/src/spv/read/graph.rs b/rust/pspp/src/spv/read/graph.rs index c5fbba5410..e051e15fb4 100644 --- a/rust/pspp/src/spv/read/graph.rs +++ b/rust/pspp/src/spv/read/graph.rs @@ -44,10 +44,7 @@ use serde::{Deserialize, Deserializer, de::Error as _}; use smallvec::{SmallVec, smallvec}; use svg::{ Document, Node, - node::{ - Comment, - element::{Circle, Definitions, Group, Line, Path, Polygon, Rectangle, path::Data}, - }, + node::element::{Circle, Definitions, Group, Line, Path, Polygon, Rectangle, path::Data}, }; use crate::{ @@ -410,7 +407,15 @@ impl Visualization { let elements = graph .elements() .map(|(raw, graphic)| { - Element::new(raw, graphic, series, bin_widths, axis_domains, styles) + Element::new( + raw, + locale, + graphic, + series, + bin_widths, + axis_domains, + styles, + ) }) .collect::, _>>()?; let coordinates = graph @@ -507,7 +512,7 @@ impl Visualization { axis_domains[axis] = AxisDomain { domain, formatter: formatter.unwrap_or_else(|| Formatter::default_for_locale(locale)), - label: dbg!(axis2.and_then(|axis| axis.label.as_ref())), + label: axis2.and_then(|axis| axis.label.as_ref()), major_ticks: axis2.and_then(|axis| axis.major_ticks.as_ref()), }; } @@ -586,7 +591,9 @@ impl Visualization { } }*/ - let mut document = svg::Document::new().set("style", "font-family: \"Sans Serif\""); + let mut document = svg::Document::new() + .set("xmlns:c", "http://www.example.org/") + .set("style", "font-family: \"Sans Serif\""); if let Some(left) = frames.frames[0].position[Axis2::X].start() && let Some(width) = frames.frames[0].position[Axis2::X].length() && let Some(top) = frames.frames[0].position[Axis2::Y].start() @@ -604,8 +611,8 @@ impl Visualization { && let Some(_width) = frame.position[Axis2::X].length() && let Some(top) = frame.position[Axis2::Y].start() && let Some(_height) = frame.position[Axis2::Y].length() + && let Some(text) = label_frame.text() { - let text = label_frame.text(); let _metrics = font_metrics.measure(&text); document.append( svg::node::element::Text::new(text) @@ -747,17 +754,22 @@ impl Visualization { .set("text-anchor", "middle"), ); } - if let Some(label) = &axis_domains[Axis3::X].label { - graph_svg.append( - svg::node::element::Text::new(label.text()) - .set("x", rect.0[Axis2::X].midpoint()) - .set("y", y + 10.0 + font_height) - .set("dominant-baseline", "hanging") - .set("text-anchor", "middle"), - ); - } + } + if let Some(label) = &axis_domains[Axis3::X].label + && let Some(label) = label.text() + { + let x = rect.0[Axis2::X].midpoint(); + let y = rect.0[Axis2::Y].1 + 10.0 + font_height; + graph_svg.append( + svg::node::element::Text::new(label) + .set("x", x) + .set("y", y) + .set("dominant-baseline", "hanging") + .set("text-anchor", "middle"), + ); } } + for (y_index, y_facet) in y_facets.clone().enumerate() { let rect = rect.subrect(0, nx_facets, y_index, ny_facets); // Y axis. @@ -770,7 +782,7 @@ impl Visualization { .set("x1", x) .set("x2", x) .set("stroke", "black") - .add(Comment::new(format!("Y axis {y_index}"))), + .set("c:description", format!("Y axis {y_index}")), ); for (frac, label) in axis_domains[Axis3::Y].ticks() { let svg_y = rect.0[Axis2::Y].frac(1.0 - frac); @@ -801,29 +813,35 @@ impl Visualization { } }) .join(", "); - let x = x - 10.0 - y_axis_text_width - font_height; - let y = rect.0[Axis2::Y].midpoint(); - graph_svg.append( - svg::node::element::Text::new(label) - .set("x", x) - .set("y", y) - .set("dominant-baseline", "hanging") - .set("text-anchor", "middle") - .set("transform", format!("rotate(-90, {x}, {y})")), - ); + if !label.is_empty() { + let x = x - 10.0 - y_axis_text_width - font_height; + let y = rect.0[Axis2::Y].midpoint(); + graph_svg.append( + svg::node::element::Text::new(label) + .set("x", x) + .set("y", y) + .set("dominant-baseline", "hanging") + .set("text-anchor", "middle") + .set("transform", format!("rotate(-90, {x}, {y})")) + .set("c:description", "Row facet label"), + ); + } } - if let Some(label) = &axis_domains[Axis3::Y].label { + if let Some(label) = &axis_domains[Axis3::Y].label + && let Some(label) = label.text() + { let x = rect.0[Axis2::X].0 - 10.0 - y_axis_text_width - font_height; let y = rect.0[Axis2::Y].midpoint(); graph_svg.append( - svg::node::element::Text::new(dbg!(label.text())) + svg::node::element::Text::new(label) .set("x", x) .set("y", y) .set("dominant-baseline", "hanging") .set("text-anchor", "middle") - .set("transform", format!("rotate(-90, {x}, {y})")), - ); + .set("transform", format!("rotate(-90, {x}, {y})")) + .set("c:description", "Y axis label"), + ) } for (x_index, x_facet) in x_facets.enumerate() { @@ -2635,6 +2653,7 @@ struct Element<'a> { impl<'a> Element<'a> { fn new( raw: &'a RawElement, + locale: &'static Locale<'static>, graphic: Graphic, series: &BTreeMap<&str, Series>, bin_widths: &mut BTreeMap, @@ -2723,6 +2742,7 @@ impl<'a> Element<'a> { let total = frequencies.values().sum::(); let mut y = x.clone(); y.categorical = false; + y.formatter = Formatter::default_for_locale(locale); for value in &mut y.values { let frequency = frequencies.get(&value.value).copied().unwrap_or_default(); @@ -4005,11 +4025,11 @@ struct Label { } impl Label { - fn text(&self) -> String { + fn text(&self) -> Option { if let LabelChild::Text(text) = &self.child { - text.iter().map(|text| &text.text).join("") + Some(text.iter().map(|text| &text.text).join("")) } else { - String::new() + None } } } @@ -4089,11 +4109,11 @@ struct LabelFrame { } impl LabelFrame { - fn text(&self) -> String { + fn text(&self) -> Option { if let Some(label) = &self.label { label.text() } else { - String::new() + None } } } @@ -4184,7 +4204,7 @@ impl<'a> FrameType<'a> { let pangocairo_context = pangocairo::functions::create_context(&context); pangocairo::functions::context_set_resolution(&pangocairo_context, 96.0); let layout = pango::Layout::new(&pangocairo_context); - let text = label_frame.text(); + let text = label_frame.text().unwrap_or_default(); layout.set_text(&text); let (w, h) = layout.size(); enum_map! { Axis2::X => w as f64 / 1024.0, Axis2::Y => h as f64 / 1024.0} diff --git a/rust/pspp/src/spv/testdata/graph1.expected.svg b/rust/pspp/src/spv/testdata/graph1.expected.svg index dae4035671..cd8df20a49 100644 --- a/rust/pspp/src/spv/testdata/graph1.expected.svg +++ b/rust/pspp/src/spv/testdata/graph1.expected.svg @@ -1,4 +1,4 @@ - + Group Name @@ -34,9 +34,7 @@ ROC Curve X Axis - - - + 0 @@ -61,7 +59,7 @@ X Axis 1 - + Y Axis diff --git a/rust/pspp/src/spv/testdata/graph2.expected.svg b/rust/pspp/src/spv/testdata/graph2.expected.svg index a1d6d25b29..0de1665fd4 100644 --- a/rust/pspp/src/spv/testdata/graph2.expected.svg +++ b/rust/pspp/src/spv/testdata/graph2.expected.svg @@ -1,4 +1,4 @@ - + Title @@ -15,9 +15,7 @@ Title V2 - - - + 0 @@ -70,9 +68,7 @@ V2 V1 - - - + 0 @@ -121,9 +117,7 @@ V1 V3 - - - + 0 diff --git a/rust/pspp/src/spv/testdata/graph3.expected.svg b/rust/pspp/src/spv/testdata/graph3.expected.svg index 866c0e6572..6c5af5e496 100644 --- a/rust/pspp/src/spv/testdata/graph3.expected.svg +++ b/rust/pspp/src/spv/testdata/graph3.expected.svg @@ -1,4 +1,4 @@ - + @@ -12,9 +12,7 @@ Value1 V0 - - - + .0% @@ -31,12 +29,10 @@ V0 30.0% - -Percent + +no - - - + .0% @@ -53,7 +49,10 @@ Percent 30.0% - + +yes + + Percent diff --git a/rust/pspp/src/spv/testdata/graph4.expected.svg b/rust/pspp/src/spv/testdata/graph4.expected.svg index b8c23486d6..23056aa2e0 100644 --- a/rust/pspp/src/spv/testdata/graph4.expected.svg +++ b/rust/pspp/src/spv/testdata/graph4.expected.svg @@ -1,4 +1,4 @@ - + @@ -25,20 +25,22 @@ 50 - - - + 0 - - - + +yes + + 0 + +no + diff --git a/rust/pspp/src/spv/testdata/graph5.expected.svg b/rust/pspp/src/spv/testdata/graph5.expected.svg index 56073e1ebb..f4b742d42d 100644 --- a/rust/pspp/src/spv/testdata/graph5.expected.svg +++ b/rust/pspp/src/spv/testdata/graph5.expected.svg @@ -1,200 +1,192 @@ - + - - - + + + - - + + - + Value of Variable 4 - - - + + + - - + + - + Value of Variable 4 - - - - - -.00 + + + +0 - - -1.00 + + +1 - - -2.00 + + +2 - - -3.00 + + +3 - - -4.00 + + +4 - - -5.00 + + +5 - - -6.00 + + +6 - + 4 - - - - - -.00 + + + +0 - - -1.00 + + +1 - - -2.00 + + +2 - - -3.00 + + +3 - - -4.00 + + +4 - - -5.00 + + +5 - - -6.00 + + +6 - + 5 - - - - - -.00 + + + +0 - - -1.00 + + +1 - - -2.00 + + +2 - - -3.00 + + +3 - - -4.00 + + +4 - - -5.00 + + +5 - - -6.00 + + +6 - + 7 - - - - - -.00 + + + +0 - - -1.00 + + +1 - - -2.00 + + +2 - - -3.00 + + +3 - - -4.00 + + +4 - - -5.00 + + +5 - - -6.00 + + +6 - + 6 - + Frequency - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - +