Skip to content

Commit e6327b6

Browse files
authored
feat: Support PrettyTables v3 (#83)
1 parent 641e45b commit e6327b6

5 files changed

Lines changed: 108 additions & 49 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@
1010

1111
### Maintenance
1212

13+
### Documentation
14+
15+
## v0.4.3 (2025-11-24)
16+
17+
### Features
18+
19+
- Support PrettyTables v3 (v2 temporarily still supported) ([#83](https://github.com/arviz-devs/PosteriorStats.jl/pull/83))
20+
21+
### Maintenance
22+
1323
- Store SummaryStats labels separately from data ([#81](https://github.com/arviz-devs/PosteriorStats.jl/pull/81))
1424
- Add historical changelog ([#82](https://github.com/arviz-devs/PosteriorStats.jl/pull/82))
1525
- Add pull request templates ([#82](https://github.com/arviz-devs/PosteriorStats.jl/pull/82))
1626

17-
### Documentation
18-
1927
## v0.4.2 (2025-10-13)
2028

2129
### Maintenance

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PosteriorStats"
22
uuid = "7f36be82-ad55-44ba-a5c0-b8b5480d7aa5"
33
authors = ["Seth Axen <seth@sethaxen.com> and contributors"]
4-
version = "0.4.3-DEV"
4+
version = "0.4.3"
55

66
[deps]
77
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
@@ -51,7 +51,7 @@ Optim = "1.7.2"
5151
OrderedCollections = "1.3.0"
5252
PDMats = "0.11.11"
5353
PSIS = "0.9.1"
54-
PrettyTables = "2.1"
54+
PrettyTables = "2.1, 3"
5555
Printf = "1"
5656
Random = "1"
5757
Roots = "1, 2"

src/compare.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ function _show(io::IO, mime::MIME, r::ModelComparisonResult; kwargs...)
143143
weights_method_name = _typename(r.weights_method)
144144
weights = table.weight
145145
digits_weights = ceil(Int, -log10(maximum(weights))) + 1
146-
weight_formatter = PrettyTables.ft_printf(
147-
"%.$(digits_weights)f", findfirst(==(:weight), cols)
146+
weight_formatter = _prettytables_printf_formatter(
147+
"%.$(digits_weights)f", [findfirst(==(:weight), cols)]
148148
)
149149
return _show_prettytable(
150150
io,

src/show_prettytable.jl

Lines changed: 89 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,42 @@
11
# Utilities for displaying tables using PrettyTables.jl
22

3+
@static if pkgversion(PrettyTables).major == 2
4+
# temporarily support PrettyTables v2 until v3 is more broadly established in the ecosystem
5+
const IS_PRETTYTABLES_V2 = true
6+
const PRETTYTABLES_TEXT_FORMAT = (; hlines=:none, vlines=:none)
7+
const PRETTYTABLES_TEXT_STYLE = (; title_crayon=PrettyTables.Crayon())
8+
_prettytables_printf_formatter(fmt::String, cols) = PrettyTables.ft_printf(fmt, cols)
9+
else
10+
const IS_PRETTYTABLES_V2 = false
11+
const PRETTYTABLES_TEXT_FORMAT = PrettyTables.TextTableFormat(;
12+
PrettyTables.@text__no_vertical_lines, PrettyTables.@text__no_horizontal_lines
13+
)
14+
const PRETTYTABLES_TEXT_STYLE = PrettyTables.TextTableStyle(;
15+
title=PrettyTables.Crayon()
16+
)
17+
_prettytables_printf_formatter(fmt::String, cols) = PrettyTables.fmt__printf(fmt, cols)
18+
end
19+
320
# formatting functions for special columns
421
# see https://ronisbr.github.io/PrettyTables.jl/stable/man/usage/#Formatters
522

623
# Use Printf to format real elements to the number of `sigdigits`.
7-
function ft_printf_sigdigits(sigdigits::Int)
24+
function _prettytables_sigdigits_formatter(sigdigits::Int)
825
return (v, _, _) -> begin
926
v isa Real || return v
1027
return _printf_with_sigdigits(v, sigdigits)
1128
end
1229
end
13-
function ft_printf_sigdigits(sigdigits::Int, columns::AbstractVector{Int})
14-
isempty(columns) && return ft_printf_sigdigits(sigdigits)
30+
function _prettytables_sigdigits_formatter(sigdigits::Int, columns::AbstractVector{Int})
31+
isempty(columns) && return _prettytables_sigdigits_formatter(sigdigits)
1532
return (v, _, j) -> begin
1633
(v isa Real && j columns) || return v
1734
return _printf_with_sigdigits(v, sigdigits)
1835
end
1936
end
2037

2138
# Use Printf to format interval elements to the number of `sigdigits`.
22-
function ft_printf_sigdigits_interval(sigdigits::Int)
39+
function _prettytables_interval_formatter(sigdigits::Int)
2340
return (v, _, _) -> begin
2441
v isa IntervalSets.AbstractInterval || return v
2542
tuple_string = map(Base.Fix2(_printf_with_sigdigits, sigdigits), extrema(v))
@@ -32,7 +49,7 @@ function _interval_delimiter(x::IntervalSets.AbstractInterval)
3249
return occursin(" .. ", str) ? " .. " : ".."
3350
end
3451

35-
function ft_printf_sigdigits_matching_se(data, col::Int, se_col::Int; kwargs...)
52+
function _prettytables_sigdigits_from_se_formatter(data, col::Int, se_col::Int; kwargs...)
3653
se_vals = Tables.getcolumn(data, se_col)
3754
return (v, i, j) -> begin
3855
(v isa Real && col == j && se_vals[i] isa Real) || return v
@@ -61,34 +78,36 @@ function _prettytables_se_formatters(data; sigdigits_se=2)
6178
col col_names || continue
6279
idx_col = Tables.columnindex(data, col)
6380
idx_col == 0 && continue
64-
push!(formatters, ft_printf_sigdigits_matching_se(data, idx_col, idx_se_col))
81+
push!(
82+
formatters, _prettytables_sigdigits_from_se_formatter(data, idx_col, idx_se_col)
83+
)
6584
end
6685
if !isempty(se_cols_inds)
67-
push!(formatters, ft_printf_sigdigits(sigdigits_se, se_cols_inds))
86+
push!(formatters, _prettytables_sigdigits_formatter(sigdigits_se, se_cols_inds))
6887
end
6988
return formatters
7089
end
7190

7291
function _prettytables_ess_formatter(data)
7392
cols = findall(_is_ess_label, Tables.columnnames(data))
7493
isempty(cols) && return nothing
75-
return PrettyTables.ft_printf("%d", cols)
94+
return _prettytables_printf_formatter("%d", cols)
7695
end
7796

7897
function _prettytables_rhat_formatter(data)
7998
col_names = Tables.columnnames(data)
8099
cols = findall(x -> (x === :rhat || startswith(string(x), "rhat_")), col_names)
81100
isempty(cols) && return nothing
82-
return PrettyTables.ft_printf("%.2f", cols)
101+
return _prettytables_printf_formatter("%.2f", cols)
83102
end
84103

85-
function _default_prettytables_formatters(data; sigdigits_se=2, sigdigits_default=3)
104+
function _prettytables_default_formatters(data; sigdigits_se=2, sigdigits_default=3)
86105
formatters = Union{Function,Nothing}[]
87106
push!(formatters, _prettytables_integer_formatter(data))
88107
append!(formatters, _prettytables_se_formatters(data; sigdigits_se))
89108
push!(formatters, _prettytables_ess_formatter(data))
90-
push!(formatters, ft_printf_sigdigits(sigdigits_default))
91-
push!(formatters, ft_printf_sigdigits_interval(sigdigits_default))
109+
push!(formatters, _prettytables_sigdigits_formatter(sigdigits_default))
110+
push!(formatters, _prettytables_interval_formatter(sigdigits_default))
92111
return filter(!isnothing, formatters)
93112
end
94113

@@ -102,14 +121,17 @@ function _text_alignment(data)
102121
end
103122

104123
function _text_alignment_anchor_regex(data)
105-
alignment_anchor_regex = Dict{Int,Vector{Regex}}()
124+
alignment_anchor_regex = Pair{Int,Vector{Regex}}[]
106125
for (i, k) in enumerate(Tables.columnnames(data))
107126
v = Tables.getcolumn(data, k)
108-
if eltype(v) <: Real && !(eltype(v) <: Integer) && !_is_ess_label(k)
109-
alignment_anchor_regex[i] = [r"\.", r"e", r"^NaN$", r"Inf$"]
127+
patterns = if eltype(v) <: Real && !(eltype(v) <: Integer) && !_is_ess_label(k)
128+
[r"\.", r"e", r"^NaN$", r"Inf$"]
110129
elseif eltype(v) <: IntervalSets.AbstractInterval
111-
alignment_anchor_regex[i] = [r"\.\."]
130+
[r"\.\."]
131+
else
132+
continue
112133
end
134+
push!(alignment_anchor_regex, i => patterns)
113135
end
114136
return alignment_anchor_regex
115137
end
@@ -123,25 +145,37 @@ function _show_prettytable(
123145
sigdigits_default=3,
124146
extra_formatters=(),
125147
alignment=_text_alignment(data),
126-
show_subheader=false,
127-
vcrop_mode=:middle,
128-
show_omitted_cell_summary=true,
129-
row_label_alignment=:l,
148+
show_first_column_label_only=true,
149+
vertical_crop_mode=:middle,
150+
row_label_column_alignment=:l,
130151
kwargs...,
131152
)
132-
formatters = (
153+
formatters = [
133154
extra_formatters...,
134-
_default_prettytables_formatters(data; sigdigits_se, sigdigits_default)...,
155+
_prettytables_default_formatters(data; sigdigits_se, sigdigits_default)...,
156+
]
157+
IS_PRETTYTABLES_V2 && return PrettyTables.pretty_table(
158+
io,
159+
data;
160+
alignment,
161+
formatters=Tuple(formatters),
162+
merge(
163+
(;
164+
show_subheader=(!show_first_column_label_only),
165+
vcrop_mode=vertical_crop_mode,
166+
row_label_alignment=row_label_column_alignment,
167+
),
168+
kwargs,
169+
)...,
135170
)
136171
PrettyTables.pretty_table(
137172
io,
138173
data;
139-
show_subheader,
140-
vcrop_mode,
141-
show_omitted_cell_summary,
142-
row_label_alignment,
143-
formatters,
174+
show_first_column_label_only,
175+
vertical_crop_mode,
176+
row_label_column_alignment,
144177
alignment,
178+
formatters,
145179
kwargs...,
146180
)
147181
return nothing
@@ -151,32 +185,49 @@ function _show_prettytable(
151185
io::IO,
152186
::MIME"text/plain",
153187
data;
154-
title_crayon=PrettyTables.Crayon(),
155-
hlines=:none,
156-
vlines=:none,
157-
newline_at_end=false,
188+
style=PRETTYTABLES_TEXT_STYLE,
189+
table_format=PRETTYTABLES_TEXT_FORMAT,
190+
new_line_at_end=false,
191+
title_alignment=:l,
158192
alignment_anchor_regex=_text_alignment_anchor_regex(data),
159193
alignment_anchor_fallback=:r,
160194
kwargs...,
161195
)
162-
return _show_prettytable(
196+
IS_PRETTYTABLES_V2 && return _show_prettytable(
163197
io,
164198
data;
165199
backend=Val(:text),
166-
title_crayon,
167-
hlines,
168-
vlines,
169-
newline_at_end,
200+
title_alignment,
201+
alignment_anchor_regex=Dict(alignment_anchor_regex),
202+
alignment_anchor_fallback,
203+
merge((; style..., table_format..., newline_at_end=new_line_at_end), kwargs)...,
204+
)
205+
return _show_prettytable(
206+
io,
207+
data;
208+
backend=:text,
209+
style,
210+
table_format,
211+
new_line_at_end,
212+
title_alignment,
170213
alignment_anchor_regex,
171214
alignment_anchor_fallback,
172215
kwargs...,
173216
)
174217
end
218+
175219
function _show_prettytable(
176-
io::IO, ::MIME"text/html", data; minify=true, max_num_of_rows=25, kwargs...
220+
io::IO, ::MIME"text/html", data; minify=true, maximum_number_of_rows=25, kwargs...
177221
)
222+
IS_PRETTYTABLES_V2 && return _show_prettytable(
223+
io,
224+
data;
225+
backend=Val(:html),
226+
minify,
227+
merge((; max_num_of_rows=maximum_number_of_rows), kwargs)...,
228+
)
178229
return _show_prettytable(
179-
io, data; backend=Val(:html), minify, max_num_of_rows, kwargs...
230+
io, data; backend=:html, minify, maximum_number_of_rows, kwargs...
180231
)
181232
end
182233

test/show_prettytable.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ using PosteriorStats
22
using Test
33

44
@testset "utilities for showing tables" begin
5-
@testset "ft_printf_sigdigits" begin
5+
@testset "_prettytables_sigdigits_formatter" begin
66
@testset "all columns" begin
77
@testset for sigdigits in 1:5
8-
ft1 = PosteriorStats.ft_printf_sigdigits(sigdigits)
8+
ft1 = PosteriorStats._prettytables_sigdigits_formatter(sigdigits)
99
for i in 1:10, j in 1:5
1010
v = randn()
1111
@test ft1(v, i, j) ==
@@ -16,7 +16,7 @@ using Test
1616
end
1717
@testset "subset of columns" begin
1818
@testset for sigdigits in 1:5
19-
ft = PosteriorStats.ft_printf_sigdigits(sigdigits, [2, 3])
19+
ft = PosteriorStats._prettytables_sigdigits_formatter(sigdigits, [2, 3])
2020
for i in 1:10, j in 1:5
2121
v = randn()
2222
if j [2, 3]
@@ -31,10 +31,10 @@ using Test
3131
end
3232
end
3333

34-
@testset "ft_printf_sigdigits_matching_se" begin
34+
@testset "_prettytables_sigdigits_from_se_formatter" begin
3535
data = (x=randn(10), x_se=rand(10), y=randn(10), y_se=rand(10))
3636
@testset for scale in 1:3, (col, se_col) in ((1, 2), (3, 4))
37-
ft = PosteriorStats.ft_printf_sigdigits_matching_se(data, 1, 2; scale)
37+
ft = PosteriorStats._prettytables_sigdigits_from_se_formatter(data, 1, 2; scale)
3838
for i in eachindex(values(data)...), j in eachindex(data)
3939
v = data[j][i]
4040
if j == col

0 commit comments

Comments
 (0)