GraphPlot¶
Status: Stable
documented, exercised by the test suite and/or worked examples, with no known limitations recorded.
Description¶
GraphPlot[g, opts]
gives a Graphics object drawing the graph g (or a list of rules {u -> v, ...}). The default layout is deterministic: tidy layered trees for branching forests, layered drawings for DAGs, stress majorization otherwise, with components packed side by side. Options: GraphLayout -> "StressEmbedding" | "SpringElectricalEmbedding" | "CircularEmbedding" | "LayeredEmbedding" | "BipartiteEmbedding" | "GridEmbedding"; VertexCoordinates -> {{x,y}, ...} or {v -> {x,y}, ...}; VertexLabels -> None | "Name" | Automatic | {v -> lbl, ...}; GraphHighlight -> {v, e, ...} (red, thicker); VertexStyle and EdgeStyle -> a colour or {item -> colour, ...}; EdgeLabels -> "EdgeWeight" | {e -> lbl}; VertexSize -> d (diameter in edge lengths). Directed edges get arrowheads that stop at the target vertex. Other options (ImageSize, PlotLabel, ...) pass through to Graphics.
Examples (13)¶
Every input below was run against the current Mathilda build and its output recorded.
Basic examples (6)¶
In[1]:= Head[GraphPlot[PetersenGraph[]]]
Out[1]= Graphics
In[2]:= Count[GraphPlot[CompleteGraph[6]], _Line, Infinity]
Out[2]= 15
In[3]:= Count[GraphPlot[Graph[{1 -> 2, 2 -> 3, 3 -> 1}]], _Arrow, Infinity]
Out[3]= 3
In[4]:= {Axes, AspectRatio} /. Rest[List @@ GraphPlot[CycleGraph[4]]]
Out[4]= {False, Automatic}
In[5]:= Length[Union[Cases[GraphPlot[GridGraph[{4, 4}]], Disk[{x_, _}, _] :> Round[x, 0.001], Infinity]]]
Out[5]= 4
In[6]:= GraphPlot[5]
Out[6]= GraphPlot[5]
Options (3)¶
In[7]:= Cases[GraphPlot[PathGraph[{1, 2, 3}], VertexCoordinates -> {{0, 0}, {1, 0}, {2, 1}}], Disk[p_, _] :> p, Infinity]
Out[7]= {{0.0, 0.0}, {1.0, 0.0}, {2.0, 1.0}}
In[8]:= Count[GraphPlot[CycleGraph[5], VertexLabels -> "Name"], _Text, Infinity]
Out[8]= 5
In[9]:= MemberQ[GraphPlot[CycleGraph[3], GraphHighlight -> {1}], RGBColor[1., 0., 0.], Infinity]
Out[9]= True
Applications (4)¶
The result is an ordinary Graphics object
A list of rules is plotted as its Graph
An explicit layout method
In[12]:= MatchQ[GraphPlot[CompleteGraph[4], GraphLayout -> "CircularEmbedding"], _Graphics]
Out[12]= True
Labels sit beside each vertex on its widest gap
Algorithm¶
graphplot.c - GraphPlot[g, opts]: draw a graph as a Graphics[...] expression, plus the drawing helpers GraphPlot shares with HypergraphPlot (glayout.h).
Pipeline¶
1. Layout (glayout.c): GraphLayout -> Automatic (tidy trees for branching
forests, layered DAGs, stress majorization otherwise), or an explicit
embedding; VertexCoordinates overrides any subset of the positions.
2. Size: vertex disks get a radius scaled to the median edge length and the
layout extent, so a 10-vertex and a 1000-vertex graph both read.
3. Frame (gd_frame): labels are placed beside their vertex on the side
with the widest angular gap between incident edges, and the world box
and page size are solved together so labels are never clipped.
4. Emit: edges (Line, or Arrow shortened to stop at the target disk, with
Arrowheads sized to the disks; mutual pairs u->v, v->u offset apart),
then vertex disks with a thin darker rim, then labels.
The output uses only primitives every renderer draws -- Line, Arrow, Disk, Circle, Text, colour and Thickness/Arrowheads directives -- with AspectRatio -> Automatic, Axes -> False and an explicit PlotRange/ImageSize. Colours: vertices RGBColor[0.368417, 0.506779, 0.709798] (ColorData[97][1]), edges a medium grey-blue, GraphHighlight in red and thicker, as Mathematica.
Memory (SPEC section 4): returns a freshly-allocated Graphics tree; the evaluator frees res. Nothing borrowed from res outlives the call.
Implementation notes¶
Algorithm. builtin_graph_plot draws a graph as a Graphics[...] expression
through a four-stage pipeline. (1) Layout (glayout_compute, in
src/graph/glayout.c): GraphLayout -> Automatic chooses by structure — a tidy
tree for a branching forest (leaves in DFS order, parents centred over their
children), a layered drawing for a DAG, and stress majorization (SMACOF on
BFS graph distances) for everything else; the explicit methods are
"CircularEmbedding", "SpringElectricalEmbedding" (Hu's spring-electrical model
with Fruchterman-Reingold grid repulsion), "StressEmbedding",
"LayeredEmbedding"/"LayeredDigraphEmbedding", "BipartiteEmbedding" and
"GridEmbedding", an inapplicable one falling back to stress. VertexCoordinates
overrides any subset of the positions, and a complete spec skips the layout
entirely. (2) Size: the vertex-disk radius is scaled to the median edge length
and the layout extent, so a 10- and a 1000-vertex graph both read. (3) Frame
(gd_frame): each label is placed beside its vertex on the side with the widest
angular gap between incident edges, and the world box and page size are solved
together so labels are never clipped. (4) Emit: edges first (a Line when
undirected, an Arrow shortened to stop at the target disk with Arrowheads
sized to the disks, mutual pairs u->v/v->u offset apart), then vertex Disks
with a thin darker rim, then labels. GraphPlot[{rules}] plots Graph[{rules}];
options the head does not consume pass through to Graphics.
Data structures. Edges are read via graph_edge_indices into integer endpoint
arrays (eu/ev) and a per-edge direction-bit array; coordinates live in a flat
double xy[] buffer filled by the layout. Primitives accumulate in a GDPrims
vector and are finished (gd_finish) into a Graphics[...] tree built from only
the primitives every renderer draws — Line, Arrow, Disk, Circle, Text
and colour/Thickness/Arrowheads directives — with AspectRatio -> Automatic,
Axes -> False and an explicit PlotRange/ImageSize. Vertex colour is
RGBColor[0.368417, 0.506779, 0.709798] (ColorData[97][1]), edges a medium
grey-blue, GraphHighlight red and thicker, matching Mathematica.
Complexity / limits. Cost is dominated by the layout: stress majorization is
O(n^2) per sweep (large components skip the per-sweep majorization), the
all-pairs BFS distance matrix is O(n (V + E)), and the exact graph centre used
to seed BFS layouts is computed only up to 2000 vertices. The output is a
Graphics object — a renderable drawing, not a machine value — so, like other
graphics heads, GraphPlot carries no NDArray/Compile fast path.
Protected. Implemented insrc/graph/graphplot.cover the layout enginesrc/graph/glayout.c. Deterministic: no random numbers anywhere, so the same graph always gives an identicalGraphicsexpression.- Default layout (
GraphLayout -> Automatic): a forest with a branching vertex is drawn as tidy layered trees (hanging from the tree centre, or from the source of an arborescence); an all-directed acyclic graph as a layered drawing; everything else (paths and cycles included) by stress majorization (SMACOF on BFS graph distances, weightsd^-2), started from Pivot MDS. Components of up to 60 vertices also try circle starts and Tutte (barycentric) starts from shortest cycles, and keep, among the drawings within 10% of the least stress, the one with the fewest edge crossings; a crossing-free drawing may cost up to 2.5x the stress when it removes at least four crossings (so the dodecahedron comes out as its Schlegel diagram while the cube stays the textbook Necker cube). Each drawing is rotated to a canonical orientation (principal axis horizontal; snapped to the axes when the edges are four-fold, then straightened so grids come out exactly as grids; vertex 1 on top when there is no preferred axis). Every connected component is laid out on its own and the components are shelf-packed, largest first, with isolated vertices gathered into a square block. - Cost: full stress majorization up to 1000 vertices per component, Pivot
MDS (50 pivots,
O(k (n + m))) above that. A 500-vertex random graph takes about 0.15 s, a 25x20 grid 0.03 s. GraphLayoutvalues:"StressEmbedding","SpringElectricalEmbedding"(Hu's spring-electrical model, exact repulsion up to 1000 vertices, grid cut-off above),"CircularEmbedding"(VertexListorder, vertex 1 on top),"LayeredEmbedding"/"LayeredDigraphEmbedding"(longest-path layers for a DAG, BFS layers from the centre otherwise, dummy vertices on long edges, barycentre crossing reduction, isotonic-regression x placement; wide shallow drawings get taller layer spacing),"BipartiteEmbedding"(the two parts in two columns, barycentre-ordered; falls back to stress for a non-bipartite graph),"GridEmbedding"(VertexListorder on a square grid).VertexCoordinates -> {{x1, y1}, ...}(one pair per vertex,VertexListorder) fixes the drawing;VertexCoordinates -> {v -> {x, y}, ...}fixes the given vertices and lays out the rest.VertexLabels -> None(default) |"Name"|Automatic|True|Alllabels each vertex with its name;{v -> lbl, ...}labels only those. A label sits beside its vertex on the side with the widest angular gap between the incident edges (upper right when free), in 10 pt Helvetica, and the frame grows so no label is clipped.- Directed edges are
Arrows with anArrowheadsdirective sized to the vertex disks; each arrow starts outside its source disk and its tip stops just short of the target disk. A mutual pairu -> v,v -> uis drawn as two arrows offset to either side. GraphHighlight -> {v, ..., e, ...}: highlighted vertices and edges are drawn red (RGBColor[1, 0, 0]), vertices 15% larger and edges 2.5x thicker, on top of the others. Edges may be writtenu <-> v,UndirectedEdge[u, v],u -> vorDirectedEdge[u, v].VertexStyle -> styleor{v -> style, ...};EdgeStyle -> styleor{e -> style, ...}(a colour, or a list of directives), e.g. a vertex colouring fromFindVertexColoring.EdgeLabels -> "EdgeWeight"writes each weight at its edge midpoint (offset towards the inside of the drawing);EdgeLabels -> {e -> lbl, ...}labels chosen edges.VertexSize -> dsets the disk diameter todedge lengths.- Look: vertices are disks in
RGBColor[0.368417, 0.506779, 0.709798](Mathematica'sColorData[97]blue) with a thin darker rim, edges 1.1 pt in grey-blueRGBColor[0.571589, 0.586483, 0.699215], the disk radius scaled to the median edge length and the extent of the drawing. The result carriesPlotRange,AspectRatio -> Automatic,Axes -> Falseand an explicitImageSize -> {w, h}(300 pt on the long side, growing gently with the vertex count), soExport["g.pdf", GraphPlot[g]]gives a tight, equal-aspect picture. - Unevaluated on a non-graph, or when an argument after the graph is not a rule.
Attributes: Protected.
References¶
See also: ImageSize, VertexList, FindVertexColoring
- E. R. Gansner, Y. Koren and S. North, Graph drawing by stress majorization, in Graph Drawing (GD 2004), LNCS 3383, Springer (2005) 239-250.
- Y. Hu, Efficient, high-quality force-directed graph drawing, The Mathematica Journal 10 (2005) 37-71.
- T. M. J. Fruchterman and E. M. Reingold, Graph drawing by force-directed placement, Software: Practice and Experience 21 (1991) 1129-1164.
- Source:
src/graph/graphplot.c - Specification:
docs/spec/builtins/graphs.md - Tests:
tests/test_graph.c - Tests:
tests/test_graphplot.c
Notes & additional examples¶
Notes¶
GraphPlot[g] returns a Graphics[...] expression drawing g, built from plain
primitives (Line, Arrow, Disk, Circle, Text), so it renders anywhere
Graphics does. Because that object is large and layout-dependent, the examples
above probe it with Head or MatchQ rather than printing the drawing itself.
The vertex positions come from GraphLayout: Automatic picks a tidy tree for a
forest, a layered drawing for a DAG, and stress-majorization placement otherwise,
while "CircularEmbedding", "SpringElectricalEmbedding", "StressEmbedding",
"LayeredEmbedding", "BipartiteEmbedding" and "GridEmbedding" request a
specific method. VertexCoordinates pins any subset of the vertices, and options
GraphPlot does not itself consume (such as ImageSize or PlotLabel) pass
through to the enclosing Graphics. A bare list of edge rules is plotted as the
corresponding Graph.