diff --git a/NEWS.md b/NEWS.md
index 2f2a6af8e6..a17d83a61b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -67,3 +67,7 @@
([#2315](https://github.com/JuliaData/DataFrames.jl/pull/2315))
* add rich display support for Markdown cell entries in HTML and LaTeX
([#2346](https://github.com/JuliaData/DataFrames.jl/pull/2346))
+* limit the maximal display width the output can use in `text/plain` before
+ being truncated (in the `textwidth` sense, excluding `…`) to `32` per column
+ by default and fix a corner case when no columns are printed in situations when
+ they are too wide ([2403](https://github.com/JuliaData/DataFrames.jl/pull/2403))
diff --git a/src/abstractdataframe/io.jl b/src/abstractdataframe/io.jl
index eda9a60200..5035fbd247 100644
--- a/src/abstractdataframe/io.jl
+++ b/src/abstractdataframe/io.jl
@@ -98,7 +98,7 @@ function _show(io::IO, ::MIME"text/html", df::AbstractDataFrame;
if get(io, :limit, false)
tty_rows, tty_cols = displaysize(io)
mxrow = min(mxrow, tty_rows)
- maxwidths = getmaxwidths(df, io, 1:mxrow, 0:-1, :X, nothing, true, buffer) .+ 2
+ maxwidths = getmaxwidths(df, io, 1:mxrow, 0:-1, :X, nothing, true, buffer, 0) .+ 2
mxcol = min(mxcol, searchsortedfirst(cumsum(maxwidths), tty_cols))
end
@@ -148,11 +148,11 @@ function _show(io::IO, ::MIME"text/html", df::AbstractDataFrame;
write(io, "")
elseif cell_val isa SHOW_TABULAR_TYPES
write(io, "
")
- cell = sprint(ourshow, cell_val)
+ cell = sprint(ourshow, cell_val, 0)
write(io, html_escape(cell))
write(io, " | ")
else
- cell = sprint(ourshow, cell_val)
+ cell = sprint(ourshow, cell_val, 0)
write(io, "$(html_escape(cell)) | ")
end
else
@@ -270,7 +270,7 @@ function _show(io::IO, ::MIME"text/latex", df::AbstractDataFrame;
if get(io, :limit, false)
tty_rows, tty_cols = get(io, :displaysize, displaysize(io))
mxrow = min(mxrow, tty_rows)
- maxwidths = getmaxwidths(df, io, 1:mxrow, 0:-1, :X, nothing, true, buffer) .+ 2
+ maxwidths = getmaxwidths(df, io, 1:mxrow, 0:-1, :X, nothing, true, buffer, 0) .+ 2
mxcol = min(mxcol, searchsortedfirst(cumsum(maxwidths), tty_cols))
end
@@ -310,13 +310,13 @@ function _show(io::IO, ::MIME"text/latex", df::AbstractDataFrame;
print(io, strip(repr(MIME("text/latex"), cell)))
elseif cell isa SHOW_TABULAR_TYPES
print(io, "\\emph{")
- print(io, latex_escape(sprint(ourshow, cell, context=io)))
+ print(io, latex_escape(sprint(ourshow, cell, 0, context=io)))
print(io, "}")
else
if showable(MIME("text/latex"), cell)
show(io, MIME("text/latex"), cell)
else
- print(io, latex_escape(sprint(ourshow, cell, context=io)))
+ print(io, latex_escape(sprint(ourshow, cell, 0, context=io)))
end
end
end
@@ -386,7 +386,10 @@ end
#
##############################################################################
-escapedprint(io::IO, x::Any, escapes::AbstractString) = ourshow(io, x)
+escapedprint(io::IO, x::SHOW_TABULAR_TYPES, escapes::AbstractString) =
+ escapedprint(io, summary(x), escapes)
+escapedprint(io::IO, x::Any, escapes::AbstractString) =
+ escapedprint(io, sprint(print, x), escapes)
escapedprint(io::IO, x::AbstractString, escapes::AbstractString) =
escape_string(io, x, escapes)
@@ -427,7 +430,7 @@ function printtable(io::IO,
r = repr(cell)
escapedprint(io, chomp(r), quotestr)
print(io, quotemark)
- elseif ! (etypes[j] <: Real)
+ elseif !(etypes[j] <: Real)
print(io, quotemark)
escapedprint(io, cell, quotestr)
print(io, quotemark)
diff --git a/src/abstractdataframe/iteration.jl b/src/abstractdataframe/iteration.jl
index 7bb74cdac3..3805a0f4f2 100644
--- a/src/abstractdataframe/iteration.jl
+++ b/src/abstractdataframe/iteration.jl
@@ -252,11 +252,12 @@ function Base.show(io::IO, dfrs::DataFrameRows;
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true)
+ eltypes::Bool = true,
+ truncate::Int = 32)
df = parent(dfrs)
summary && print(io, "$(nrow(df))×$(ncol(df)) DataFrameRows")
_show(io, df, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=false, eltypes=eltypes)
+ rowlabel=rowlabel, summary=false, eltypes=eltypes, truncstring=truncate)
end
Base.show(io::IO, mime::MIME"text/plain", dfrs::DataFrameRows;
@@ -265,9 +266,10 @@ Base.show(io::IO, mime::MIME"text/plain", dfrs::DataFrameRows;
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(io, dfrs, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncate=truncate)
Base.show(dfrs::DataFrameRows;
allrows::Bool = !get(stdout, :limit, true),
@@ -275,9 +277,10 @@ Base.show(dfrs::DataFrameRows;
splitcols = get(stdout, :limit, true),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(stdout, dfrs, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncate=truncate)
function Base.show(io::IO, dfcs::DataFrameColumns;
allrows::Bool = !get(io, :limit, false),
@@ -285,11 +288,12 @@ function Base.show(io::IO, dfcs::DataFrameColumns;
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true)
+ eltypes::Bool = true,
+ truncate::Int = 32)
df = parent(dfcs)
summary && print(io, "$(nrow(df))×$(ncol(df)) DataFrameColumns")
_show(io, parent(dfcs), allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=false, eltypes=eltypes)
+ rowlabel=rowlabel, summary=false, eltypes=eltypes, truncstring=truncate)
end
Base.show(io::IO, mime::MIME"text/plain", dfcs::DataFrameColumns;
@@ -298,9 +302,10 @@ Base.show(io::IO, mime::MIME"text/plain", dfcs::DataFrameColumns;
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(io, dfcs, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncate=truncate)
Base.show(dfcs::DataFrameColumns;
allrows::Bool = !get(stdout, :limit, true),
@@ -308,9 +313,10 @@ Base.show(dfcs::DataFrameColumns;
splitcols = get(stdout, :limit, true),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(stdout, dfcs, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncate=truncate)
"""
mapcols(f::Union{Function,Type}, df::AbstractDataFrame)
diff --git a/src/abstractdataframe/show.jl b/src/abstractdataframe/show.jl
index 4bbc203943..7e23975f2c 100644
--- a/src/abstractdataframe/show.jl
+++ b/src/abstractdataframe/show.jl
@@ -3,24 +3,38 @@ Base.summary(df::AbstractDataFrame) =
Base.summary(io::IO, df::AbstractDataFrame) = print(io, summary(df))
"""
- DataFrames.ourstrwidth(io::IO, x::Any, buffer)
+ DataFrames.ourstrwidth(io::IO, x::Any, buffer::IOBuffer, truncstring::Int)
Determine the number of characters that would be used to print a value.
"""
-function ourstrwidth(io::IO, x::Any, buffer::IOBuffer)
+function ourstrwidth(io::IO, x::Any, buffer::IOBuffer, truncstring::Int)
truncate(buffer, 0)
- ourshow(IOContext(buffer, :compact=>get(io, :compact, true)), x)
+ ourshow(IOContext(buffer, :compact=>get(io, :compact, true)), x, truncstring)
return textwidth(String(take!(buffer)))
end
+function truncatestring(s::AbstractString, truncstring::Int)
+ truncstring <= 0 && return s
+ totalwidth = 0
+ for (i, c) in enumerate(s)
+ totalwidth += textwidth(c)
+ if totalwidth > truncstring
+ return first(s, i-1) * '…'
+ end
+ end
+ return s
+end
+
"""
- DataFrames.ourshow(io::IO, x::Any)
+ DataFrames.ourshow(io::IO, x::Any, truncstring::Int)
Render a value to an `IO` object compactly and omitting type information, by
calling 3-argument `show`, or 2-argument `show` if the former contains line breaks.
Unlike `show`, render strings without surrounding quote marks.
+`truncstring` indicates the approximate number of text characters width to truncate
+the output (if it is a non-positive value then no truncation is applied).
"""
-function ourshow(io::IO, x::Any; styled::Bool=false)
+function ourshow(io::IO, x::Any, truncstring::Int; styled::Bool=false)
io_ctx = IOContext(io, :compact=>get(io, :compact, true), :typeinfo=>typeof(x))
# This mirrors the behavior of Base.print_matrix_row
@@ -38,6 +52,8 @@ function ourshow(io::IO, x::Any; styled::Bool=false)
sx = escape_string(chop(sx, head=1, tail=1), "")
end
+ sx = truncatestring(sx, truncstring)
+
if styled
printstyled(io_ctx, sx, color=:light_black)
else
@@ -48,22 +64,27 @@ end
const SHOW_TABULAR_TYPES = Union{AbstractDataFrame, DataFrameRow, DataFrameRows,
DataFrameColumns, GroupedDataFrame}
-ourshow(io::IO, x::AbstractString) = escape_string(io, x, "")
-ourshow(io::IO, x::CategoricalValue{<:AbstractString}) = escape_string(io, get(x), "")
-ourshow(io::IO, x::Symbol) = ourshow(io, string(x))
-ourshow(io::IO, x::Nothing; styled::Bool=false) = ourshow(io, "", styled=styled)
-ourshow(io::IO, x::SHOW_TABULAR_TYPES; styled::Bool=false) =
- ourshow(io, summary(x), styled=styled)
-function ourshow(io::IO, x::Markdown.MD)
+ourshow(io::IO, x::AbstractString, truncstring::Int) =
+ escape_string(io, truncatestring(x, truncstring), "")
+ourshow(io::IO, x::CategoricalValue{<:AbstractString}, truncstring::Int) =
+ ourshow(io, get(x), truncstring)
+ourshow(io::IO, x::Symbol, truncstring::Int) = ourshow(io, string(x), truncstring)
+ourshow(io::IO, x::Nothing, truncstring::Int; styled::Bool=false) =
+ ourshow(io, "", styled=styled, truncstring)
+ourshow(io::IO, x::SHOW_TABULAR_TYPES, truncstring::Int; styled::Bool=false) =
+ ourshow(io, summary(x), truncstring, styled=styled)
+
+function ourshow(io::IO, x::Markdown.MD, truncstring::Int)
r = repr(x)
- len = min(length(r, 1, something(findfirst(==('\n'), r), lastindex(r)+1)-1), 32)
+ truncstring <= 0 && return chomp(truncstring)
+ len = min(length(r, 1, something(findfirst(==('\n'), r), lastindex(r)+1)-1), truncstring)
return print(io, len < length(r) - 1 ? first(r, len)*'…' : first(r, len))
end
# AbstractChar: https://github.com/JuliaLang/julia/pull/34730 (1.5.0-DEV.261)
# Irrational: https://github.com/JuliaLang/julia/pull/34741 (1.5.0-DEV.266)
if VERSION < v"1.5.0-DEV.261" || VERSION < v"1.5.0-DEV.266"
- function ourshow(io::IO, x::T) where T <: Union{AbstractChar, Irrational}
+ function ourshow(io::IO, x::T, truncstring::Int) where T <: Union{AbstractChar, Irrational}
io = IOContext(io, :compact=>get(io, :compact, true), :typeinfo=>typeof(x))
show(io, x)
end
@@ -164,38 +185,43 @@ function getmaxwidths(df::AbstractDataFrame,
rowlabel::Symbol,
rowid::Union{Integer, Nothing},
show_eltype::Bool,
- buffer::IOBuffer)
+ buffer::IOBuffer,
+ truncstring::Int)
maxwidths = Vector{Int}(undef, size(df, 2) + 1)
- undefstrwidth = ourstrwidth(io, "#undef", buffer)
+ undefstrwidth = ourstrwidth(io, "#undef", buffer, truncstring)
j = 1
for (name, col) in pairs(eachcol(df))
# (1) Consider length of column name
- maxwidth = ourstrwidth(io, name, buffer)
+ # do not truncate column name
+ maxwidth = ourstrwidth(io, name, buffer, 0)
# (2) Consider length of longest entry in that column
for indices in (rowindices1, rowindices2), i in indices
if isassigned(col, i)
- maxwidth = max(maxwidth, ourstrwidth(io, col[i], buffer))
+ maxwidth = max(maxwidth, ourstrwidth(io, col[i], buffer, truncstring))
else
maxwidth = max(maxwidth, undefstrwidth)
end
end
if show_eltype
- maxwidths[j] = max(maxwidth, ourstrwidth(io, compacttype(eltype(col)), buffer))
+ # do not truncate eltype name
+ maxwidths[j] = max(maxwidth, ourstrwidth(io, compacttype(eltype(col)), buffer, 0))
else
maxwidths[j] = maxwidth
end
j += 1
end
+ # do not truncate rowlabel
if rowid isa Nothing
rowmaxwidth1 = isempty(rowindices1) ? 0 : ndigits(maximum(rowindices1))
rowmaxwidth2 = isempty(rowindices2) ? 0 : ndigits(maximum(rowindices2))
- maxwidths[j] = max(max(rowmaxwidth1, rowmaxwidth2), ourstrwidth(io, rowlabel, buffer))
+ maxwidths[j] = max(max(rowmaxwidth1, rowmaxwidth2),
+ ourstrwidth(io, rowlabel, buffer, 0))
else
- maxwidths[j] = max(ndigits(rowid), ourstrwidth(io, rowlabel, buffer))
+ maxwidths[j] = max(ndigits(rowid), ourstrwidth(io, rowlabel, buffer, 0))
end
return maxwidths
@@ -320,7 +346,8 @@ function showrowindices(io::IO,
leftcol::Int,
rightcol::Int,
rowid::Union{Integer, Nothing},
- buffer::IOBuffer)
+ buffer::IOBuffer,
+ truncstring::Int)
rowmaxwidth = maxwidths[end]
for i in rowindices
@@ -340,15 +367,15 @@ function showrowindices(io::IO,
strlen = 0
if isassigned(df[!, j], i)
s = df[i, j]
- strlen = ourstrwidth(io, s, buffer)
+ strlen = ourstrwidth(io, s, buffer, truncstring)
if ismissing(s) || s isa SHOW_TABULAR_TYPES
- ourshow(io, s, styled=true)
+ ourshow(io, s, truncstring, styled=true)
else
- ourshow(io, s)
+ ourshow(io, s, truncstring)
end
else
- strlen = ourstrwidth(io, "#undef", buffer)
- ourshow(io, "#undef", styled=true)
+ strlen = ourstrwidth(io, "#undef", buffer, truncstring)
+ ourshow(io, "#undef", truncstring, styled=true)
end
padding = maxwidths[j] - strlen
for _ in 1:padding
@@ -441,7 +468,8 @@ function showrows(io::IO,
displaysummary::Bool,
eltypes::Bool,
rowid::Union{Integer, Nothing},
- buffer::IOBuffer)
+ buffer::IOBuffer,
+ truncstring::Int)
ncols = size(df, 2)
@@ -457,26 +485,39 @@ function showrows(io::IO,
nchunks = allcols ? length(chunkbounds) - 1 : min(length(chunkbounds) - 1, 1)
header = displaysummary ? summary(df) : ""
+ cols_other_chunks = chunkbounds[end] - chunkbounds[2]
if !allcols && length(chunkbounds) > 2
- header *= ". Omitted printing of $(chunkbounds[end] - chunkbounds[2]) columns"
+ # if we print only one chunk and it does not fit the screen give up
+ if cols_other_chunks == ncols
+ print(io, header * ". Omitted printing of all columns as they do " *
+ "not fit the display size")
+ return
+ end
+ header *= ". Omitted printing of $cols_other_chunks columns"
end
+
println(io, header)
for chunkindex in 1:nchunks
leftcol = chunkbounds[chunkindex] + 1
rightcol = chunkbounds[chunkindex + 1]
+ # nothing to print in this chunk
+ leftcol > rightcol && continue
+
# Print column names
@printf io "│ %s" rowlabel
- padding = rowmaxwidth - ourstrwidth(io, rowlabel, buffer)
+ # do not truncate rowlabel
+ padding = rowmaxwidth - ourstrwidth(io, rowlabel, buffer, 0)
for itr in 1:padding
write(io, ' ')
end
print(io, " │ ")
for j in leftcol:rightcol
s = _names(df)[j]
- ourshow(io, s)
- padding = maxwidths[j] - ourstrwidth(io, s, buffer)
+ # do not truncate column names
+ ourshow(io, s, 0)
+ padding = maxwidths[j] - ourstrwidth(io, s, buffer, 0)
for itr in 1:padding
write(io, ' ')
end
@@ -498,7 +539,8 @@ function showrows(io::IO,
for j in leftcol:rightcol
s = compacttype(eltype(df[!, j]), maxwidths[j], false)
printstyled(io, s, color=:light_black)
- padding = maxwidths[j] - ourstrwidth(io, s, buffer)
+ # do not truncate eltype
+ padding = maxwidths[j] - ourstrwidth(io, s, buffer, 0)
for itr in 1:padding
write(io, ' ')
end
@@ -529,23 +571,13 @@ function showrows(io::IO,
write(io, '\n')
# Print main table body, potentially in two abbreviated sections
- showrowindices(io,
- df,
- rowindices1,
- maxwidths,
- leftcol,
- rightcol,
- rowid, buffer)
+ showrowindices(io, df, rowindices1, maxwidths, leftcol, rightcol,
+ rowid, buffer, truncstring)
if !isempty(rowindices2)
print(io, "\n⋮\n")
- showrowindices(io,
- df,
- rowindices2,
- maxwidths,
- leftcol,
- rightcol,
- rowid, buffer)
+ showrowindices(io, df, rowindices2, maxwidths, leftcol, rightcol,
+ rowid, buffer, truncstring)
end
# Print newlines to separate chunks
@@ -565,7 +597,8 @@ function _show(io::IO,
rowlabel::Symbol = :Row,
summary::Bool = true,
eltypes::Bool = true,
- rowid=nothing)
+ rowid=nothing,
+ truncstring::Int)
_check_consistency(df)
# we will pass around this buffer to avoid its reallocation in ourstrwidth
@@ -590,19 +623,11 @@ function _show(io::IO,
rowindices1 = 1:bound
rowindices2 = max(bound + 1, nrows - nrowssubset + 1):nrows
end
- maxwidths = getmaxwidths(df, io, rowindices1, rowindices2, rowlabel, rowid, eltypes, buffer)
+ maxwidths = getmaxwidths(df, io, rowindices1, rowindices2, rowlabel, rowid,
+ eltypes, buffer, truncstring)
width = getprintedwidth(maxwidths)
- showrows(io,
- df,
- rowindices1,
- rowindices2,
- maxwidths,
- splitcols,
- allcols,
- rowlabel,
- summary,
- eltypes,
- rowid, buffer)
+ showrows(io, df, rowindices1, rowindices2, maxwidths, splitcols, allcols,
+ rowlabel, summary, eltypes, rowid, buffer, truncstring)
return
end
@@ -614,7 +639,8 @@ end
splitcols::Bool = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true)
+ eltypes::Bool = true,
+ truncate::Int = 32)
Render a data frame to an I/O stream. The specific visual
representation chosen depends on the width of the display.
@@ -643,6 +669,9 @@ while `splitcols` defaults to `true`.
- `rowlabel::Symbol = :Row`: The label to use for the column containing row numbers.
- `summary::Bool = true`: Whether to print a brief string summary of the data frame.
- `eltypes::Bool = true`: Whether to print the column types under column names.
+- `truncate::Int = 32`: the maximal display width the output can use before
+ being truncated (in the `textwidth` sense, excluding `…`).
+ If `truncate` is 0 or less, no truncation is applied.
# Examples
```jldoctest
@@ -667,9 +696,10 @@ Base.show(io::IO,
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
_show(io, df, allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncstring=truncate)
Base.show(df::AbstractDataFrame;
allrows::Bool = !get(stdout, :limit, true),
@@ -677,7 +707,8 @@ Base.show(df::AbstractDataFrame;
splitcols = get(stdout, :limit, true),
rowlabel::Symbol = :Row,
summary::Bool = true,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(stdout, df,
allrows=allrows, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=summary, eltypes=eltypes)
+ rowlabel=rowlabel, summary=summary, eltypes=eltypes, truncate=truncate)
diff --git a/src/dataframerow/show.jl b/src/dataframerow/show.jl
index ba7c030d64..a4b2016a83 100644
--- a/src/dataframerow/show.jl
+++ b/src/dataframerow/show.jl
@@ -2,25 +2,28 @@ function Base.show(io::IO, dfr::DataFrameRow;
allcols::Bool = !get(io, :limit, false),
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
- eltypes::Bool = true)
+ eltypes::Bool = true,
+ truncate::Int = 32)
r, c = parentindices(dfr)
print(io, "DataFrameRow")
_show(io, view(parent(dfr), [r], c), allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, summary=false, rowid=r, eltypes=eltypes)
+ rowlabel=rowlabel, summary=false, rowid=r, eltypes=eltypes, truncstring=truncate)
end
Base.show(io::IO, mime::MIME"text/plain", dfr::DataFrameRow;
allcols::Bool = !get(io, :limit, false),
splitcols = get(io, :limit, false),
rowlabel::Symbol = :Row,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(io, dfr, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, eltypes=eltypes)
+ rowlabel=rowlabel, eltypes=eltypes, truncate=truncate)
Base.show(dfr::DataFrameRow;
allcols::Bool = !get(stdout, :limit, true),
splitcols = get(stdout, :limit, true),
rowlabel::Symbol = :Row,
- eltypes::Bool = true) =
+ eltypes::Bool = true,
+ truncate::Int = 32) =
show(stdout, dfr, allcols=allcols, splitcols=splitcols,
- rowlabel=rowlabel, eltypes=eltypes)
+ rowlabel=rowlabel, eltypes=eltypes, truncate=truncate)
diff --git a/src/groupeddataframe/show.jl b/src/groupeddataframe/show.jl
index aeab3c1938..37948d957c 100644
--- a/src/groupeddataframe/show.jl
+++ b/src/groupeddataframe/show.jl
@@ -12,7 +12,8 @@ function Base.show(io::IO, gd::GroupedDataFrame;
allcols::Bool = !get(io, :limit, false),
splitcols::Bool = get(io, :limit, false),
rowlabel::Symbol = :Row,
- summary::Bool = true)
+ summary::Bool = true,
+ truncate::Int = 32)
N = length(gd)
summary && Base.summary(io, gd)
@@ -29,7 +30,7 @@ function Base.show(io::IO, gd::GroupedDataFrame;
join(io, identified_groups, ", ")
show(io, gd[i], summary=false,
- allrows=allrows, allcols=allcols, rowlabel=rowlabel)
+ allrows=allrows, allcols=allcols, rowlabel=rowlabel, truncate=truncate)
end
else
if N > 0
@@ -43,7 +44,7 @@ function Base.show(io::IO, gd::GroupedDataFrame;
join(io, identified_groups, ", ")
show(io, gd[1], summary=false,
- allrows=allrows, allcols=allcols, rowlabel=rowlabel)
+ allrows=allrows, allcols=allcols, rowlabel=rowlabel, truncate=truncate)
end
if N > 1
nrows = size(gd[N], 1)
@@ -56,7 +57,7 @@ function Base.show(io::IO, gd::GroupedDataFrame;
join(io, identified_groups, ", ")
show(io, gd[N], summary=false,
- allrows=allrows, allcols=allcols, rowlabel=rowlabel)
+ allrows=allrows, allcols=allcols, rowlabel=rowlabel, truncate=truncate)
end
end
end
@@ -67,8 +68,9 @@ function Base.show(df::GroupedDataFrame;
allgroups::Bool = !get(stdout, :limit, true),
splitcols::Bool = get(stdout, :limit, true),
rowlabel::Symbol = :Row,
- summary::Bool = true) # -> Nothing
+ summary::Bool = true,
+ truncate::Int = 32) # -> Nothing
return show(stdout, df,
allrows=allrows, allcols=allcols, allgroups=allgroups,
- splitcols=splitcols, rowlabel=rowlabel, summary=summary)
+ splitcols=splitcols, rowlabel=rowlabel, summary=summary, truncate=truncate)
end
diff --git a/test/io.jl b/test/io.jl
index 6df042e064..99bf28dc88 100644
--- a/test/io.jl
+++ b/test/io.jl
@@ -180,9 +180,9 @@ end
@test sprint(DataFrames.printtable, df) ==
"""
"A","B","C","D","E","F","G","H"
- 1,"'a'","A","a","A","1",missing,missing
- 2,"'b'","B","b","B","2",missing,missing
- 3,"'c'","C","c",missing,"3",missing,missing
+ 1,"a","A","a","A","1",missing,missing
+ 2,"b","B","b","B","2",missing,missing
+ 3,"c","C","c",missing,"3",missing,missing
"""
end
@@ -531,18 +531,18 @@ end
@test str == """
9×2 DataFrame
- │ Row │ A │ B │
- │ │ Int64 │ Any │
- ├─────┼───────┼────────────────────────────────────────────────┤
- │ 1 │ 1 │ 9×2 DataFrame │
- │ 2 │ 2 │ 2-element DataFrameRow │
- │ 3 │ 3 │ 1×2 SubDataFrame │
- │ 4 │ 4 │ 9-element DataFrameRows │
- │ 5 │ 5 │ 2-element DataFrameColumns │
- │ 6 │ 6 │ GroupedDataFrame with 9 groups based on key: A │
- │ 7 │ 7 │ missing │
- │ 8 │ 8 │ │
- │ 9 │ 9 │ #undef │"""
+ │ Row │ A │ B │
+ │ │ Int64 │ Any │
+ ├─────┼───────┼───────────────────────────────────┤
+ │ 1 │ 1 │ 9×2 DataFrame │
+ │ 2 │ 2 │ 2-element DataFrameRow │
+ │ 3 │ 3 │ 1×2 SubDataFrame │
+ │ 4 │ 4 │ 9-element DataFrameRows │
+ │ 5 │ 5 │ 2-element DataFrameColumns │
+ │ 6 │ 6 │ GroupedDataFrame with 9 groups b… │
+ │ 7 │ 7 │ missing │
+ │ 8 │ 8 │ │
+ │ 9 │ 9 │ #undef │"""
io = IOBuffer()
@@ -550,18 +550,18 @@ end
str = String(take!(io))
@test str == """
9×2 DataFrame
- │ Row │ A │ B │
- │ │ \e[90mInt64\e[39m │ \e[90mAny\e[39m │
- ├─────┼───────┼────────────────────────────────────────────────┤
- │ 1 │ 1 │ \e[90m9×2 DataFrame\e[39m │
- │ 2 │ 2 │ \e[90m2-element DataFrameRow\e[39m │
- │ 3 │ 3 │ \e[90m1×2 SubDataFrame\e[39m │
- │ 4 │ 4 │ \e[90m9-element DataFrameRows\e[39m │
- │ 5 │ 5 │ \e[90m2-element DataFrameColumns\e[39m │
- │ 6 │ 6 │ \e[90mGroupedDataFrame with 9 groups based on key: A\e[39m │
- │ 7 │ 7 │ \e[90mmissing\e[39m │
- │ 8 │ 8 │ │
- │ 9 │ 9 │ \e[90m#undef\e[39m │"""
+ │ Row │ A │ B │
+ │ │ \e[90mInt64\e[39m │ \e[90mAny\e[39m │
+ ├─────┼───────┼───────────────────────────────────┤
+ │ 1 │ 1 │ \e[90m9×2 DataFrame\e[39m │
+ │ 2 │ 2 │ \e[90m2-element DataFrameRow\e[39m │
+ │ 3 │ 3 │ \e[90m1×2 SubDataFrame\e[39m │
+ │ 4 │ 4 │ \e[90m9-element DataFrameRows\e[39m │
+ │ 5 │ 5 │ \e[90m2-element DataFrameColumns\e[39m │
+ │ 6 │ 6 │ \e[90mGroupedDataFrame with 9 groups b…\e[39m │
+ │ 7 │ 7 │ \e[90mmissing\e[39m │
+ │ 8 │ 8 │ │
+ │ 9 │ 9 │ \e[90m#undef\e[39m │"""
io = IOBuffer()
@@ -604,35 +604,143 @@ end
@test_throws UndefRefError show(io, MIME("text/csv"), df)
@test_throws UndefRefError show(io, MIME("text/tab-separated-values"), df)
+ df[end, 2] = "\""
+ push!(df, (10, Symbol("\"")))
+ push!(df, (11, '"'))
io = IOBuffer()
- show(io, MIME("text/csv"), df[1:end-1, :])
+ show(io, MIME("text/csv"), df)
str = String(take!(io))
@test str == """
"A","B"
- 1,"9×2 DataFrame"
+ 1,"11×2 DataFrame"
2,"2-element DataFrameRow"
3,"1×2 SubDataFrame"
- 4,"9-element DataFrameRows"
+ 4,"11-element DataFrameRows"
5,"2-element DataFrameColumns"
6,"GroupedDataFrame with 9 groups based on key: A"
7,missing
8,nothing
+ 9,"\\""
+ 10,"\\""
+ 11,"\\""
"""
io = IOBuffer()
- show(io, MIME("text/tab-separated-values"), df[1:end-1, :])
+ show(io, MIME("text/tab-separated-values"), df)
str = String(take!(io))
@test str == """
"A"\t"B"
- 1\t"9×2 DataFrame"
+ 1\t"11×2 DataFrame"
2\t"2-element DataFrameRow"
3\t"1×2 SubDataFrame"
- 4\t"9-element DataFrameRows"
+ 4\t"11-element DataFrameRows"
5\t"2-element DataFrameColumns"
6\t"GroupedDataFrame with 9 groups based on key: A"
7\tmissing
8\tnothing
+ 9\t"\\""
+ 10\t"\\""
+ 11\t"\\""
"""
end
+@testset "check truncate keyword argument" begin
+ df = DataFrame(x = "0123456789"^10)
+
+ # no truncation
+ io = IOBuffer()
+ show(io, MIME("text/html"), df)
+ str = String(take!(io))
+ @test str == " | x |
" *
+ " | String |
" *
+ "1 rows × 1 columns
1 | " *
+ "01234567890123456789012345678901234567890123456789" *
+ "01234567890123456789012345678901234567890123456789 | "*
+ "
---|
"
+
+ # no truncation
+ io = IOBuffer()
+ show(io, MIME("text/latex"), df)
+ str = String(take!(io))
+ @test str == """
+ \\begin{tabular}{r|c}
+ \t& x\\\\
+ \t\\hline
+ \t& String\\\\
+ \t\\hline
+ \t1 & 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 \\\\
+ \\end{tabular}
+ """
+
+ # no truncation
+ io = IOBuffer()
+ show(io, MIME("text/csv"), df)
+ str = String(take!(io))
+ @test str == "\"x\"\n\"01234567890123456789012345678901234567890123456789" *
+ "01234567890123456789012345678901234567890123456789\"\n"
+
+ # no truncation
+ io = IOBuffer()
+ show(io, MIME("text/tab-separated-values"), df)
+ str = String(take!(io))
+ @test str == "\"x\"\n\"01234567890123456789012345678901234567890123456789" *
+ "01234567890123456789012345678901234567890123456789\"\n"
+
+ # default truncation
+ io = IOBuffer()
+ show(io, MIME("text/plain"), df)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 01234567890123456789012345678901… │"""
+
+ io = IOBuffer()
+ show(io, df)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 01234567890123456789012345678901… │"""
+
+ # no truncation
+ io = IOBuffer()
+ show(io, df, truncate=0)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ 1 │ 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 │"""
+
+ # custom truncation
+ io = IOBuffer()
+ show(io, df, truncate=1)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼────────┤
+ │ 1 │ 0… │"""
+
+
+ df = DataFrame(x12345678901234567890 = "0123456789"^10)
+ io = IOBuffer()
+ show(io, df, truncate=1, rowlabel=:r12345678901234567890)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ r12345678901234567890 │ x12345678901234567890 │
+ │ │ String │
+ ├───────────────────────┼───────────────────────┤
+ │ 1 │ 0… │"""
+
+end
+
end # module
diff --git a/test/show.jl b/test/show.jl
index c8392d3bc7..be6d563833 100644
--- a/test/show.jl
+++ b/test/show.jl
@@ -500,4 +500,49 @@ end
│ 1 │ 1:2 │"""
end
+@testset "wide output and column trimming" begin
+ df = DataFrame(x = "0123456789"^4)
+ io = IOBuffer()
+ show(io, df)
+ str = String(take!(io))
+ @test str == """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 01234567890123456789012345678901… │"""
+
+ io = IOContext(IOBuffer(), :displaysize=>(10,10), :limit=>true)
+ show(io, df)
+ str = String(take!(io.io))
+ @test str === "1×1 DataFrame. Omitted printing of all columns as they do not fit the display size"
+
+ df = DataFrame(x = "0123456789"^4, y = "0123456789"^4)
+ io = IOContext(IOBuffer(), :displaysize=>(10,10), :limit=>true)
+ show(io, df, splitcols=true, allcols=true)
+ str = String(take!(io.io))
+ @test str === """
+ 1×2 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 01234567890123456789012345678901… │
+
+ │ Row │ y │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 01234567890123456789012345678901… │"""
+
+ df = DataFrame(x = "😄"^20)
+ io = IOBuffer()
+ show(io, df)
+ str = String(take!(io))
+ @test str === """
+ 1×1 DataFrame
+ │ Row │ x │
+ │ │ String │
+ ├─────┼───────────────────────────────────┤
+ │ 1 │ 😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄😄… │"""
+end
+
end # module