HSG-MCS-HS21_Julia/Exam1/jlFiles/printmat.jl
2021-11-15 21:14:51 +01:00

247 lines
8.1 KiB
Julia

#------------------------------------------------------------------------------
"""
printmat([fh::IO],x...;colNames=[],rowNames=[],
width=10,prec=3,NoPrinting=false,StringFmt="",cell00="")
Print all elements of a matrix (or several) with predefined formatting. It can also handle
OffsetArrays. StringFmt = "csv" prints using a csv format.
# Input
- `fh::IO`: (optional) file handle. If not supplied, prints to screen
- `x::Array(s)`: (of numbers, dates, strings, ...) to print
- `colNames::Array`: of strings with column headers
- `rowNames::Array`: of strings with row labels
- `width::Int`: (keyword) scalar, minimum width of printed cells
- `prec::Int`: (keyword) scalar, precision of printed cells
- `NoPrinting::Bool`: (keyword) bool, true: no printing, just return formatted string [false]
- `StringFmt::String`: (keyword) string, "", "csv"
- `cell00::String`: (keyword) string, for row 0, column 0
# Output
- str (if NoPrinting) string, (otherwise nothing)
# Examples
```
x = [11 12;21 22]
printmat(x)
```
```
x = [1 "ab"; Date(2018,10,7) 3.14]
printmat(x,width=20,colNames=["col 1","col 2"])
```
```
printmat([11,12],[21,22])
```
Can also call as
```
opt = Dict(:rowNames=>["1";"4"],:width=>10,:prec=>3,:NoPrinting=>false,:StringFmt=>"")
printmat(x;colNames=["a","b"],opt...) #notice ; and ...
```
(not all keywords are needed)
# Requires
- fmtNumPs
# Notice
- The prefixN and suffixN could potentially be made function inputs. This would allow
a fairly flexible way to format tables.
Paul.Soderlind@unisg.ch
"""
function printmat(fh::IO,x...;colNames=[],rowNames=[],
width=10,prec=3,NoPrinting=false,StringFmt="",cell00="")
isempty(x) && return nothing #do nothing is isempty(x)
typeTestQ = any(!=(eltype(x[1])),[eltype(z) for z in x]) #test if eltype(x[i]) differs
if typeTestQ #create matrix from tuple created by x...
x = hcat(Matrix{Any}(hcat(x[1])),x[2:end]...) #preserving types of x[i]
else
x = hcat(x...)
end
(m,n) = (size(x,1),size(x,2))
(length(rowNames) == 1 < m) && (rowNames = [string(rowNames[1],i) for i = 1:m]) #"ri"
(length(colNames) == 1 < n) && (colNames = [string(colNames[1],i) for i = 1:n]) #"ci"
if StringFmt == "csv"
(prefixN,suffixN) = (fill("",n),vcat(fill(",",n-1),"")) #prefix and suffix for column 1:n
(prefixC0,suffixC0) = ("",",") #prefix and suffix for column 0
else
(prefixN,suffixN) = (fill("",n),fill("",n))
(prefixC0,suffixC0) = ("","")
end
if length(rowNames) == 0 #width of column 0 (cell00 and rowNames)
col0Width = 0
else
col0Width = maximum(length,vcat(cell00,rowNames)) + length(prefixC0) + length(suffixC0)
end
colWidth = [width + length(prefixN[j]) + length(suffixN[j]) for j=1:n] #widths of column 1:n
iob = IOBuffer()
if !isempty(colNames) #print (cell00,colNames), if any
!isempty(cell00) ? txt0 = string(prefixC0,cell00,suffixC0) : txt0 = ""
print(iob,rpad(txt0,col0Width))
for j = 1:n #loop over columns
print(iob,lpad(string(prefixN[j],colNames[j],suffixN[j]),colWidth[j]))
end
print(iob,"\n")
end
#print rowNames and x
(i0,j0) = (1 - first(axes(x,1)),1 - first(axes(x,2))) #i+i0,j+j0 give traditional indices
for i in axes(x,1) #loop over rows
!isempty(rowNames) && print(iob,rpad(string(prefixC0,rowNames[i+i0],suffixC0),col0Width))
for j in axes(x,2) #loop over columns
print(iob,fmtNumPs(x[i,j],width,prec,"right",prefix=prefixN[j+j0],suffix=suffixN[j+j0]))
end
print(iob,"\n")
end
str = String(take!(iob))
if NoPrinting #no printing, just return str
return str
else #print, return nothing
print(fh,str,"\n")
return nothing
end
end
#when fh is not supplied: printing to screen
printmat(x...;colNames=[],rowNames=[],width=10,prec=3,NoPrinting=false,StringFmt="",cell00="") =
printmat(stdout::IO,x...;colNames,rowNames,width,prec,NoPrinting,StringFmt,cell00)
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
"""
printlnPs([fh::IO],z...;width=10,prec=3)
Subsitute for println, with predefined formatting.
# Input
- `fh::IO`: (optional) file handle. If not supplied, prints to screen
- `z::String`: string, numbers and arrays to print
Paul.Soderlind@unisg.ch
"""
function printlnPs(fh::IO,z...;width=10,prec=3)
for x in z #loop over inputs in z...
if isa(x,AbstractArray)
iob = IOBuffer()
for i = 1:length(x)
print(iob,fmtNumPs(x[i],width,prec,"right"))
end
print(fh,String(take!(iob)))
else
print(fh,fmtNumPs(x,width,prec,"right"))
end
end
print(fh,"\n")
end
#when fh is not supplied: printing to screen
printlnPs(z...;width=10,prec=3) = printlnPs(stdout::IO,z...;width,prec)
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
"""
fmtNumPs(z,width=10,prec=2,justify="right";prefix="",suffix="")
Create a formatted string of a float (eg, "%10.4f"), nothing (""),
while other values are passed through. Strings are right (or left) justified
and can optionally be given prefix and suffix (eg, ",")
# Notice
- With prec > 0 and isa(z,Integer), then the string is padded with 1+prec spaces
to align with the printing of floats with the same prec.
# Requires
- Printf (for 1.6-), fmtNumPsC (for < 1.6)
"""
function fmtNumPs(z,width=10,prec=2,justify="right";prefix="",suffix="")
isa(z,Bool) && (z = convert(Int,z)) #Bool -> Int
if isa(z,AbstractFloat) #example: 101.0234, prec=3
if VERSION < v"1.6-"
fmt = "%$(width).$(prec)f"
zRound = round(z,digits=prec)
strLR = fmtNumPsC(fmt,zRound) #C fallback solution
else
fmt = Printf.Format("%$(width).$(prec)f")
strLR = Printf.format(fmt,z)
end
elseif isa(z,Nothing)
strLR = ""
elseif isa(z,Integer) && prec > 0 #integer followed by (1+prec spaces)
strLR = string(z," "^(1+prec))
else #Int, String, Date, Missing, etc
strLR = string(z)
end
strLR = string(prefix,strLR,suffix)
if justify == "left" #justification
strLR = rpad(strLR,width+length(prefix)+length(suffix))
else
strLR = lpad(strLR,width+length(prefix)+length(suffix))
end
return strLR
end
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
"""
fmtNumPsC(fmt,z)
c fallback solution for formatting of floating point number. Used if VERSION < v"1.6-"
"""
function fmtNumPsC(fmt,z) #c fallback solution
if ismissing(z) || isnan(z) || isinf(z) #asprintf does not work for these cases
str = string(z)
else
strp = Ref{Ptr{Cchar}}(0)
len = ccall(:asprintf,Cint,(Ptr{Ptr{Cchar}},Cstring,Cdouble...),strp,fmt,z)
str = unsafe_string(strp[],len)
Libc.free(strp[])
end
return str
end
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
function printblue(x...)
foreach(z->printstyled(z,color=:blue,bold=true),x)
print("\n")
end
function printred(x...)
foreach(z->printstyled(z,color=:red,bold=true),x)
print("\n")
end
function printmagenta(x...)
foreach(z->printstyled(z,color=:magenta,bold=true),x)
print("\n")
end
function printyellow(x...)
foreach(z->printstyled(z,color=:yellow,bold=true),x)
print("\n")
end
#------------------------------------------------------------------------------