JuliaGraphs / NetworkLayout.jl

Layout algorithms for graphs and trees in pure Julia.
Other
97 stars 22 forks source link

Spring layout for directed graphs - #66

Open kenahoo opened 1 month ago

kenahoo commented 1 month ago

I noticed that when I use the Spring layout on directed graphs, initialization & iteration aren't working as expected. My use case is to keep most points pinned, but initialize some points to the centroid and use Spring to find good places for them.

# 'g' is a MetaGraph{Int32, SimpleDiGraph{Int32}, ...} object
layout = NetworkLayout.spring(g; pin = pin, initialpos = center, initialtemp = sd)

But the layout seems to not initialize to the centroid, rather to values in [-1, 1], ignoring the initialpos parameter.

When I changed the graph argument to be undirected, it works as expected:

layout = NetworkLayout.spring(Graph(g.graph); pin = pin, initialpos = center, initialtemp = sd)

(Unfortunately I don't have a good small shareable example because my data is pretty big & proprietary.)

Thanks.

hexaeder commented 1 month ago

Hi! Is that in a GraphMakie context? I tried to create an MWE, and the layout output seems fine. The first position respects both initialpos and pin arguments. From then on it iterates but does not change pined points.

However as soos as I try to dynamicially update a GraphMakie plot with this iterator, everything breaks. Including the Makie Axis which I don't understand at all.

using Pkg
pkg"activate --temp"
pkg"add CairoMakie, GraphMakie, NetworkLayout, Graphs"
using CairoMakie, GraphMakie, NetworkLayout, Graphs

g1 = wheel_graph(10)
g2 = wheel_digraph(10)

pin = Dict(1 => (0,0),
            2 => (1,0))
initialpos = [(0,0) for _ in 1:nv(g1)]

# try with undirected graph
f, ax, p = graphplot(g1; nlabels=repr.(1:nv(g1)))
xlims!(ax, -2, 2)
ylims!(ax, -2, 2)

iterator = LayoutIterator(Spring(;pin, initialpos), g1)
Makie.record(f, "spring_undirected.mp4", iterator; framerate = 10) do pos
    p[:node_pos][] = pos
end

# same for directed graph
f, ax, p = graphplot(g2; nlabels=repr.(1:nv(g2)))
xlims!(ax, -2, 2)
ylims!(ax, -2, 2)

iterator = LayoutIterator(Spring(;pin, initialpos), g2)
Makie.record(f, "spring_directed.mp4", iterator; framerate = 10) do pos
    p[:node_pos][] = pos
end

https://github.com/user-attachments/assets/1e1ca417-b5c9-408e-8fdd-93883657d50a

https://github.com/user-attachments/assets/e3d85e6f-0617-40fb-a307-5a6831693e18

hexaeder commented 1 month ago

If it was indeed GraphMakie-related, it should be fixed in GraphMakie@0.5.12, which will be tagged shortly.