-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multigraph support #52
Comments
yeah, the assumptions inside GraphMakie arn't that strict, it should work with any subtype of I guess MultiGraphs defines such Edge Iterator. Probably the easiest solution would be to use the new interface created in #48 for that. That is, set a base distance of |
Well no, forget what i just said, Multigraphs does not work like this. g = Multigraph(3)
add_edge!(g, 1, 2)
add_edge!(g, 1, 2)
add_edge!(g, 2, 3)
edges(g) |> collect will instead return
which is a new edge type. Hm... |
Perhaps internally it could take whatever input ( |
Yeah i guess you'd have to define a new graph type which handles multiple edges as literal multiple edges instead of a single edge with multiplicity. I guess there are points two make for both views. Simple example on how a wrapper like this could look. using GraphMakie
using GLMakie
using Multigraphs
using Graphs
using Graphs.SimpleGraphs
struct MultigraphWrap{T} <: AbstractGraph{T}
g::Multigraph{T}
end
Base.eltype(g::MultigraphWrap) = eltype(g.g)
Graphs.edgetype(g::MultigraphWrap) = edgetype(g.g)
Graphs.has_edge(g::MultigraphWrap, s, d) = has_edge(g.g, s, d)
Graphs.has_vertex(g::MultigraphWrap, i) = has_vertex(g.g, i)
Graphs.inneighbors(g::MultigraphWrap{T}, i) where T = inneighbors(g.g, i)
Graphs.outneighbors(g::MultigraphWrap{T}, i) where T = outneighbors(g.g, i)
Graphs.ne(g::MultigraphWrap) = mapreduce(e->e.mul, +, edges(g.g))
Graphs.nv(g::MultigraphWrap) = nv(g.g)
Graphs.vertices(g::MultigraphWrap) = vertices(g.g)
Graphs.is_directed(g::MultigraphWrap) = is_directed(g.g)
function Graphs.edges(g::MultigraphWrap)
out = SimpleEdge[]
for e in edges(g.g)
for m in 1:e.mul
push!(out, SimpleEdge(e.src, e.dst))
end
end
return out
end
function gen_distances(g::MultigraphWrap; inc=.1)
edgearray = edges(g)
distances = zeros(length(edgearray))
for i in 2:Base.length(edgearray)
if edgearray[i] == edgearray[i-1]
distances[i] = distances[i-1] + inc
end
end
return distances
end
g = Multigraph(3)
add_edge!(g, 1, 2, 1) # one edge
add_edge!(g, 2, 3, 2) # two edges
add_edge!(g, 3, 1, 3) # three edges
gwrap = MultigraphWrap(g)
# random layout becaus adjecency matrix does not work on my type
# graphplot(gwrap; layout=_->Point2f.([(0,0),(1,1),(0,1)]), curve_distance=gen_distances(gwrap))
# update 27.01.2023
graphplot(gwrap; layout=_->Point2f.([(0,0),(1,1),(0,1)]),
curve_distance=gen_distances(gwrap),
curve_distance_usage=true) |
Awesome! That looks straightforward. Once we start adding multigraph visualization to our package, I'm happy to just include a wrapper type like that internally in our code (our multigraphs actually get determined implicitly by the tensor network where there are multiple indices contracted between pairs of tensors, so we would never really have a |
Well, for the context of plotting I don't really like the approach of grouping multiple edges into one. There is a lot of code which depends on the fact that the Also, displaying the multiple edges as curvy lines would be yet another interface for that feature besides |
Gotcha, I think I understand. Perhaps one approach could be to make an extension package to |
Does that sound reasonable? I suppose we would have to think about how keyword arguments like edge labels and things like that get forwarded. |
Yeah something like this could work, but is probably harder to maintain instead of just exporting the wrapper (or better: an alternative Multigraph-type) to the end user and let them do the conversion of the arguments themself. For example one would need to "hand craft" conversion for every single new argument. But let me know when you've found a nice solution for |
For ITensor, I think I would just define something like But for the sake of exposing multigraph plotting functionality through Based on the multigraphs example, it looks like @Roger-luo, @ChenZhao44, do you have an opinion about this? |
Thanks for the visualization tool for Graphs.ne(g::MultigraphWrap) = ne(g.g; count_mul = true) instead of Graphs.ne(g::MultigraphWrap) = mapreduce(e->e.mul, +, edges(g.g)) to get the number of simple edges. As for |
That is cleaner, thanks @ChenZhao44. @ChenZhao44, @hexaeder, maybe an interface solution to this could be the following. What if # Internal fallback definition
graphmakie_edges(g) = edges(g)
# This could be overloaded externally
function GraphMakie.graphmakie_edges(g::Multigraphs.Multigraph)
out = SimpleEdge[]
for e in edges(g.g)
for m in 1:e.mul
push!(out, SimpleEdge(e.src, e.dst))
end
end
return out
end and additionally a similar @ChenZhao44, I was not suggesting or considering using Perhaps, knowing now that |
letting you know that the code aboive doesn't work as it should tested for
any ideas why ? |
Hm you need to use graphplot(gwrap; layout=_->Point2f.([(0,0),(1,1),(0,1)]),
curve_distance=gen_distances(gwrap),
curve_distance_usage=true) so explicitly set Lines 376 to 387 in 6c40e58
Not sure if this is the best possible default. |
@mtfishman Maybe this is of interest to you JuliaGraphs/MetaGraphsNext.jl#40 . My motivation is also to have a I personally find it quite a big decision to migrate all Maybe with the introduction of weak dependencies, we can again discuss about putting a weak dependency to Multigraphs.jl, and i.e. dealing with this as an exception. Basically wrapping it up around |
I think both are nearly interchangable. Either define Either way there probably needs to be a new (tbh I really hate the whole |
Hi @hexaeder,
Thanks again for the great package. We are currently using it very successfully as a backend for visualizing tensor networks in ITensors.jl (through add-on packages like ITensorGLMakie).
Do you support or plan to support plotting multigraphs? I see that Plots.jl has some support: https://docs.juliaplots.org/latest/graphrecipes/examples/#Multigraphs and there is a Multigraphs.jl package, but over all the support for multigraphs is a bit lacking in the Julia ecosystem. I imagine it doesn't need a special graph type, just some extra keyword arguments passed to
graphplot
optionally indicating the multiplicity (and maybe directions) of the edges.For the application of tensor network visualization, directed multigraphs are quite common. Right now, out of simplicity, I just handle the multigraph case with a simple graph that has edge labels indicating there are multiple edges, but ultimately it would be nice to visualize multigraphs directly.
Time permitting, I would be interested in helping out with adding that as a feature (though I am not so familiar with the design and internals of Makie).
Cheers,
Matt
The text was updated successfully, but these errors were encountered: