From b166e31aed08797ba52a1df348655853f3dbbfd7 Mon Sep 17 00:00:00 2001 From: Jacob Amos Date: Wed, 15 Aug 2018 19:42:01 -0400 Subject: [PATCH] modernize the show function to use iterator protocol much code cleanup here --- src/io.jl | 1 + src/show.jl | 121 ++++++++++++++++++++-------------------------------- 2 files changed, 48 insertions(+), 74 deletions(-) diff --git a/src/io.jl b/src/io.jl index 14d76ea..ce2aa63 100644 --- a/src/io.jl +++ b/src/io.jl @@ -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 diff --git a/src/show.jl b/src/show.jl index dafaca1..002fda4 100644 --- a/src/show.jl +++ b/src/show.jl @@ -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)) @@ -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) @@ -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.= 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