From: Ben Pfaff Date: Fri, 2 Jan 2026 23:55:02 +0000 (-0800) Subject: legacy table subscripts X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=48982a0fa2ba3171bc16fd42294439a111105ab1;p=pspp legacy table subscripts --- diff --git a/rust/pspp/src/spv/read/legacy_bin.rs b/rust/pspp/src/spv/read/legacy_bin.rs index 813dd9d4db..acd43b751b 100644 --- a/rust/pspp/src/spv/read/legacy_bin.rs +++ b/rust/pspp/src/spv/read/legacy_bin.rs @@ -202,8 +202,10 @@ impl DataValue { && let Ok(time) = NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S%.3f") { Value::new_time(time) - } else { + } else if !self.value.is_sysmis() { Value::new_datum(&self.value) + } else { + Value::new_empty() } .with_format(format) } diff --git a/rust/pspp/src/spv/read/legacy_xml.rs b/rust/pspp/src/spv/read/legacy_xml.rs index f5f39a3449..325afa44ad 100644 --- a/rust/pspp/src/spv/read/legacy_xml.rs +++ b/rust/pspp/src/spv/read/legacy_xml.rs @@ -256,6 +256,7 @@ impl Visualization { .chain(derived_variables.iter().map(|dv| dv.id.clone())) .collect(), )); + break; } } series @@ -378,6 +379,21 @@ impl Visualization { return HashMap::default(); }; + let markers = if let Some(markers) = graph.interval.footnotes(false) + && let Some(series) = series.get(markers.variable.as_str()) + { + Some(( + series, + markers + .mappings + .iter() + .map(|m| (m.from.get(), m.to.as_str())) + .collect::>(), + )) + } else { + None + }; + let mut data = HashMap::new(); let mut coords = Vec::with_capacity(dims.len()); let (cell_formats, format_map) = graph.interval.labeling.decode_format_map(&series); @@ -420,13 +436,15 @@ impl Visualization { } } } - - if let Some(datum) = value.datum() - && datum.is_sysmis() - && value.footnotes().is_empty() + if let Some((series, mappings)) = &markers + && let Some(dv) = series.values.get(i) + && let Some(category) = dv.category() + && let Some(marker) = mappings.get(&category) { - // A system-missing value without a footnote represents an empty cell. - } else { + value.add_subscript(*marker); + } + + if !value.is_empty() { data.insert(coords.clone(), value); } } @@ -674,7 +692,7 @@ impl Visualization { let cell_footnotes = graph .interval - .footnotes() + .footnotes(true) .and_then(|footnotes| series.get(footnotes.variable.as_str())); let mut data = self.decode_data(graph, &footnotes, cell_footnotes, &dims, &series, warn); @@ -1829,14 +1847,17 @@ struct Interval { } impl Interval { - fn footnotes(&self) -> Option<&Footnotes> { - if let Some(footnotes) = &self.footnotes { + fn footnotes(&self, superscript: bool) -> Option<&Footnotes> { + if let Some(footnotes) = &self.footnotes + && footnotes.superscript == superscript + { Some(footnotes) } else { self.labeling .children .iter() - .find_map(|child| child.as_footnotes()) + .flat_map(|child| child.as_footnotes()) + .find(|child| child.superscript == superscript) } } } @@ -1918,6 +1939,9 @@ struct Footnotes { #[serde(rename = "@variable")] variable: String, + #[serde(default, rename = "@superscript")] + superscript: bool, + #[serde(default, rename = "footnoteMapping")] mappings: Vec, } diff --git a/rust/pspp/src/spv/read/tests.rs b/rust/pspp/src/spv/read/tests.rs index c1860153ec..65de04f68a 100644 --- a/rust/pspp/src/spv/read/tests.rs +++ b/rust/pspp/src/spv/read/tests.rs @@ -102,6 +102,12 @@ fn legacy15() { test_raw_spvfile("legacy15"); } +/// Subscript support. +#[test] +fn legacy16() { + test_raw_spvfile("legacy16"); +} + fn test_raw_spvfile(name: &str) { let input_filename = Path::new("src/spv/testdata") .join(name) diff --git a/rust/pspp/src/spv/testdata/legacy16.expected b/rust/pspp/src/spv/testdata/legacy16.expected new file mode 100644 index 0000000000..b8cf7896bc --- /dev/null +++ b/rust/pspp/src/spv/testdata/legacy16.expected @@ -0,0 +1,17 @@ + Table 1 +╭────────────────────────┬─────────────────────────────────────────────────────────────────────────────╮ +│ │ GENDER │ +│ ├──────────────────────────┬──────────────────────────┬───────────────────────┤ +│ │ Male │ Female │ Total │ +│ ├───────┬──────────────────┼───────┬──────────────────┼────┬──────────────────┤ +│ │ Mean │Standard Deviation│ Mean │Standard Deviation│Mean│Standard Deviation│ +├────────────────────────┼───────┼──────────────────┼───────┼──────────────────┼────┼──────────────────┤ +│STATUS Examined AGE│ 52.3_a│ 9.2│ 51.8_a│ 10.7│52.0│ 10.1│ +│ Not Available AGE│ 50.8_a│ 7.4│ 49.4_a│ 8.2│50.6│ 7.4│ +│ Refused AGE│59.0[1]│. │50.0[1]│. │54.5│ 6.4│ +│ Total AGE│ 52.1│ 9.1│ 51.8│ 10.7│51.9│ 10.0│ +╰────────────────────────┴───────┴──────────────────┴───────┴──────────────────┴────┴──────────────────╯ +Note: Values in the same row and subtable not sharing the same subscript are significantly different at p< 0.05 in the two-sided test of equality for column means. Cells with no subscript are not included in the test. Tests assume equal variances.[2][3] +1. This category is not used in comparisons because the sum of case weights is less than two. +2. Tests are adjusted for all pairwise comparisons within a row of each innermost subtable using the Bonferroni correction. +3. Pairwise comparisons are not performed for some subtables because of numerical problems. diff --git a/rust/pspp/src/spv/testdata/legacy16.spv b/rust/pspp/src/spv/testdata/legacy16.spv new file mode 100644 index 0000000000..47f844f056 Binary files /dev/null and b/rust/pspp/src/spv/testdata/legacy16.spv differ