Layout Interface
At its core, each layout algorithm is a mapping
graph ↦ node_positions
where each layout has several parameters. The main goal of the following interface is to keep the separation between parameters and function call. Each layout is implemented as subtype of AbstractLayout
.
NetworkLayout.AbstractLayout
— TypeAbstractLayout{Dim,Ptype}
Abstract supertype for all layouts. Each layout Layout <: AbstractLayout
needs to implement
layout(::Layout, adj_matrix)::Vector{Point{Dim,Ptype}}
which takes the adjacency matrix representation of a network and returns a list of node positions. Each Layout
object holds all of the necessary parameters.
The type parameters specify the returntype Vector{Point{Dim,Ptype}}
:
Dim
: the dimensionality of the layout (i.e. 2 or 3)Ptype
: the type of the returned points (i.e.Float32
orFloat64
)
By implementing layout
the Layout also inherits the function-like property
Layout(; kwargs...)(adj_matrix) -> node_positions
Therefore, each LayoutAlgorithm <: AbstractLayout
is a functor and can be passed around as a function graph ↦ node_positions
which encapsulates all the parameters. This is handy for plotting libraries such as GraphMakie.jl.
There are some additional guidelines:
- All of the parameters should be keyword arguments, i.e. it should be allways possible to call
LayoutAlgorithm()
without specifying any parameters. - Algorithms should allways return
Vector{Point{Dim,Ptype}}
. If the type or dimensions can be altered use the keywordsdim
andPtype
for it. - Some parameters may depend on the specific network (i.e. length of start positions vector). If possible, there should be a fallback option (i.e. truncate the list of start positions if network is to small or append with random values).
It is convenient to define the lowercase functions
layoutalgorithm(g; kwargs...) = layout(LayoutAlgorihtm(; kwargs...), g)
which can done using this macro:
NetworkLayout.@addcall
— Macro@addcall
Annotate subtypes of AbstractLayout
to create a lowercase function call for them.
@addcall struct MyLayout{Dim, Ptype} <: AbstractLayout{Dim, Ptype}
para
end
will add the function
mylayout(g; kwargs...) = layout(MyLayout(; kwargs...), g)
Iterative Layouts
Iterative layouts are a specific type of layouts which produce a sequence of positions rather than a single list of positions. Those algorithms are implemented as subtypes of IterativeLayout
:
NetworkLayout.IterativeLayout
— TypeIterativeLayout{Dim,Ptype} <: AbstractLayout{Dim,Ptype}
Abstract supertype for iterative layouts. Instead of implementing layout
directly, subtypes Algorithm<:IterativeLayout
need to implement the iterator interface
Base.iterate(iter::LayoutIterator{<:Algorithm})
Base.iterate(iter::LayoutIterator{<:Algorithm}, state)
where the iteration item is a Vector{Point{Dim,Ptype}}
and the iteration state depends on the algorithm.
By implementing the iterator interface the Algorithm
inherits the layout
and function-like call
layout(algo::Algorithm, adj_matrix) -> node_postions
Algorithm(; kwargs...)(adj_matrix) -> node_positions
One can instantiate an iterable object LayoutIterator
NetworkLayout.LayoutIterator
— TypeLayoutIterator{T<:IterativeLayout,M<:AbstractMatrix}(algorithm, adj_matrix)
This type bundles an IterativeLayout
with an adjacency matrix to form an iterable object whose items are the node positions.
Example
for p in LayoutIterator(Stress(), adj_matrix)
# do stuff with positions p
end