Skip to content

Commit f6a3202

Browse files
feat[array]: validity in display array (#5799)
Signed-off-by: Joe Isaacs <[email protected]>
1 parent d3021c7 commit f6a3202

File tree

3 files changed

+102
-6
lines changed

3 files changed

+102
-6
lines changed

vortex-array/src/compute/zip.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ mod tests {
329329
let result = zip(&const1, &const2, &mask).unwrap();
330330

331331
insta::assert_snapshot!(result.display_tree(), @r"
332-
root: vortex.varbinview(utf8?, len=100) nbytes=1.66 kB (100.00%)
332+
root: vortex.varbinview(utf8?, len=100) nbytes=1.66 kB (100.00%) [all_valid]
333333
metadata: EmptyMetadata
334334
buffer (align=1): 29 B (1.75%)
335335
buffer (align=1): 28 B (1.69%)
@@ -348,7 +348,7 @@ mod tests {
348348
insta::assert_snapshot!(wrapped_result.display_tree(), @r"
349349
root: vortex.struct({nested=utf8?}, len=100) nbytes=1.66 kB (100.00%)
350350
metadata: EmptyMetadata
351-
nested: vortex.varbinview(utf8?, len=100) nbytes=1.66 kB (100.00%)
351+
nested: vortex.varbinview(utf8?, len=100) nbytes=1.66 kB (100.00%) [all_valid]
352352
metadata: EmptyMetadata
353353
buffer (align=1): 29 B (1.75%)
354354
buffer (align=1): 28 B (1.69%)

vortex-array/src/display/tree.rs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,109 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
use std::fmt::Write;
45
use std::fmt::{self};
56

67
use humansize::DECIMAL;
78
use humansize::format_size;
89

10+
use crate::Array;
911
use crate::ArrayRef;
1012
use crate::ArrayVisitor;
1113
use crate::arrays::ChunkedVTable;
1214
use crate::display::DisplayOptions;
15+
use crate::expr::stats::Stat;
16+
use crate::expr::stats::StatsProvider;
17+
18+
/// Display wrapper for array statistics in compact format.
19+
struct StatsDisplay<'a>(&'a dyn Array);
20+
21+
impl fmt::Display for StatsDisplay<'_> {
22+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23+
let stats = self.0.statistics();
24+
let mut first = true;
25+
26+
// Helper to write separator
27+
let mut sep = |f: &mut fmt::Formatter<'_>| -> fmt::Result {
28+
if first {
29+
first = false;
30+
f.write_str(" [")
31+
} else {
32+
f.write_str(", ")
33+
}
34+
};
35+
36+
// Null count or validity fallback
37+
if let Some(nc) = stats.get(Stat::NullCount) {
38+
if let Ok(n) = usize::try_from(&nc.clone().into_inner()) {
39+
sep(f)?;
40+
write!(f, "nulls={}", n)?;
41+
} else {
42+
sep(f)?;
43+
write!(f, "nulls={}", nc)?;
44+
}
45+
} else if self.0.dtype().is_nullable() {
46+
if self.0.all_valid() {
47+
sep(f)?;
48+
f.write_str("all_valid")?;
49+
} else if self.0.all_invalid() {
50+
sep(f)?;
51+
f.write_str("all_invalid")?;
52+
}
53+
}
54+
55+
// NaN count (only if > 0)
56+
if let Some(nan) = stats.get(Stat::NaNCount)
57+
&& let Ok(n) = usize::try_from(&nan.into_inner())
58+
&& n > 0
59+
{
60+
sep(f)?;
61+
write!(f, "nan={}", n)?;
62+
}
63+
64+
// Min/Max
65+
if let Some(min) = stats.get(Stat::Min) {
66+
sep(f)?;
67+
write!(f, "min={}", min)?;
68+
}
69+
if let Some(max) = stats.get(Stat::Max) {
70+
sep(f)?;
71+
write!(f, "max={}", max)?;
72+
}
73+
74+
// Sum
75+
if let Some(sum) = stats.get(Stat::Sum) {
76+
sep(f)?;
77+
write!(f, "sum={}", sum)?;
78+
}
79+
80+
// Boolean flags (compact)
81+
if let Some(c) = stats.get(Stat::IsConstant)
82+
&& bool::try_from(&c.into_inner()).unwrap_or(false)
83+
{
84+
sep(f)?;
85+
f.write_str("const")?;
86+
}
87+
if let Some(s) = stats.get(Stat::IsStrictSorted) {
88+
if bool::try_from(&s.into_inner()).unwrap_or(false) {
89+
sep(f)?;
90+
f.write_str("strict")?;
91+
}
92+
} else if let Some(s) = stats.get(Stat::IsSorted)
93+
&& bool::try_from(&s.into_inner()).unwrap_or(false)
94+
{
95+
sep(f)?;
96+
f.write_str("sorted")?;
97+
}
98+
99+
// Close bracket if we wrote anything
100+
if !first {
101+
f.write_char(']')?;
102+
}
103+
104+
Ok(())
105+
}
106+
}
13107

14108
pub(crate) struct TreeDisplayWrapper(pub(crate) ArrayRef);
15109

@@ -39,13 +133,15 @@ impl<'a, 'b: 'a> TreeFormatter<'a, 'b> {
39133
} else {
40134
100_f64 * nbytes as f64 / total_size as f64
41135
};
136+
42137
writeln!(
43138
self,
44-
"{}: {} nbytes={} ({:.2}%)",
139+
"{}: {} nbytes={} ({:.2}%){}",
45140
name,
46141
array.display_as(DisplayOptions::MetadataOnly),
47142
format_size(nbytes, DECIMAL),
48-
percent
143+
percent,
144+
StatsDisplay(array.as_ref()),
49145
)?;
50146

51147
self.indent(|i| {

vortex-python/src/arrays/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,11 +650,11 @@ impl PyArray {
650650
/// ```python
651651
/// >>> import vortex as vx
652652
/// >>> arr = vx.array([1, 2, None, 3])
653-
/// >>> print(arr.display_tree())
653+
/// >>> print(arr.display_tree()) # doctest: +ELLIPSIS
654654
/// root: vortex.primitive(i64?, len=4) nbytes=33 B (100.00%)
655655
/// metadata: EmptyMetadata
656656
/// buffer (align=8): 32 B (96.97%)
657-
/// validity: vortex.bool(bool, len=4) nbytes=1 B (3.03%)
657+
/// validity: vortex.bool(bool, len=4) nbytes=1 B (3.03%)...
658658
/// metadata: BoolMetadata { offset: 0 }
659659
/// buffer (align=1): 1 B (100.00%)
660660
/// <BLANKLINE>

0 commit comments

Comments
 (0)