Skip to content

Commit

Permalink
writeSignalTable(..) improved
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinOtter committed Aug 11, 2022
1 parent ddfa490 commit 4f3197d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SignalTables"
uuid = "3201582d-3078-4276-ba5d-0a1254d79d7c"
authors = ["[email protected] <[email protected]>"]
version = "0.4.0"
version = "0.4.1"

[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Expand Down
6 changes: 6 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ are different to the Python 2.x version.

## Release Notes

### Version 0.4.1

- writeSignalTable(..., log=false):
- Info messages about not written elements only printed if log=true.
- Some issues corrected when writing signals.

### Version 0.4.0

- New signal-type Map added (additionally to Var und Par signals) with two new functions Map(..), isMap(..).
Expand Down
149 changes: 80 additions & 69 deletions src/SignalTableFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ end

"""
new_signal_table(args...)::OrderedDict{String,Any}
Returns a new signal table, that is `OrderedDict{String,Any}("_class" => :SignalTable, args...)`
"""
new_signal_table(args...) = OrderedDict{String,Any}("_class" => :SignalTable, args...)
Expand Down Expand Up @@ -106,7 +106,7 @@ function showMapValue(iostr,mapValue)::Nothing
for (key,val) in mapValue
if key in doNotShowAttributes
continue
end
end
if first
first = false
else
Expand Down Expand Up @@ -295,7 +295,7 @@ function eltypeOrTypeWithMeasurements(obj)
btype = typeof(obj1.val)
else
btype = eltypeOrType(obj)
end
end
end
else
btype = eltypeOrType(obj)
Expand All @@ -315,7 +315,7 @@ function eltypeOrTypeWithMeasurements(obj)
btype = typeof(obj1.val)
else
btype = eltypeOrType(obj)
end
end
end
else
btype = eltypeOrType(obj)
Expand All @@ -336,7 +336,7 @@ function eltypeOrTypeWithMeasurements(obj)
btype = typeof(obj1.val)
else
btype = eltypeOrType(obj)
end
end
return btype
end

Expand All @@ -362,7 +362,7 @@ function getValuesFromPar(signal, len::Int)
end
return nothing
end


"""
signal = getFlattenedSignal(signalTable, name;
Expand All @@ -371,7 +371,7 @@ end
targetFloat = Float64)
Returns a copy of a signal where the *flattened* and *converted* values (e.g.: missing -> NaN)
are stored as `signal[:flattenedValues]` and the legend as `signal[:legend]`.
are stored as `signal[:flattenedValues]` and the legend as `signal[:legend]`.
A flattened signal can be, for example, used for traditional plot functions or for traditional tables.
`signal[:flattenedValues]` is a reshape of values into a vector or a matrix with optionally the following transformations:
Expand All @@ -396,18 +396,18 @@ so signal[:flattenedValues] = signal[:values].
function getFlattenedSignal(signalTable, name::String;
missingToNaN = true,
targetInt = Int,
targetFloat = Float64)
independentSignalsSize = getIndependentSignalsSize(signalTable)
if length(independentSignalsSize) != 1
targetFloat = Float64)
independentSignalsSize = getIndependentSignalsSize(signalTable)
if length(independentSignalsSize) != 1
ni = length(independentSignalsSize)
@info "getFlattenedSignal(.., \"$name\") supported for one independent signal,\nbut number of independent signals = $(ni)! Signal is ignored."
return nothing
end
end
lenx = independentSignalsSize[1]
sigPresent = false
if hasSignal(signalTable,name)
# name is a signal name without range
signal = getSignal(signalTable,name)
signal = getSignal(signalTable,name)
if isVar(signal) && haskey(signal, :values)
sigValues = signal[:values]
elseif isPar(signal) && haskey(signal, :value)
Expand All @@ -416,7 +416,7 @@ function getFlattenedSignal(signalTable, name::String;
@goto ERROR
end
else
@goto ERROR
@goto ERROR
end
dims = size(sigValues)
if dims[1] > 0
Expand All @@ -438,7 +438,7 @@ function getFlattenedSignal(signalTable, name::String;
nScalarSignals = prod(i for i in varDims)
end
end

else
# Handle signal arrays, such as a.b.c[3] or a.b.c[2:3, 1:5, 3]
if name[end] == ']'
Expand All @@ -456,7 +456,7 @@ function getFlattenedSignal(signalTable, name::String;
@goto ERROR
end
else
@goto ERROR
@goto ERROR
end
dims = size(sigValues)

Expand Down Expand Up @@ -488,21 +488,21 @@ function getFlattenedSignal(signalTable, name::String;
if !sigPresent
@goto ERROR
end

# Transform sigValues
sigElType = eltype(sigValues)
eltypeOrType2 = eltypeOrTypeWithMeasurements(sigValues)
hasMissing = isa(missing, sigElType)

if (!isnothing(targetInt) && eltypeOrType2 == targetInt ||
if (!isnothing(targetInt) && eltypeOrType2 == targetInt ||
!isnothing(targetFloat) && eltypeOrType2 == targetFloat) &&
!(missingToNaN && hasMissing)
!(missingToNaN && hasMissing)
# Signal need not be converted - do nothing

elseif hasMissing && missingToNaN && !isnothing(targetFloat)
# sig contains missing or nothing - convert to targetFloat and replace missing by NaN
sigNaN = convert(targetFloat, NaN)
sigValues2 = Array{targetFloat, ndims(sigValues)}(undef, size(sigValues))
sigValues2 = Array{targetFloat, ndims(sigValues)}(undef, size(sigValues))
try
for i = 1:length(sigValues)
sigValues2[i] = ismissing(sigValues[i]) ? sigNaN : convert(targetFloat, sigValues[i])
Expand All @@ -513,7 +513,7 @@ function getFlattenedSignal(signalTable, name::String;
return nothing
end
sigValues = sigValues2

elseif !hasMissing && sigElType <: Integer && !isnothing(targetInt)
# Transform to targetInt
sigValues2 = Array{targetInt, ndims(sigValues)}(undef, size(sigValues))
Expand All @@ -529,7 +529,7 @@ function getFlattenedSignal(signalTable, name::String;
sigValues2[i] = convert(targetFloat, sigValues[i])
end
sigValues = sigValues2

else
@goto ERROR
end
Expand All @@ -555,7 +555,7 @@ function getFlattenedSignal(signalTable, name::String;
for j2 in 1:div(nScalarSignals, sizeLength[1])
for j3 in arrayIndices[1]
legend[i] *= string(j3)
push!(legendIndices[i], j3)
push!(legendIndices[i], j3)
# println("i = $i, j2 = $j2, j3 = $j3, legend[$i] = ", legend[i], ", legendIndices[$i] = ", legendIndices[i])
i += 1
end
Expand Down Expand Up @@ -601,7 +601,7 @@ function signalValuesForLinePlots(sigTable, name)
end
sig = signal[:flattenedValues]
sigLegend = signal[:legend]
variability = get(signal, :variability, "")
variability = get(signal, :variability, "")
if variability == "independent"
sigKind = Independent
elseif variability == "clocked" || variability == "clock" || variability == "trigger" || get(signal, "interpolation", "") == "none"
Expand Down Expand Up @@ -630,18 +630,18 @@ function getPlotSignal(sigTable, ysigName::AbstractString; xsigName=nothing)
(xsig, xsigLegend, xsigKind) = signalValuesForLinePlots(sigTable, xsigName2)
if isnothing(xsig)
@goto ERROR
end
end

# Check x-axis signal
if ndims(xsig) != 1
@info "\"$xsigName\" does not characterize a scalar variable as needed for the x-axis."
@goto ERROR
#elseif !(typeof(xsigValue) <: Real ||
#elseif !(typeof(xsigValue) <: Real ||
# typeof(xsigValue) <: Measurements.Measurement ||
# typeof(xsigValue) <: MonteCarloMeasurements.StaticParticles ||
# typeof(xsigValue) <: MonteCarloMeasurements.Particles )
# @info "\"$xsigName\" is of type " * string(typeof(xsigValue)) * " which is not supported for the x-axis."
# @goto ERROR
# @goto ERROR
end

return (xsig, xsigLegend[1], ysig, ysigLegend, ysigKind)
Expand Down Expand Up @@ -685,7 +685,7 @@ Encodes a SignalTable suitable to convert to JSON format.
If a keyword signalNames with a vector of strings is provided, then only
the corresponding signals are encoded.
"""
function encodeSignalTable(signalTable; signalNames=nothing)
function encodeSignalTable(signalTable; signalNames=nothing, log=false)
if isSignalTable(signalTable)
jdict = OrderedDict{String,Any}("_class" => "SignalTable",
"_classVersion" => version_SignalTable_JSON)
Expand All @@ -699,7 +699,7 @@ function encodeSignalTable(signalTable; signalNames=nothing)
delete!(signal, :values)
delete!(signal, :value)
end
encodedSignal = encodeSignalTableElement(name, signal)
encodedSignal = encodeSignalTableElement(name, signal, log=log)
if !isnothing(encodedSignal)
jdict[name] = encodedSignal
end
Expand All @@ -712,78 +712,89 @@ end


"""
jsigDict = encodeSignalTableElement(path, signalTableElement)
jsigDict = encodeSignalTableElement(path, signalTableElement; log=false)
Encodes a signal table element suitable to convert to JSON format.
"""
function encodeSignalTableElement(path, element)
function encodeSignalTableElement(path, element; log=false)
if isSignal(element)
if isVar(element)
jdict = OrderedDict{String,Any}("_class" => "Var")
elseif isPar(element)
jdict = OrderedDict{String,Any}("_class" => "Par")
else
jdict = OrderedDict{String,Any}("_class" => "Map")
jdict = OrderedDict{String,Any}("_class" => "Map")
end
available = true
available = false
for (key,val) in element
if key != ":_class"
encodedSignal = encodeSignalTableElement(appendNames(path,key),val)
if isnothing(encodedSignal)
available = false
else
encodedSignal = encodeSignalTableElement(appendNames(path,key),val, log=log)
if !isnothing(encodedSignal)
available = true
jdict[string(key)] = encodedSignal
end
end
end
end
if available
return jdict
else
return nothing
end

elseif typeof(element) <: AbstractArray && (elementBaseType(eltype(element)) <: Number || elementBaseType(eltype(element)) <: String)
if ndims(element) == 1 && string(eltype(element)) in TypesWithoutEncoding
return element
end
elunit = unitAsParseableString(element)
if elunit == ""
jdict = OrderedDict{String,Any}("_class" => "Array",
"eltype" => string(eltype(element)),
"size" => Int[i for i in size(element)],
"layout" => "column-major",
"values" => reshape(element, length(element)))

# elseif typeof(element) <: AbstractArray && (elementBaseType(eltype(element)) <: Number || elementBaseType(eltype(element)) <: String)
elseif typeof(element) <: AbstractArray
if ndims(element) == 1
eltypeElement = eltype(element)
if string(eltypeElement) in TypesWithoutEncoding || eltypeElement <: AbstractArray && ndims(eltypeElement) == 1
return element
else
if log
@info "$path::$(typeof(element)) is ignored, because mapping to JSON not known"
end
return nothing
end
else
element = ustrip.(element)
jdict = OrderedDict{String,Any}("_class" => "Array",
"unit" => elunit,
"eltype" => string(eltype(element)),
"size" => Int[i for i in size(element)],
"layout" => "column-major",
"values" => reshape(element, length(element)))
elunit = unitAsParseableString(element)
if elunit == ""
jdict = OrderedDict{String,Any}("_class" => "Array",
"eltype" => string(eltype(element)),
"size" => Int[i for i in size(element)],
"layout" => "column-major",
"values" => reshape(element, length(element)))
else
element = ustrip.(element)
jdict = OrderedDict{String,Any}("_class" => "Array",
"unit" => elunit,
"eltype" => string(eltype(element)),
"size" => Int[i for i in size(element)],
"layout" => "column-major",
"values" => reshape(element, length(element)))
end
return jdict
end
return jdict

elseif string(typeof(element)) in TypesWithoutEncoding
return element

elseif typeof(element) <: Number
elunit = unitAsParseableString(element)
elunit = unitAsParseableString(element)
if elunit == ""
jdict = OrderedDict{String,Any}("_class" => "Number",
"type" => typeof(element),
jdict = OrderedDict{String,Any}("_class" => "Number",
"type" => typeof(element),
"value" => element)
else
element = ustrip.(element)
jdict = OrderedDict{String,Any}("_class" => "Number",
jdict = OrderedDict{String,Any}("_class" => "Number",
"unit" => elunit,
"type" => typeof(element),
"value" => element)
"type" => typeof(element),
"value" => element)
end
return jdict

else
@info "$path::$(typeof(element)) is ignored, because mapping to JSON not known"
if log
@info "$path::$(typeof(element)) is ignored, because mapping to JSON not known"
end
return nothing
end
end
Expand All @@ -797,15 +808,15 @@ Returns a JSON string representation of signalTable
If keyword signalNames with a Vector of strings is provided, then a
signal table with the corresponding signals are returned as JSON string.
"""
function signalTableToJSON(signalTable; signalNames = nothing)::String
jsignalTable = encodeSignalTable(signalTable; signalNames=signalNames)
function signalTableToJSON(signalTable; signalNames = nothing, log=false)::String
jsignalTable = encodeSignalTable(signalTable; signalNames=signalNames, log=log)
return JSON.json(jsignalTable)
end


"""
writeSignalTable(filename::String, signalTable; signalNames=nothing, indent=nothing, log=false)
Write signalTable in JSON format on file `filename`.
If keyword signalNames with a Vector of strings is provided, then a
Expand All @@ -818,7 +829,7 @@ function writeSignalTable(filename::String, signalTable; signalNames = nothing,
if log
println(" Write signalTable in JSON format on file \"$file\"")
end
jsignalTable = encodeSignalTable(signalTable; signalNames=signalNames)
jsignalTable = encodeSignalTable(signalTable; signalNames=signalNames, log=log)
open(file, "w") do io
JSON.print(io, jsignalTable, indent)
end
Expand Down
Loading

0 comments on commit 4f3197d

Please sign in to comment.