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.
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
layoutattribute. The node position is accessible from outside the plot objectpas an observable usingp[:node_pos]. - plot edges as
edgeplot-plot - if
arrow_showplot arrowheads asscatter-plot - plot nodes as
scatter-plot - if
nlabels!=nothingplot node labels astext-plot - if
elabels!=nothingplot 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}orVector{Point}that determines the base layout. Can also be any network layout from NetworkLayout.jl, likeSpring,Stress,Spectral, etc.node_color=automatic: Defaults toscatter_theme.colorin absence ofilabels.node_size=automatic: Defaults toscatter_theme.markersizein absence ofilabels. Otherwise choses node size based onilabelssize.node_marker=automatic: Defaults toscatter_theme.markerin absence ofilabels.node_strokewidth=automaticDefaults toscatter_theme.strokewidthin absence ofilabels.node_attr=(;): List of kw arguments which gets passed to thescattercommandedge_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_linestyle=:solid: Linestyle of edges. Can also be vector or dict for per-edge styling. When using different linestyles for different edges, GraphMakie creates separate line plots for each edge rather than combining them into one plot, which may reduce performance for graphs with many edges. For optimal performance with large graphs, use homogeneous linestyles.edge_attr=(;): List of kw arguments which gets passed to the underlyinglinescommand used for plotting edges.arrow_show=Makie.automatic:Bool, indicate edge directions with arrowheads? Defaults toGraphs.is_directed(graph).arrow_marker='โค'arrow_size=scatter_theme.markersize: Size of arrowheads.arrow_shift=0.5: Shift arrow position from source (0) to dest (1) node. Ifarrow_shift=:end, the arrowhead will be placed on the surface of the destination node (assuming the destination node is circular).arrow_attr=(;): List of kw arguments which gets passed to thescattercommand
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.colornlabels_offset=nothing:PointorVector{Point}(in data space)nlabels_fontsize=labels_theme.fontsizenlabels_attr=(;): List of kw arguments which gets passed to thetextcommand
Inner node labels
Put labels inside the marker. If labels are provided, change default attributes to node_marker=Circle, node_strokewidth=1 and node_color=:gray80. The node_size will match size of the ilabels.
ilabels=nothing:Vectorwith label for each nodeilabels_color=labels_theme.colorilabels_fontsize=labels_theme.fontsizeilabels_attr=(;): List of kw arguments which gets passed to thetextcommand
Edge labels
The base position of each label is determined 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, :center): Anchor of text field.elabels_side = :left: Side of the edge to put the edge label textelabels_distance=Makie.automatic: Pixel distance of anchor to edge. The direction is decided based onelabels_sideelabels_shift=0.5: Position between src and dst of edge.elabels_rotation=Makie.automatic: Angle of text per label. Ifnothingthis will be determined by the edge angle. Ifautomaticit will also point upwards making it easy to read.elabels_offset=nothing: Additional offset in data spaceelabels_color=labels_theme.colorelabels_fontsize=labels_theme.fontsizeelabels_attr=(;): List of kw arguments which gets passed to thetextcommand
Self edges / loops:
selfedge_size=Makie.automatic(): Size of selfloop (dict/vector possible).selfedge_direction=Makie.automatic(): Direction of center of the selfloop asPoint2(dict/vector possible).selfedge_width=Makie.automatic(): Opening of selfloop in rad (dict/vector possible).- Note: If valid waypoints are provided for selfloops, the selfedge attributes above will be ignored.
High level interface for curvy edges:
force_straight_edges=false: Iftrue, ignore all curvy edge attributes and draw all edges as straight lines.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 provided
tangentsorwaypointswill overrule this property.curve_distance_usage=Makie.automatic():If
Makie.automatic(), only plot double edges in a curvy way. Other options aretrueandfalse.
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.
Note: Tangents are ignored on selfloops if no waypoints are provided.
Waypoints along edges:
waypoints=nothingSpecify 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=nothingIf the attribute
waypoint_radiusisnothingor:splinethe waypoints will be crossed using natural cubic spline interpolation. If number (dict/vector possible), the waypoints won't be reached, instead they will be connected with straight lines which bend in the given radius around the waypoints.
Passing arguments
The recipe can handle a range of argument types. For all the arguments that support a collection of configurations per element, you pass-in a Vector. However you can also pass in a Dict or a DefaultDict to only specify a configuration for a specific element of interest, while the rest get the default value. The keys of the Dictionaries are the Int index of the element or the Edge when reasonable. See some demonstration on Changes of node and label sizes, Dict and DefaultDict and Use Dict{Edge} for edge arguments.
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))
endPredefined 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 magnifies 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 dragging 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. ```