Skip to content

Commit 8695b3f

Browse files
authored
improve printing of GroupedDataFrame in corner cases (#3187)
1 parent c43c8da commit 8695b3f

File tree

2 files changed

+50
-25
lines changed

2 files changed

+50
-25
lines changed

src/groupeddataframe/show.jl

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,42 @@ function Base.show(io::IO, gd::GroupedDataFrame;
4242

4343
(h, w) = displaysize(io)
4444

45+
# in the code below we accept that output for desired height less
46+
# than 15 does not have to always exactly match the passed value
4547
if h > 0
46-
h -= 2 # two lines are already used for header and gap between groups
47-
h <= 5 && (h = 5) # if too small to fit, print fully compact
48-
end
49-
50-
h1 = h2 = h # display heights available for first and last groups
51-
if N > 1 && h > 0
52-
53-
# line height of groups if printed in full (nrows + 3 extra for header)
54-
g1 = size(gd[1], 1) + 3
55-
g2 = size(gd[N], 1) + 3
56-
57-
if g1 + g2 > h # won't fit on screen
58-
if g1 < h ÷ 2
59-
h2 = h - g1 - 2 # show first group fully, squash last
60-
elseif g2 < h ÷ 2
61-
h1 = h - g2 - 2 # show last group fully, squash first
48+
# 2 lines for header and gap between groups, 3 lines for prompts;
49+
# correcting for this allows at least 8 lines (4 for each group)
50+
h = max(h - 5, 8)
51+
52+
if N == 1
53+
h1 = h + 3 # add two lines for prompts and one line as there is no gap between groups
54+
h2 = 0 # not used
55+
else
56+
# line height of groups if printed in full; 4 lines for header
57+
# we assume scenario where eltype is printed for simplicity
58+
g1 = size(gd[1], 1) + 4
59+
g2 = size(gd[N], 1) + 4
60+
# below +2 is for 2 lines for prompts as we do not print summary
61+
if g1 + g2 > h # won't fit on screen
62+
if g1 <= h ÷ 2
63+
h1 = g1 + 2
64+
h2 = h - g1 + 2 # show first group fully, squash last
65+
elseif g2 <= h ÷ 2
66+
h1 = h - g2 + 2 # show last group fully, squash first
67+
h2 = g2 + 2
68+
else
69+
# squash both groups
70+
h2 = h ÷ 2 + 2
71+
h1 = h - h2 + 4
72+
end
6273
else
63-
# squash both groups
64-
h += 1
65-
h2 = h ÷ 2
66-
h1 = h - h2
74+
h1 = g1 + 2
75+
h2 = g2 + 2
6776
end
6877
end
78+
else
79+
h1 = h # no limit
80+
h2 = h # no limit
6981
end
7082

7183
nrows = size(gd[1], 1)

test/show.jl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ end
261261
4 │ true true true
262262
5 │ true true true"""
263263

264-
show(io, groupby(df, :x), allcols=true, allrows=true)
264+
show(io, groupby(df, :x), allcols=true, allrows=true)
265265
str = String(take!(io.io))
266266
@test str == """
267267
GroupedDataFrame with 2 groups based on key: x
@@ -336,22 +336,35 @@ end
336336
end
337337

338338
# printed height always matches desired height, above a reasonable minimum
339-
for h in 15:40
339+
for a in 1:50, b in 1:50, h in 15:40
340+
df = DataFrame(x = [fill(1, a); fill(2, b)])
340341
io = IOContext(IOBuffer(), :displaysize=>(h, 40), :limit=>true)
341342
show(io, groupby(df, :x), allcols=true)
342343
str = String(take!(io.io))
343344
nlines = length(split(str, '\n'))
344-
desired = h - 3 # leave one line for last REPL prompt at top, two for new prompt
345+
# leave one line for last REPL prompt at top, two for new prompt
345346
# (this is the same behavior as ungrouped data frames)
347+
desired = min(a + b + 10, h - 3)
348+
@test nlines == desired
349+
end
350+
351+
for a in 1:50, h in 15:40
352+
df = DataFrame(x = fill(1, a))
353+
io = IOContext(IOBuffer(), :displaysize=>(h, 40), :limit=>true)
354+
show(io, groupby(df, :x), allcols=true)
355+
str = String(take!(io.io))
356+
nlines = length(split(str, '\n'))
357+
# leave one line for last REPL prompt at top, two for new prompt
358+
# (this is the same behavior as ungrouped data frames)
359+
desired = min(a + 5, h - 3)
346360
@test nlines == desired
347361
end
348362

349363
# one group
350364
io = IOContext(IOBuffer(), :displaysize=>(15, 40), :limit=>true)
351-
df = DataFrame(x = 1:15, y = 1)
365+
df = DataFrame(x = Int64.(1:15), y = Int64(1))
352366
show(io, groupby(df, :y))
353367
str = String(take!(io.io))
354-
print(str)
355368
@test str == """
356369
GroupedDataFrame with 1 group based on key: y
357370
First Group (15 rows): y = 1

0 commit comments

Comments
 (0)