Skip to content

Commit dea58c9

Browse files
Merge branch 'master' into hotfix/curve
2 parents 92dcc35 + 6458908 commit dea58c9

File tree

5 files changed

+76
-61
lines changed

5 files changed

+76
-61
lines changed

Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
2424
test = ["Test", "Cairo", "ImageMagick", "VisualRegressionTests"]
2525

2626
[compat]
27-
"Compose" = "~0.7"
28-
"LightGraphs" = "~1"
29-
"VisualRegressionTests" = "~0.2, ~0.3"
27+
"Compose" = ">= 0.7"
28+
"LightGraphs" = ">= 1.1"
29+
"VisualRegressionTests" = ">= 0.2"

src/collapse_plot.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using GraphPlot
22

3-
function collapse_graph(g::AbstractGraph{T}, membership::Vector{Int}) where {T<:Integer}
3+
function collapse_graph(g::AbstractGraph, membership::Vector{Int})
44
nb_comm = maximum(membership)
55

66
collapsed_edge_weights = Vector{Dict{Int,Float64}}(undef, nb_comm)
@@ -36,7 +36,7 @@ function collapse_graph(g::AbstractGraph{T}, membership::Vector{Int}) where {T<:
3636
end
3737
end
3838

39-
collapsed_graph, collapsed_weights
39+
return collapsed_graph, collapsed_weights
4040
end
4141

4242
function community_layout(g::AbstractGraph, membership::Vector{Int})
@@ -60,10 +60,10 @@ function community_layout(g::AbstractGraph, membership::Vector{Int})
6060
ly[node] = 1.8*length(nodes)/N*sin(θ[idx]) + cly[lbl]
6161
end
6262
end
63-
lx, ly
63+
return lx, ly
6464
end
6565

66-
function collapse_layout(g::AbstractGraph{T}, membership::Vector{Int}) where {T<:Integer}
66+
function collapse_layout(g::AbstractGraph, membership::Vector{Int})
6767
lightg = LightGraphs.SimpleGraph(nv(g))
6868
for e in edges(g)
6969
u = src(e)
@@ -92,5 +92,5 @@ function collapse_layout(g::AbstractGraph{T}, membership::Vector{Int}) where {T<
9292
ly[node] = 1.8*length(nodes)/N*subly[idx] + cly[lbl]
9393
end
9494
end
95-
lx, ly
95+
return lx, ly
9696
end

src/layout.jl

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using SparseArrays: SparseMatrixCSC, sparse
2-
using ArnoldiMethod: LR
2+
using ArnoldiMethod: SR
3+
using Base: OneTo
34
using LinearAlgebra: eigen
45

56
"""
@@ -39,7 +40,7 @@ Position nodes on a circle.
3940
4041
**Parameters**
4142
42-
*G*
43+
*g*
4344
a graph
4445
4546
**Returns**
@@ -51,7 +52,7 @@ but will be normalized and centered anyway
5152
**Examples**
5253
5354
```
54-
julia> g = simple_house_graph()
55+
julia> g = smallgraph(:house)
5556
julia> locs_x, locs_y = circular_layout(g)
5657
```
5758
"""
@@ -60,18 +61,18 @@ function circular_layout(g)
6061
return [0.0], [0.0]
6162
else
6263
# Discard the extra angle since it matches 0 radians.
63-
θ = range(0, stop=2pi, length=_nv(G)+1)[1:end-1]
64+
θ = range(0, stop=2pi, length=nv(g)+1)[1:end-1]
6465
return cos.(θ), sin.(θ)
6566
end
6667
end
6768

6869
"""
6970
This function is copy from [IainNZ](https://github.com/IainNZ)'s [GraphLayout.jl](https://github.com/IainNZ/GraphLayout.jl)
7071
71-
Use the spring/repulsion model of Fruchterman and Reingold (1991):
72+
Use a modified version of the spring/repulsion model of Fruchterman and Reingold (1991):
7273
73-
+ Attractive force: f_a(d) = d^2 / k
74-
+ Repulsive force: f_r(d) = -k^2 / d
74+
+ Attractive force: f_a(d) = d / k
75+
+ Repulsive force: f_r(d) = -k^2 / d^2
7576
7677
where d is distance between two vertices and the optimal distance
7778
between vertices k is defined as C * sqrt( area / num_vertices )
@@ -96,63 +97,66 @@ Integer seed for pseudorandom generation of locations (default = 0).
9697
9798
**Examples**
9899
```
99-
julia> g = graphfamous("karate")
100+
julia> g = smallgraph(:karate)
100101
julia> locs_x, locs_y = spring_layout(g)
101102
```
102103
"""
103-
function spring_layout(g::AbstractGraph{T}, locs_x, locs_y; C=2.0, MAXITER=100, INITTEMP=2.0) where {T<:Integer}
104-
105-
#size(adj_matrix, 1) != size(adj_matrix, 2) && error("Adj. matrix must be square.")
106-
N = nv(g)
104+
function spring_layout(g::AbstractGraph,
105+
locs_x=2*rand(nv(g)).-1.0,
106+
locs_y=2*rand(nv(g)).-1.0;
107+
C=2.0,
108+
MAXITER=100,
109+
INITTEMP=2.0)
110+
111+
nvg = nv(g)
107112
adj_matrix = adjacency_matrix(g)
108113

109114
# The optimal distance bewteen vertices
110-
K = C * sqrt(4.0 / N)
115+
k = C * sqrt(4.0 / nvg)
116+
= k * k
111117

112118
# Store forces and apply at end of iteration all at once
113-
force_x = zeros(N)
114-
force_y = zeros(N)
119+
force_x = zeros(nvg)
120+
force_y = zeros(nvg)
115121

116122
# Iterate MAXITER times
117123
@inbounds for iter = 1:MAXITER
118124
# Calculate forces
119-
for i = 1:N
125+
for i = 1:nvg
120126
force_vec_x = 0.0
121127
force_vec_y = 0.0
122-
for j = 1:N
128+
for j = 1:nvg
123129
i == j && continue
124130
d_x = locs_x[j] - locs_x[i]
125131
d_y = locs_y[j] - locs_y[i]
126-
d = sqrt(d_x^2 + d_y^2)
127-
if adj_matrix[i,j] != zero(eltype(adj_matrix)) || adj_matrix[j,i] != zero(eltype(adj_matrix))
128-
# F = d^2 / K - K^2 / d
129-
F_d = d / K - K^2 / d^2
132+
dist² = (d_x * d_x) + (d_y * d_y)
133+
dist = sqrt(dist²)
134+
135+
if !( iszero(adj_matrix[i,j]) && iszero(adj_matrix[j,i]) )
136+
# Attractive + repulsive force
137+
# F_d = dist² / k - k² / dist # original FR algorithm
138+
F_d = dist / k -/ dist²
130139
else
131140
# Just repulsive
132-
# F = -K^2 / d^
133-
F_d = -K^2 / d^2
141+
# F_d = - / dist # original FR algorithm
142+
F_d = - / dist²
134143
end
135-
# d / sin θ = d_y/d = fy/F
136-
# F /| dy fy -> fy = F*d_y/d
137-
# / | cos θ = d_x/d = fx/F
138-
# /--- -> fx = F*d_x/d
139-
# dx fx
140144
force_vec_x += F_d*d_x
141145
force_vec_y += F_d*d_y
142146
end
143147
force_x[i] = force_vec_x
144148
force_y[i] = force_vec_y
145149
end
146150
# Cool down
147-
TEMP = INITTEMP / iter
151+
temp = INITTEMP / iter
148152
# Now apply them, but limit to temperature
149-
for i = 1:N
150-
force_mag = sqrt(force_x[i]^2 + force_y[i]^2)
151-
scale = min(force_mag, TEMP)/force_mag
153+
for i = 1:nvg
154+
fx = force_x[i]
155+
fy = force_y[i]
156+
force_mag = sqrt((fx * fx) + (fy * fy))
157+
scale = min(force_mag, temp) / force_mag
152158
locs_x[i] += force_x[i] * scale
153-
#locs_x[i] = max(-1.0, min(locs_x[i], +1.0))
154159
locs_y[i] += force_y[i] * scale
155-
#locs_y[i] = max(-1.0, min(locs_y[i], +1.0))
156160
end
157161
end
158162

@@ -165,7 +169,7 @@ function spring_layout(g::AbstractGraph{T}, locs_x, locs_y; C=2.0, MAXITER=100,
165169
map!(z -> scaler(z, min_x, max_x), locs_x, locs_x)
166170
map!(z -> scaler(z, min_y, max_y), locs_y, locs_y)
167171

168-
return locs_x,locs_y
172+
return locs_x, locs_y
169173
end
170174

171175
using Random: MersenneTwister
@@ -181,28 +185,27 @@ Position nodes in concentric circles.
181185
182186
**Parameters**
183187
184-
*G*
188+
*g*
185189
a graph
186190
187191
*nlist*
188192
Vector of Vector, Vector of node Vector for each shell.
189193
190194
**Examples**
191195
```
192-
julia> g = graphfamous("karate")
196+
julia> g = smallgraph(:karate)
193197
julia> nlist = Array{Vector{Int}}(2)
194198
julia> nlist[1] = [1:5]
195199
julia> nlist[2] = [6:num_vertiecs(g)]
196200
julia> locs_x, locs_y = shell_layout(g, nlist)
197201
```
198202
"""
199-
function shell_layout(G, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
200-
if _nv(G) == 1
203+
function shell_layout(g, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
204+
if nv(g) == 1
201205
return [0.0], [0.0]
202206
end
203207
if nlist == nothing
204-
nlist = Array{Vector{Int}}(1)
205-
nlist[1] = collect(1:_nv(G))
208+
nlist = [collect(1:nv(g))]
206209
end
207210
radius = 0.0
208211
if length(nlist[1]) > 1
@@ -217,7 +220,7 @@ function shell_layout(G, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
217220
append!(locs_y, radius*sin.(θ))
218221
radius += 1.0
219222
end
220-
locs_x, locs_y
223+
return locs_x, locs_y
221224
end
222225

223226
"""
@@ -237,20 +240,20 @@ the edge weight. If None, then all edge weights are 1.
237240
238241
**Examples**
239242
```
240-
julia> g = graphfamous("karate")
243+
julia> g = smallgraph(:karate)
241244
julia> weight = rand(num_edges(g))
242245
julia> locs_x, locs_y = spectral_layout(g, weight)
243246
```
244247
"""
245-
function spectral_layout(g::AbstractGraph{T}, weight=nothing) where {T<:Integer}
248+
function spectral_layout(g::AbstractGraph, weight=nothing)
246249
if nv(g) == 1
247250
return [0.0], [0.0]
248251
elseif nv(g) == 2
249252
return [0.0, 1.0], [0.0, 0.0]
250253
end
251254

252255
if weight == nothing
253-
weight = ones(length(edges(g)))
256+
weight = ones(ne(g))
254257
end
255258
if nv(g) > 500
256259
A = sparse(Int[src(e) for e in edges(g)],
@@ -276,7 +279,7 @@ function _spectral(A::SparseMatrixCSC)
276279
data = vec(sum(A, dims=1))
277280
D = sparse(Base.OneTo(length(data)), Base.OneTo(length(data)), data)
278281
L = D - A
279-
eigenvalues, eigenvectors = LightGraphs.LinAlg.eigs(L, nev=3, which=LR())
282+
eigenvalues, eigenvectors = LightGraphs.LinAlg.eigs(L, nev=3, which=SR())
280283
index = sortperm(real(eigenvalues))[2:3]
281284
return real(eigenvectors[:, index[1]]), real(eigenvectors[:, index[2]])
282285
end

src/stress.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,21 @@ Reference:
5555
pages={239--250},
5656
}
5757
"""
58-
function stressmajorize_layout(g::AbstractGraph, p::Int=2, w=nothing, X0=randn(nv(g), p);
59-
maxiter = 400size(X0, 1)^2, abstols=(eps(eltype(X0))),
60-
reltols=(eps(eltype(X0))), abstolx=(eps(eltype(X0))),
61-
verbose = false, returnall = false)
58+
function stressmajorize_layout(g::AbstractGraph,
59+
p::Int=2,
60+
w=nothing,
61+
X0=randn(nv(g), p);
62+
maxiter = 400size(X0, 1)^2,
63+
abstols=(eps(eltype(X0))),
64+
reltols=(eps(eltype(X0))),
65+
abstolx=(eps(eltype(X0))),
66+
verbose = false,
67+
returnall = false)
6268

6369
@assert size(X0, 2)==p
6470
δ = fill(1.0, nv(g), nv(g))
6571

66-
if w==nothing
72+
if w == nothing
6773
w = δ.^-2
6874
w[.!isfinite.(w)] .= 0
6975
end
@@ -137,7 +143,7 @@ function weightedlaplacian(w)
137143
Lw[i, j] = -w[i, j]
138144
D += w[i, j]
139145
end
140-
Lw[i, i]=D
146+
Lw[i, i] = D
141147
end
142148
return Lw
143149
end

test/runtests.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ using ImageMagick
1616
istravis = "TRAVIS" keys(ENV)
1717
datadir = joinpath(@__DIR__, "data")
1818

19+
20+
21+
22+
# TODO smallgraph(:karate) has already been added to LightGraphs
23+
# but as there hasn't been any new version tagged, we relay on this instead
1924
karate_edges = Edge.([
2025
1 => 2, 1 => 3, 1 => 4, 1 => 5, 1 => 6, 1 => 7,
2126
1 => 8, 1 => 9, 1 => 11, 1 => 12, 1 => 13, 1 => 14,
@@ -31,11 +36,12 @@ karate_edges = Edge.([
3136
27 => 30, 27 => 34, 28 => 34, 29 => 32, 29 => 34, 30 => 33,
3237
30 => 34, 31 => 33, 31 => 34, 32 => 33, 32 => 34, 33 => 34,
3338
])
34-
3539
# graphs to test
40+
#g = smallgraph(:karate)
3641
g = SimpleGraph(karate_edges)
3742
h = LightGraphs.WheelGraph(10)
3843

44+
3945
test_layout(g::AbstractGraph; kws...) = spring_layout(g; seed=2017, kws...)
4046

4147
# plot and save function for visual regression tests

0 commit comments

Comments
 (0)