Skip to content

Commit

Permalink
modernize the show function to use iterator protocol
Browse files Browse the repository at this point in the history
much code cleanup here
  • Loading branch information
dysonance committed Aug 15, 2018
1 parent 9973e91 commit b166e31
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 74 deletions.
1 change: 1 addition & 0 deletions src/io.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Temporal
using JSON
if VERSION >= v"0.7-"
using Printf # needed for @sprintf macro
using Dates
else
using Base.Dates
Expand Down
121 changes: 47 additions & 74 deletions src/show.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
if VERSION >= v"0.7-"
using Printf # needed for @sprintf macro
end

# const SHOWROWS = 5 # number of rows to print at beginning and end
const DECIMALS = 4 # the maximum number of decimals to show
const DECIMALS = 4 # the maximum number of decimals to show
const PADDING = 2 # number of spaces minimum between fields
const SHOWINT = false # whether to format integer columns without decimals

str_width(s::AbstractString) = length(s)
str_width(s::Symbol) = length(string(s))
Expand All @@ -17,16 +11,6 @@ str_width(::Missing) = 7

_round(x, n=4) = ismissing(x) ? missing : round(x, digits=n)

function print_summary(io::IO, x::TS{V,T}) where {V,T}
if isempty(x)
println(@sprintf("Empty %s", typeof(x)))
return 0
else
println(@sprintf("%ix%i %s: %s to %s", size(x,1), size(x,2), typeof(x), x.index[1], x.index[end]))
return 1
end
end

function getshowrows(io::IO, x::TS{V,T}) where {V,T}
nrow = size(x,1)
dims = displaysize(io)
Expand All @@ -38,75 +22,64 @@ function getshowrows(io::IO, x::TS{V,T}) where {V,T}
end
end

function getwidths(io::IO, x::TS{V,T}) where {V,T}
widths = [T==Date ? 10 : 19; str_width.(x.fields)]
toprows, botrows = getshowrows(io, x)
vals = [x.values[toprows,:]; x.values[botrows,:]]
function getwidths(io::IO, X::TS{V,T}, padding::Int) where {V,T}
width_index = T==Date ? 10 : 19
width_values = str_width.(X.fields)
if V <: Bool
widths[2:end] .= 5
width_values .= 5
elseif V <: Number
@inbounds for j in 1:size(x,2)
widths[j+1] = max(widths[j+1], maximum(str_width.(_round.(vals[:,j], DECIMALS))))
@inbounds for j in 1:size(X,2)
width_values[j] = max(width_values[j], maximum(str_width.(_round.(X.values[:,j], DECIMALS))))
end
else
@inbounds for j in 1:size(x,2)
widths[j+1] = max(widths[j+1], maximum(str_width.(vals[:,j])))
@inbounds for j in 1:size(X,2)
width_values[j] = max(width_values[j], maximum(str_width.(X.values[:,j])))
end
end
return widths
return width_index + padding, width_values .+ padding
end

hasnegs(v::Vector) = eltype(v)<:Number ? any(v.<zero(eltype(v))) : false
hasnegs(x::Vector)::Bool = eltype(x)<:Number ? any(x.<zero(eltype(x))) : false
hasnegs(X::Matrix)::Vector{Bool} = [hasnegs(X[:,j]) for j in 1:size(X,2)]

function getnegs(io::IO, x::TS)
toprows, botrows = getshowrows(io, x)
idx = [toprows; botrows]
return [hasnegs(x.values[:,j]) for j in 1:size(x,2)]
end

print_header(x::TS, widths::Vector{Int}, negs::Vector{Bool}) = prod(rpad.(["Index"; lpad.(string.(x.fields), str_width.(x.fields).+negs)], widths))

pos_or_missing(x) = [(ismissing(x) || x >= 0.0) for x in x]

function print_row(x::TS{V,T}, row::Int, widths::Vector{Int}, negs::Vector{Bool}) where {V,T}
if V <: Bool
return prod(rpad.([string(x.index[row]); [" "].^(negs .* pos_or_missing(x.values[row,:])) .* string.(x.values[row,:])], widths))
elseif V <: Number
return prod(rpad.([string(x.index[row]); [" "].^(negs .* pos_or_missing(x.values[row,:])) .* string.(_round.(x.values[row,:], DECIMALS))], widths))
function show(io::IO, X::TS, padding::Int=PADDING, digits::Int=DECIMALS)::Nothing
# print summary of data structure
if (isempty(X))
print("Empty $(typeof(X))\n")
return nothing
else
return prod(rpad.([string(x.index[row]); string.(x.values[row,:])], widths))
print("$(size(X,1))x$(size(X,2)) $(typeof(X)): $(X.index[1]) to $(X.index[end])\n\n")
end
end

function print_rows(io::IO, x::TS, widths::Vector{Int}=getwidths(io,x).+PADDING, negs::Vector{Bool}=getnegs(io,x))
# negs = getnegs(io,x)
# widths = getwidths(io,x) .+ PADDING
nrow = size(x,1)
ncol = size(x,2)
toprows, botrows = getshowrows(io,x)
if nrow > 1
@inbounds for row in toprows
println(io, print_row(x, row, widths, negs))
# partition rows if data too large
toprows, bottomrows = getshowrows(io, X)
negatives = hasnegs(X.values)
width_index, width_values = getwidths(io, X, padding)
headerline = [rpad("Index", width_index); [rpad(string(X.fields[j]), width_values[j]) for j in 1:size(X,2)]]
print(io, join(headerline), '\n')
if toprows[end] == bottomrows[1] - 1
@inbounds for (t, x) in X
datarow = [
rpad(t, width_index);
[rpad(string(round(x[j], digits=digits)), width_values[j]) for j in 1:size(X,2)]
]
print(io, join(datarow), '\n')
end
if toprows[end] < botrows[1] - 1
println(io, "")
else
@inbounds for (t, x) in X[toprows]
datarow = [
rpad(t, width_index);
[rpad(string(round(x[j], digits=digits)), width_values[j]) for j in 1:size(X,2)]
]
print(io, join(datarow), '\n')
end
print(io, "\n")
@inbounds for (t, x) in X[bottomrows]
datarow = [
rpad(t, width_index);
[rpad(string(round(x[j], digits=digits)), width_values[j]) for j in 1:size(X,2)]
]
print(io, join(datarow), '\n')
end
end
@inbounds for row in botrows[1:end-1]
println(io, print_row(x, row, widths, negs))
end
print(io, print_row(x, botrows[end], widths, negs))
nothing
end

function show(io::IO, x::TS{V,T}) where {V,T}
if print_summary(io, x) == 0
return nothing
end
# println() # print whitespace before actualy data starts to improve readability
widths = getwidths(io, x) .+ PADDING
negs = getnegs(io, x)
println(io, print_header(x, widths, negs))
print_rows(io, x, widths, negs)
nothing
return nothing
end

0 comments on commit b166e31

Please sign in to comment.