From e56ea91a81f51f8f0428a1c590c3f099701b201d Mon Sep 17 00:00:00 2001 From: Truls Flatberg Date: Tue, 30 Sep 2025 22:25:47 +0200 Subject: [PATCH 1/5] Custom profile print --- src/profiles.jl | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/profiles.jl b/src/profiles.jl index 3c21469..6931bc1 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -27,6 +27,10 @@ struct FixedProfile{T} <: TimeProfile{T} end end +function Base.show(io::IO, fp::FixedProfile) + return print(io, fp.val) +end + function Base.getindex( fp::FixedProfile, _::T, @@ -79,6 +83,22 @@ function Base.getindex(op::OperationalProfile, i::TimeStructurePeriod) return error("Type $(typeof(i)) can not be used as index for an operational profile") end +function _print_values(vals; delim = ',', max_elems = 10) + n = length(vals) + sep = delim * " " + if n <= max_elems + return join(vals, sep) + end + nshow = round(Int, max_elems / 2) + seq1 = vals[1:nshow] + seq2 = vals[(end-nshow+1):end] + return join(seq1, sep) * sep * "... " * sep * join(seq2, sep) +end + +function Base.show(io::IO, op::OperationalProfile) + return print(io, "OperationalProfile[", _print_values(op.vals), "]") +end + function Base.convert(::Type{OperationalProfile{T}}, op::OperationalProfile{S}) where {T,S} return OperationalProfile(convert.(T, op.vals)) end @@ -145,6 +165,10 @@ function Base.getindex( return _value_lookup(StrategicIndexable(T), sp, period) end +function Base.show(io::IO, sp::StrategicProfile) + return print(io, "StrategicProfile[", _print_values(sp.vals), "]") +end + """ ScenarioProfile(vals::Vector{P}) where {T, P<:TimeProfile{T}} ScenarioProfile(vals::Vector) @@ -206,6 +230,10 @@ function Base.getindex( return _value_lookup(ScenarioIndexable(T), sp, period) end +function Base.show(io::IO, sp::ScenarioProfile) + return print(io, "ScenarioProfile[", _print_values(sp.vals), "]") +end + """ RepresentativeProfile(vals::Vector{P}) where {T, P<:TimeProfile{T}} RepresentativeProfile(vals::Vector) @@ -265,6 +293,10 @@ function Base.getindex( return _value_lookup(RepresentativeIndexable(T), rp, period) end +function Base.show(io::IO, rp::RepresentativeProfile) + return print(io, "RepresentativeProfile[", _print_values(rp.vals), "]") +end + """ StrategicStochasticProfile(vals::Vector{<:Vector{P}}) where {T, P<:TimeProfile{T}} StrategicStochasticProfile(vals::Vector{<:Vector}) From fcc7c67b084e5e8efd2a2d2d2eabc0e2b2a16957 Mon Sep 17 00:00:00 2001 From: Truls Flatberg Date: Wed, 1 Oct 2025 15:42:10 +0200 Subject: [PATCH 2/5] Improved profile output with indenting of multiple layers --- src/profiles.jl | 73 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index 6931bc1..9af9673 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -28,7 +28,7 @@ struct FixedProfile{T} <: TimeProfile{T} end function Base.show(io::IO, fp::FixedProfile) - return print(io, fp.val) + return print(io, _print_profile(fp)) end function Base.getindex( @@ -83,20 +83,8 @@ function Base.getindex(op::OperationalProfile, i::TimeStructurePeriod) return error("Type $(typeof(i)) can not be used as index for an operational profile") end -function _print_values(vals; delim = ',', max_elems = 10) - n = length(vals) - sep = delim * " " - if n <= max_elems - return join(vals, sep) - end - nshow = round(Int, max_elems / 2) - seq1 = vals[1:nshow] - seq2 = vals[(end-nshow+1):end] - return join(seq1, sep) * sep * "... " * sep * join(seq2, sep) -end - function Base.show(io::IO, op::OperationalProfile) - return print(io, "OperationalProfile[", _print_values(op.vals), "]") + return print(io, _print_profile(op)) end function Base.convert(::Type{OperationalProfile{T}}, op::OperationalProfile{S}) where {T,S} @@ -166,7 +154,7 @@ function Base.getindex( end function Base.show(io::IO, sp::StrategicProfile) - return print(io, "StrategicProfile[", _print_values(sp.vals), "]") + return print(io, _print_profile(sp)) end """ @@ -231,7 +219,7 @@ function Base.getindex( end function Base.show(io::IO, sp::ScenarioProfile) - return print(io, "ScenarioProfile[", _print_values(sp.vals), "]") + return print(io, _print_profile(sp)) end """ @@ -440,3 +428,56 @@ end function /(a::RepresentativeProfile{T}, b::Number) where {T} return RepresentativeProfile(a.vals ./ b) end + +function _print_values(vals; delim = ' ', max_elems = 6) + n = length(vals) + sep = delim * " " + if n <= max_elems + return join(vals, sep) + end + nshow = round(Int, max_elems / 2) + seq1 = vals[1:nshow] + seq2 = vals[(end-nshow+1):end] + return join(seq1, sep) * sep * "..." * sep * join(seq2, sep) +end + +_layers(vals::Vector) = maximum(_layers(v) for v in vals) +_layers(p::TimeProfile) = _layers(p.vals) + 1 +_layers(p::FixedProfile) = 1 +_layers(p::OperationalProfile) = 1 + +function _print_values_indent(vals, indent_level; max_lines = 5) + n = length(vals) + m = _layers(vals) + if n <= max_lines - 2m + 2 + return join([_print_profile(v, indent_level) for v in vals], ",\n") + end + nshow = round(Int, max_lines / 2 - m + 1) + seq1 = vals[1:max(nshow, 2)] + seq2 = vals[(end-max(nshow, 1)+1):end] + indent = " " ^ (indent_level * 2) + return join([_print_profile(v, indent_level) for v in seq1], ",\n") * + ",\n" * + indent * + "⋮\n" * + join([_print_profile(v, indent_level) for v in seq2], ",\n") +end + +_indent(n) = " " ^ (n * 2) + +function _print_profile(p::TimeProfile, indent_level = 0) + return _indent(indent_level) * + "$(typeof(p))[\n" * + _print_values_indent(p.vals, indent_level + 1) * + "\n" * + _indent(indent_level) * + "]" +end + +function _print_profile(fp::FixedProfile, indent_level = 0) + return _indent(indent_level) * "$(typeof(fp))[" * string(fp.val) * "]" +end + +function _print_profile(op::OperationalProfile, indent_level = 0) + return _indent(indent_level) * "$(typeof(op))[" * _print_values(op.vals) * "]" +end From 1da506b5c96b015b734b5c9745e7668b43208af2 Mon Sep 17 00:00:00 2001 From: Truls Flatberg Date: Wed, 1 Oct 2025 16:30:58 +0200 Subject: [PATCH 3/5] Tweaking output to align with standard Julia --- src/profiles.jl | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index 9af9673..0c06337 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -429,16 +429,20 @@ function /(a::RepresentativeProfile{T}, b::Number) where {T} return RepresentativeProfile(a.vals ./ b) end -function _print_values(vals; delim = ' ', max_elems = 6) +_display_val(val) = val +_display_val(val::Float64) = round(val; digits = 5) +_display_val(val::Float32) = round(val; digits = 5) + +function _print_values(vals; delim = ' ', max_elems = 10) n = length(vals) sep = delim * " " if n <= max_elems return join(vals, sep) end nshow = round(Int, max_elems / 2) - seq1 = vals[1:nshow] - seq2 = vals[(end-nshow+1):end] - return join(seq1, sep) * sep * "..." * sep * join(seq2, sep) + seq1 = _display_val.(vals[1:nshow]) + seq2 = _display_val.(vals[(end-nshow+1):end]) + return join(seq1, sep) * sep * "…" * sep * join(seq2, sep) end _layers(vals::Vector) = maximum(_layers(v) for v in vals) @@ -465,9 +469,18 @@ end _indent(n) = " " ^ (n * 2) +function _profile_name(p::TimeProfile{T}, indent_level) where {T} + profile_name = "$(typeof(p).name.name)" + if indent_level == 0 + profile_name = profile_name * " with eltype $(T): " + end + return profile_name +end + function _print_profile(p::TimeProfile, indent_level = 0) return _indent(indent_level) * - "$(typeof(p))[\n" * + _profile_name(p, indent_level) * + "[\n" * _print_values_indent(p.vals, indent_level + 1) * "\n" * _indent(indent_level) * @@ -475,9 +488,17 @@ function _print_profile(p::TimeProfile, indent_level = 0) end function _print_profile(fp::FixedProfile, indent_level = 0) - return _indent(indent_level) * "$(typeof(fp))[" * string(fp.val) * "]" + return _indent(indent_level) * + _profile_name(fp, indent_level) * + "[" * + string(fp.val) * + "]" end function _print_profile(op::OperationalProfile, indent_level = 0) - return _indent(indent_level) * "$(typeof(op))[" * _print_values(op.vals) * "]" + return _indent(indent_level) * + _profile_name(op, indent_level) * + "[" * + _print_values(op.vals) * + "]" end From 7be5b8734d3decf2747226052bd0e7b2a412e79b Mon Sep 17 00:00:00 2001 From: Truls Flatberg Date: Wed, 1 Oct 2025 16:36:44 +0200 Subject: [PATCH 4/5] Format with correct version of JuliaFormatter --- src/profiles.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index 0c06337..dcd7778 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -459,7 +459,7 @@ function _print_values_indent(vals, indent_level; max_lines = 5) nshow = round(Int, max_lines / 2 - m + 1) seq1 = vals[1:max(nshow, 2)] seq2 = vals[(end-max(nshow, 1)+1):end] - indent = " " ^ (indent_level * 2) + indent = " "^(indent_level * 2) return join([_print_profile(v, indent_level) for v in seq1], ",\n") * ",\n" * indent * @@ -467,7 +467,7 @@ function _print_values_indent(vals, indent_level; max_lines = 5) join([_print_profile(v, indent_level) for v in seq2], ",\n") end -_indent(n) = " " ^ (n * 2) +_indent(n) = " "^(n * 2) function _profile_name(p::TimeProfile{T}, indent_level) where {T} profile_name = "$(typeof(p).name.name)" From ee11c137fb55eb4bdf7615c28d297654bde2e462 Mon Sep 17 00:00:00 2001 From: Truls Flatberg Date: Sat, 4 Oct 2025 18:22:14 +0200 Subject: [PATCH 5/5] Tweaks and simplifications --- src/profiles.jl | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/profiles.jl b/src/profiles.jl index dcd7778..804303f 100644 --- a/src/profiles.jl +++ b/src/profiles.jl @@ -27,10 +27,6 @@ struct FixedProfile{T} <: TimeProfile{T} end end -function Base.show(io::IO, fp::FixedProfile) - return print(io, _print_profile(fp)) -end - function Base.getindex( fp::FixedProfile, _::T, @@ -83,10 +79,6 @@ function Base.getindex(op::OperationalProfile, i::TimeStructurePeriod) return error("Type $(typeof(i)) can not be used as index for an operational profile") end -function Base.show(io::IO, op::OperationalProfile) - return print(io, _print_profile(op)) -end - function Base.convert(::Type{OperationalProfile{T}}, op::OperationalProfile{S}) where {T,S} return OperationalProfile(convert.(T, op.vals)) end @@ -153,10 +145,6 @@ function Base.getindex( return _value_lookup(StrategicIndexable(T), sp, period) end -function Base.show(io::IO, sp::StrategicProfile) - return print(io, _print_profile(sp)) -end - """ ScenarioProfile(vals::Vector{P}) where {T, P<:TimeProfile{T}} ScenarioProfile(vals::Vector) @@ -218,10 +206,6 @@ function Base.getindex( return _value_lookup(ScenarioIndexable(T), sp, period) end -function Base.show(io::IO, sp::ScenarioProfile) - return print(io, _print_profile(sp)) -end - """ RepresentativeProfile(vals::Vector{P}) where {T, P<:TimeProfile{T}} RepresentativeProfile(vals::Vector) @@ -281,10 +265,6 @@ function Base.getindex( return _value_lookup(RepresentativeIndexable(T), rp, period) end -function Base.show(io::IO, rp::RepresentativeProfile) - return print(io, "RepresentativeProfile[", _print_values(rp.vals), "]") -end - """ StrategicStochasticProfile(vals::Vector{<:Vector{P}}) where {T, P<:TimeProfile{T}} StrategicStochasticProfile(vals::Vector{<:Vector}) @@ -429,11 +409,13 @@ function /(a::RepresentativeProfile{T}, b::Number) where {T} return RepresentativeProfile(a.vals ./ b) end +# Profile printing + _display_val(val) = val _display_val(val::Float64) = round(val; digits = 5) _display_val(val::Float32) = round(val; digits = 5) -function _print_values(vals; delim = ' ', max_elems = 10) +function _print_values(vals; delim = ',', max_elems = 10) n = length(vals) sep = delim * " " if n <= max_elems @@ -442,7 +424,7 @@ function _print_values(vals; delim = ' ', max_elems = 10) nshow = round(Int, max_elems / 2) seq1 = _display_val.(vals[1:nshow]) seq2 = _display_val.(vals[(end-nshow+1):end]) - return join(seq1, sep) * sep * "…" * sep * join(seq2, sep) + return join(seq1, sep) * " … " * join(seq2, sep) end _layers(vals::Vector) = maximum(_layers(v) for v in vals) @@ -454,23 +436,25 @@ function _print_values_indent(vals, indent_level; max_lines = 5) n = length(vals) m = _layers(vals) if n <= max_lines - 2m + 2 - return join([_print_profile(v, indent_level) for v in vals], ",\n") + return join([_print_profile(v, indent_level) for v in vals], "\n") end nshow = round(Int, max_lines / 2 - m + 1) seq1 = vals[1:max(nshow, 2)] seq2 = vals[(end-max(nshow, 1)+1):end] indent = " "^(indent_level * 2) - return join([_print_profile(v, indent_level) for v in seq1], ",\n") * - ",\n" * + return join([_print_profile(v, indent_level) for v in seq1], "\n") * + "\n" * indent * "⋮\n" * - join([_print_profile(v, indent_level) for v in seq2], ",\n") + join([_print_profile(v, indent_level) for v in seq2], "\n") end _indent(n) = " "^(n * 2) +_length(p::TimeProfile) = "$(length(p.vals))-element " +_length(p::FixedProfile) = "" function _profile_name(p::TimeProfile{T}, indent_level) where {T} - profile_name = "$(typeof(p).name.name)" + profile_name = _length(p) * "$(typeof(p).name.name)" if indent_level == 0 profile_name = profile_name * " with eltype $(T): " end @@ -480,6 +464,8 @@ end function _print_profile(p::TimeProfile, indent_level = 0) return _indent(indent_level) * _profile_name(p, indent_level) * + "\n" * + _indent(indent_level) * "[\n" * _print_values_indent(p.vals, indent_level + 1) * "\n" * @@ -502,3 +488,15 @@ function _print_profile(op::OperationalProfile, indent_level = 0) _print_values(op.vals) * "]" end + +function Base.summary(io::IO, p::TimeProfile{T}) where {T} + return print(io, _length(p) * "$(typeof(p).name.name) with eltype $T") +end + +function Base.show(io::IO, p::TimeProfile) + if get(io, :compact, false) + summary(io, p) + else + print(io, _print_profile(p)) + end +end