GraphMakie
This is the Documentation for GraphMakie.
This Package consists of two parts: a plot recipe for graphs types from Graphs.jl and some helper functions to add interactions to those plots.
Starting from v0.3 GraphMakie.jl
switches from LightGraphs.jl
to Graphs.jl
as the for the underlying graph package. See this discourse post for more information. If you want to use LightGraphs.jl
please specifically ] add GraphMakie@0.2
!
There are also plot examples and interaction examples pages.
The graphplot
Recipe
GraphMakie.graphplot
— Functiongraphplot(graph::AbstractGraph)
graphplot!(ax, graph::AbstractGraph)
Creates a plot of the network graph
. Consists of multiple steps:
- Layout the nodes: see
layout
attribute. The node position is accessible from outside the plot objectp
as an observable usingp[:node_pos]
. - plot edges as
edgeplot
-plot - if
arrow_show
plot arrowheads asscatter
-plot - plot nodes as
scatter
-plot - if
nlabels!=nothing
plot node labels astext
-plot - if
elabels!=nothing
plot edge labels astext
-plot
The main attributes for the subplots are exposed as attributes for graphplot
. Additional attributes for the scatter
, edgeplot
and text
plots can be provided as a named tuples to node_attr
, edge_attr
, nlabels_attr
and elabels_attr
.
Most of the arguments can be either given as a vector of length of the edges/nodes or as a single value. One might run into errors when changing the underlying graph and therefore changing the number of Edges/Nodes.
Attributes
Main attributes
layout=Spring()
: functionAbstractGraph->Vector{Point}
determines the base layoutnode_color=scatter_theme.color
node_size=scatter_theme.markersize
node_marker=scatter_theme.marker
node_attr=(;)
: List of kw arguments which gets passed to thescatter
commandedge_color=lineseg_theme.color
: Color for edges.edge_width=lineseg_theme.linewidth
: Pass a vector with 2 width per edge to get pointy edges.edge_attr=(;)
: List of kw arguments which gets passed to thelinesegments
commandarrow_show=Makie.automatic
:Bool
, indicate edge directions with arrowheads? Defaults toGraphs.is_directed(graph)
.arrow_size=scatter_theme.markersize
: Size of arrowheads.arrow_shift=0.5
: Shift arrow position from source (0) to dest (1) node.arrow_attr=(;)
: List of kw arguments which gets passed to thescatter
command
Node labels
The position of each label is determined by the node position plus an offset in data space.
nlabels=nothing
:Vector{String}
with label for each nodenlabels_align=(:left, :bottom)
: Anchor of text field.nlabels_distance=0.0
: Pixel distance from node in direction of align.nlabels_color=labels_theme.color
nlabels_offset=nothing
:Point
orVector{Point}
(in data space)nlabels_textsize=labels_theme.textsize
nlabels_attr=(;)
: List of kw arguments which gets passed to thetext
command
Edge labels
The base position of each label is determinded by src + shift*(dst-src)
. The additional distance
parameter is given in pixels and shifts the text away from the edge.
elabels=nothing
:Vector{String}
with label for each edgeelabels_align=(:center, :bottom)
: Anchor of text field.elabels_distance=0.0
: Pixel distance of anchor to edge.elabels_shift=0.5
: Position between src and dst of edge.elabels_opposite=Int[]
: List of edge indices, for which the label should be displayed on the opposite sideelabels_rotation=nothing
: Angle of text per label. Ifnothing
this will be determined by the edge angle!elabels_offset=nothing
: Additional offset in data spaceelabels_color=labels_theme.color
elabels_textsize=labels_theme.textsize
elabels_attr=(;)
: List of kw arguments which gets passed to thetext
command
Curvy edges & self edges/loops
edge_plottype=Makie.automatic()
: Eitherautomatic
,:linesegments
or:beziersegments
.:beziersegments
are much slower for big graphs!
Self edges / loops:
selfedge_size=Makie.automatic()
: Size of self-edge-loop (dict/vector possible).selfedge_direction=Makie.automatic()
: Direction of self-edge-loop asPoint2
(dict/vector possible).selfedge_width=Makie.automatic()
: Opening of selfloop in rad (dict/vector possible).
High level interface for curvy edges:
curve_distance=0.1
:Specify a distance of the (now curved) line to the straight line in data space. Can be single value, array or dict. User proivded
tangents
orwaypoints
will overrule this property.curve_distance_usage=Makie.automatic()
:If
Makie.automatic()
, only plot double edges in a curvy way. Other options aretrue
andfalse
.
Tangents interface for curvy edges:
tangents=nothing
:Specify a pair of tangent vectors per edge (for src and dst). If
nothing
(or edge idx not in dict) draw a straight line.tfactor=0.6
:Factor is used to calculate the bezier waypoints from the (normalized) tangents. Higher factor means bigger radius. Can be tuple per edge to specify different factor for src and dst.
Waypoints along edges:
waypoints=nothing
Specify waypoints for edges. This parameter should be given as a vector or dict. Waypoints will be crossed using natural cubic splines. The waypoints may or may not include the src/dst positions.
waypoint_radius=nothing
: If number (dict/vector possible) bent lines within radius of waypoints.
Network Layouts
The layout algorithms are provided by NetworkLayout.jl
. See the docs for a list of available layouts.
A layout has to be a function f(g::AbstractGraph) -> pos::Vector{Point}
. You can also provide your own layouts or use other packages like LayeredLayouts.jl
for DAG (see also the Dependency Graph of a Package example).
using LayeredLayouts
function mylayout(g::SimpleGraph)
xs, ys, _ = solve_positions(Zarate(), g)
return Point.(zip(xs, ys))
end
Predefined Interactions
GraphMakie.jl
provides some pre-built interactions to enable drag&drop of nodes and edges as well as highlight on hover.
To try them all use the following code in a GLMakie
environment.
using GLMakie
using GraphMakie
using Graphs
g = wheel_graph(10)
f, ax, p = graphplot(g, edge_width=[3 for i in 1:ne(g)],
node_size=[10 for i in 1:nv(g)])
deregister_interaction!(ax, :rectanglezoom)
register_interaction!(ax, :nhover, NodeHoverHighlight(p))
register_interaction!(ax, :ehover, EdgeHoverHighlight(p))
register_interaction!(ax, :ndrag, NodeDrag(p))
register_interaction!(ax, :edrag, EdgeDrag(p))
GraphMakie.NodeHoverHighlight
— FunctionNodeHoverHeighlight(p::GraphPlot, factor=2)
Magnifies the node_size
of node under cursor by factor
.
Example
julia> g = wheel_graph(10)
julia> f, ax, p = graphplot(g, node_size = [20 for i in 1:nv(g)])
julia> register_interaction!(ax, :nodehover, NodeHoverHighlight(p))
GraphMakie.EdgeHoverHighlight
— FunctionEdgeHoverHeighlight(p::GraphPlot, factor=2)
Magnifies the edge_width
of edge under cursor by factor
. If arrow_size isa Vector{<:Real}
it also magnefies the arrow scatter.
Example
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, edge_width = [3 for i in 1:ne(g)],
arrow_size=[10 for i in 1:ne(g)])
julia> register_interaction!(ax, :nodehover, EdgeHoverHighlight(p))
GraphMakie.NodeDrag
— FunctionNodeDrag(p::GraphPlot)
Allows drag and drop of Nodes. Please deregister the :rectanglezoom
interaction.
Example
julia> g = wheel_graph(10)
julia> f, ax, p = graphplot(g, node_size = [10 for i in 1:nv(g)])
julia> deregister_interaction!(ax, :rectanglezoom)
julia> register_interaction!(ax, :nodehover, NodeHoverHighlight(p))
julia> register_interaction!(ax, :nodedrag, NodeDrag(p))
GraphMakie.EdgeDrag
— FunctionEdgeDrag(p::GraphPlot)
Allows drag and drop of Edges. Please deregister the :rectanglezoom
interaction.
Example
julia> g = wheel_graph(10)
julia> f, ax, p = graphplot(g, edge_width = [3 for i in 1:ne(g)])
julia> deregister_interaction!(ax, :rectanglezoom)
julia> register_interaction!(ax, :edgehover, EdgeHoverHighlight(p))
julia> register_interaction!(ax, :edgedrag, EdgeDrag(p))
Interaction Interface
GraphMakie.jl
provides some helper functions to register interactions to your graph plot. There are special interaction types for hovering, clicking and draging nodes and edges. For more information on the axis interaction please consult the Makie.jl
docs.
The general idea is to create some handler type, provide some action function and register it as an interaction with the axes.
Click Interactions
GraphMakie.NodeClickHandler
— FunctionNodeClickHandler(fun)
Initializes ClickHandler
for nodes. Calls function
fun(idx, event, axis)
on left-click events where idx
is the node index.
Example
julia> using Makie.Colors
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, node_size=30, node_color=[colorant"red" for i in 1:nv(g)])
julia> function action(idx, event, axis)
p.node_color[][idx] = rand(RGB)
p.node_color[] = p.node_color[]
end
julia> register_interaction!(ax, :nodeclick, NodeClickHandler(action))
GraphMakie.EdgeClickHandler
— FunctionEdgeClickHandler(fun)
Initializes ClickHandler
for edges. Calls function
fun(idx, event, axis)
on left-click events where idx
is the edge index.
Example
julia> using Makie.Colors
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, edge_width=4, edge_color=[colorant"black" for i in 1:ne(g)])
julia> function action(idx, event, axis)
p.edge_color[][idx] = rand(RGB)
p.edge_color[] = p.edge_color[]
end
julia> register_interaction!(ax, :edgeclick, EdgeClickHandler(action))
Hover Interactions
GraphMakie.NodeHoverHandler
— FunctionNodeHoverHandler(fun)
Initializes HoverHandler
for nodes. Calls function
fun(hoverstate, idx, event, axis)
with hoverstate=true
on hover and false
at the end of hover. idx
is the node index.
Example
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, node_size = [20 for i in 1:nv(g)])
julia> function action(state, idx, event, axis)
p.node_size[][idx] = state ? 40 : 20
p.node_size[] = p.node_size[] #trigger observable
end
julia> register_interaction!(ax, :nodehover, NodeHoverHandler(action))
GraphMakie.EdgeHoverHandler
— FunctionEdgeHoverHandler(fun)
Initializes HoverHandler
for edges. Calls function
fun(hoverstate, idx, event, axis)
with hoverstate=true
on hover and false
at the end of hover. idx
is the edge index.
Example
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, edge_width = [3.0 for i in 1:ne(g)])
julia> function action(state, idx, event, axis)
p.edge_width[][idx] = state ? 6.0 : 3.0
p.edge_width[] = p.edge_width[] #trigger observable
end
julia> register_interaction!(ax, :edgehover, EdgeHoverHandler(action))
Drag Interactions
GraphMakie.NodeDragHandler
— FunctionNodeDragHandler(fun)
Initializes DragHandler
for Nodes. Calls function
fun(dragstate, idx, event, axis)
where dragstate=true
during the drag and false
at the end of the drag, the last time fun
is triggered. idx
is the node index.
Example
julia> g = wheel_digraph(10)
julia> f, ax, p = graphplot(g, node_size=20)
julia> deregister_interaction!(ax, :rectanglezoom)
julia> function action(state, idx, event, axis)
p[:node_pos][][idx] = event.data
p[:node_pos][] = p[:node_pos][]
end
julia> register_interaction!(ax, :nodedrag, NodeDragHandler(action))
GraphMakie.EdgeDragHandler
— FunctionEdgeDragHandler(fun)
Initializes DragHandler
for Edges. Calls function
fun(dragstate, idx, event, axis)
where dragstate=true
during the drag and false
at the end of the drag, the last time fun
is triggered. idx
is the edge index.
See EdgeDrag
for a concrete implementation. ```