Skip to content

Commit 8909fee

Browse files
authored
Enhance deleteVariables! deleteFactors! and plotDFG shows tags on hover (#1253)
* Enhance deleteVariables!|Factors! * plotDFG shows tags on hover * Fix Id errors and OrderedDict depr * Test coverage and formatting --------- Co-authored-by: Johannes Terblanche <Affie@users.noreply.github.com>
1 parent 83e63e7 commit 8909fee

8 files changed

Lines changed: 82 additions & 33 deletions

File tree

ext/DFGPlots.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,20 @@ function plotDFG(dfg::GraphsDFG; p::DFGPlotProps = DFGPlotProps(), interactive::
6161
0;
6262
text = "",
6363
font = :bold,
64-
fontsize = 30,
64+
fontsize = 20,
6565
glowcolor = (:white, 1),
6666
glowwidth = 3,
6767
)
6868

69-
ax.aspect = GraphMakie.DataAspect()
69+
ax.aspect = nothing
70+
ax.autolimitaspect = 1
7071
if interactive
72+
node_hover_labels = map(dfg.g.labels) do label
73+
tags = sort(DFG.listTags(dfg, label))
74+
tags_str = isempty(tags) ? "[]" : "[" * join(string.(tags), ", ") * "]"
75+
return string(label, "\ntags: ", tags_str)
76+
end
77+
7178
function node_drag_action(state, idx, event, axis)
7279
p[:node_pos][][idx] = event.data
7380
return p[:node_pos][] = p[:node_pos][]
@@ -79,8 +86,7 @@ function plotDFG(dfg::GraphsDFG; p::DFGPlotProps = DFGPlotProps(), interactive::
7986
GraphMakie.register_interaction!(ax, :ndrag, ndrag)
8087

8188
function node_hover_action(state, idx, event, axis)
82-
label = dfg.g.labels[idx]
83-
label_text.text[] = state ? string(label) : ""
89+
label_text.text[] = state ? node_hover_labels[idx] : ""
8490
return label_text.transformation.translation[] = (event.data..., 0)
8591
end
8692
nhover = NodeHoverHandler(node_hover_action)

src/FileDFG/services/FileDFG.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ function loadDFG!(
117117

118118
# extract the factor graph from fileDFG folder
119119
variablefiles = readdir(joinpath(loaddir, "variables"); sort = false, join = true)
120+
sort!(variablefiles; lt = natural_lt)
120121

121122
# type instability on `variables` as either `::Vector{Variable}` or `::Vector{VariableDFG{<:}}` (vector of abstract)
122123
variables = @showprogress dt = 1 desc = "loading variables" asyncmap(
@@ -129,6 +130,7 @@ function loadDFG!(
129130
@debug "Loaded $(length(variables)) variables"
130131

131132
factorfiles = readdir(joinpath(loaddir, "factors"); sort = false, join = true)
133+
sort!(factorfiles; lt = natural_lt)
132134

133135
factors = @showprogress dt = 1 desc = "loading factors" asyncmap(factorfiles) do file
134136
f = JSON.parsefile(file, F; style = DFGJSONStyle())
@@ -203,14 +205,14 @@ function loadDFG(file::AbstractString)
203205
blobproviders = if isfile(joinpath(loaddir, "blobproviders.json"))
204206
JSON.parsefile(
205207
joinpath(loaddir, "blobproviders.json"),
206-
Dict{Symbol, AbstractBlobprovider};
208+
OrderedDict{Symbol, AbstractBlobprovider};
207209
style = DFGJSONStyle(),
208210
)
209211
elseif isfile(joinpath(loaddir, "blobstores.json"))
210212
# backward compat: load old blobstores.json format
211213
JSON.parsefile(
212214
joinpath(loaddir, "blobstores.json"),
213-
Dict{Symbol, AbstractBlobprovider};
215+
OrderedDict{Symbol, AbstractBlobprovider};
214216
style = DFGJSONStyle(),
215217
)
216218
else

src/GraphsDFG/FactorGraphs/FactorGraphs.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Graphs:
1818
add_vertex!,
1919
add_edge!,
2020
rem_vertex!,
21+
rem_vertices!,
2122
rem_edge!,
2223
has_vertex,
2324
has_edge,
@@ -171,4 +172,27 @@ function rem_vertex!(g::FactorGraph{T, V, F}, v::Integer) where {T, V, F}
171172
return true
172173
end
173174

175+
function Graphs.rem_vertices!(g::FactorGraph{T, V, F}, vs::Vector{Int}) where {T, V, F}
176+
for v in sort(vs; rev = true)
177+
v in vertices(g) || continue
178+
lastv = nv(g)
179+
180+
rem_vertex!(g.graph, v) || continue
181+
182+
label = g.labels[v]
183+
delete!(g.variables, label)
184+
delete!(g.factors, label)
185+
186+
if v != lastv
187+
g.labels[v] = g.labels[lastv] #lastSym
188+
else
189+
delete!(g.labels, v)
190+
end
191+
end
192+
193+
OrderedCollections.rehash!(g.variables)
194+
OrderedCollections.rehash!(g.factors)
195+
return true
196+
end
197+
174198
end

src/GraphsDFG/services/factor_ops.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,9 @@ function DFG.deleteFactor!(dfg::GraphsDFG, label::Symbol)
7474
end
7575

7676
function DFG.deleteFactors!(dfg::AbstractDFG, labels::Vector{Symbol})
77-
counts = asyncmap(labels) do l
78-
return deleteFactor!(dfg, l)
79-
end
80-
return sum(counts)
77+
count = sum(map(l->hasFactor(dfg, l), labels); init = 0)
78+
rem_vertices!(dfg.g, map(l->dfg.g.labels[l], labels))
79+
return count
8180
end
8281

8382
function DFG.deleteFactors!(dfg::AbstractDFG; kwargs...)

src/GraphsDFG/services/variable_ops.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,25 @@ function DFG.deleteVariable!(dfg::GraphsDFG, label::Symbol)#::Tuple{AbstractGrap
7777
!haskey(dfg.g.variables, label) && return 0
7878

7979
# orphaned factors are not supported.
80-
del_facs = map(l -> deleteFactor!(dfg, l), listNeighbors(dfg, label))
80+
del_facs = deleteFactors!(dfg, listNeighbors(dfg, label))
8181

8282
rem_vertex!(dfg.g, dfg.g.labels[label])
8383
return sum(del_facs; init = 0) + 1
8484
end
8585

86+
function DFG.deleteVariables!(dfg::GraphsDFG, labels::Vector{Symbol})
87+
# collect factor neighbors for all variables before any deletion
88+
fac_labels = mapreduce(l -> listNeighbors(dfg, l), union, labels; init = Symbol[])
89+
fac_labels = filter(l -> hasFactor(dfg, l), fac_labels)
90+
91+
var_labels = filter(l -> hasVariable(dfg, l), labels)
92+
93+
count = length(var_labels) + length(fac_labels)
94+
vs = map(l -> dfg.g.labels[l], [var_labels; fac_labels])
95+
rem_vertices!(dfg.g, vs)
96+
return count
97+
end
98+
8699
function DFG.listVariables(
87100
dfg::GraphsDFG;
88101
whereSolvable::Union{Nothing, Function} = nothing,

src/entities/Error.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,41 +44,41 @@ function Base.showerror(io::IO, ex::LabelExistsError)
4444
end
4545

4646
"""
47-
IdNotFoundError(Id, available)
47+
IdNotFoundError(id, available)
4848
49-
Error thrown when a requested Id is not found.
49+
Error thrown when a requested id is not found.
5050
"""
51-
struct IdNotFoundError <: Exception
51+
struct IdNotFoundError{T} <: Exception
5252
name::String
53-
Id::UUID
54-
available::Vector{UUID}
53+
id::T
54+
available::Vector{T}
5555
end
5656

57-
IdNotFoundError(name::String, Id::UUID) = IdNotFoundError(name, Id, UUID[])
58-
IdNotFoundError(Id::UUID) = IdNotFoundError("Node", Id, UUID[])
57+
IdNotFoundError(name::String, id::T) where {T} = IdNotFoundError(name, id, T[])
58+
IdNotFoundError(id::T) where {T} = IdNotFoundError("Node", id, T[])
5959

6060
function Base.showerror(io::IO, ex::IdNotFoundError)
61-
print(io, "IdNotFoundError: ", ex.name, " Id '", ex.Id, "' not found.")
61+
print(io, "IdNotFoundError: ", ex.name, " id '", ex.id, "' not found.")
6262
if !isempty(ex.available)
63-
println(io, " Available Ids:")
63+
println(io, " Available ids:")
6464
show(io, ex.available)
6565
end
6666
end
6767

6868
"""
69-
IdExistsError(Id)
69+
IdExistsError(id)
7070
71-
Error thrown when attempting to add an Id that already exists in the collection.
71+
Error thrown when attempting to add an id that already exists in the collection.
7272
"""
73-
struct IdExistsError <: Exception
73+
struct IdExistsError{T} <: Exception
7474
name::String
75-
Id::UUID
75+
id::T
7676
end
7777

78-
IdExistsError(Id::UUID) = IdExistsError("Node", Id)
78+
IdExistsError(id) = IdExistsError("Node", id)
7979

8080
function Base.showerror(io::IO, ex::IdExistsError)
81-
return print(io, "IdExistsError: ", ex.name, " Id '", ex.Id, "' already exists.")
81+
return print(io, "IdExistsError: ", ex.name, " id '", ex.id, "' already exists.")
8282
end
8383

8484
"""

src/services/variable_ops.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function deleteVariables!(dfg::AbstractDFG, labels::Vector{Symbol})
121121
counts = asyncmap(labels) do l
122122
return deleteVariable!(dfg, l)
123123
end
124-
return sum(counts)
124+
return sum(counts; init = 0)
125125
end
126126

127127
function deleteVariables!(dfg::AbstractDFG; kwargs...)

test/testBlocks.jl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -460,15 +460,20 @@ function VariablesandFactorsCRUD_SET!(fg, v1, v2, v3, f0, f1, f2)
460460
@test addVariable!(fg, v3) === v3
461461
@test addFactor!(fg, f2) === f2
462462

463-
@test deleteFactor!(fg, f2) == 1
463+
@test deleteFactors!(fg, [getLabel(f2)]) == 1
464+
@test addFactor!(fg, f2) === f2
465+
@test deleteFactors!(fg; whereLabel = ==(string(getLabel(f2)))) == 1
466+
@test deleteFactors!(fg; whereLabel = ==("doesnotexist")) == 0
467+
468+
@test addFactor!(fg, f2) === f2
469+
@test deleteVariables!(fg, [getLabel(v3)]) == 2
470+
@test addVariable!(fg, v3) === v3
471+
@test deleteVariables!(fg; whereLabel = ==(string(getLabel(v3)))) == 1
472+
@test deleteVariables!(fg; whereLabel = ==("doesnotexist")) == 0
473+
464474
@test deleteFactor!(fg, f2) == 0
465475
@test lsf(fg) == [:abf1]
466476

467-
delvarCompare = getVariable(fg, :c)
468-
delfacCompare = []
469-
ndel = deleteVariable!(fg, v3)
470-
@test ndel == 1
471-
472477
@test getVariable(fg, :a) == v1
473478

474479
@test addFactor!(fg, f0) == f0

0 commit comments

Comments
 (0)