1. Overview

In this tutorial, we’ll discuss how to draw a graph using LaTeX.

We’ll first start by listing the main LaTeX packages that we can use for graphs, and express their particular advantages.

Then, we’ll study some examples of graphs drawn with those packages, and also their variations.

At the end of this tutorial, we’ll be able to implement a graph in a LaTeX document.

2. A Short Recap on Graphs

2.1. Components of Graphs and Their Representation

A graph G(V, E) comprises a set V of vertices and a set E of edges. The edges can be either directed or undirected, and normally connect two vertices, not necessarily distinct. For hypergraphs, edges can also connect more than two edges, but we won’t treat them here.

The standard representation of a vertex consists of the image of a circle:

Rendered by QuickLaTeX.com

If the vertex has a label, this is typed inside the circle, as is the case with the number 1 in the example above. We can also represent multiple vertices by placing them in a non-overlapping manner anywhere in the image:

Rendered by QuickLaTeX.com

The standard representation of an edge corresponds to a line for undirected edges or an arrow for directed edges:

Rendered by QuickLaTeX.com

2.2. Typical Representation of Graphs

An image that represents a graph, therefore, consists of a set of circles on an empty field and a set of lines or arrows connecting them.  Further, if the graph is a weighted graph, we can indicate the weights as labels on the edges:

Rendered by QuickLaTeX.com

And lastly, if the graph has loops, we can represent them as edges that connect a vertex to itself:

Rendered by QuickLaTeX.com

These are all the elements we need to represent a graph of any complexity. In the next section, we’ll first study the relevant packages for drawing graphs, and then see some examples of the implementation of graphs in code.

2.3. Alternative Representations of Graphs

We should also state, though, that graphical representations aren’t the only way to describe graphs intuitively. Other representations, and in particular edge lists, adjacency lists, or adjacency matrices, are also prevalent in practice.

In some cases, they may be more informative to a human reader than a drawn image of a graph. For example, a directed graph with 26 vertices V = \{A, B, ..., X, Y, Z\} and only two edges E = \{(X, Y), (X,Z)\}, is very simple to represent with formal notation:

G(V, \{(X, Y), (X,Z)\})

Its full graphical representation would however occupy a significantly vast space and be mostly uninformative. This is because, if the graph we’re using possesses more than a handful of nodes or edges, it then becomes challenging to understand its structure by looking at its image. Some extensive graphs, such as the graph representing internet nodes, possess graphical representations that, while very beautiful, are however meaningless to a human.

For this reason, if our graph holds more than a few vertices or edges, we should avoid drawing it. Instead, we should use other types of formal representations such as adjacency matrices, edge lists, or adjacency lists:

\begin{matrix}  \framebox{A} \\ \framebox{B} \\ \vdots \\\framebox{X}\rightarrow\fbox{Y}\fbox{Z} \\ \framebox{Y} \\ \framebox{Z} \\\end{matrix}

3. Tikz

We can now discuss the packages that we can use to draw graphs in LaTeX. The most common LaTeX package used for drawing, in general, is TikZ, which is a layer over PGF that simplifies its syntax. TikZ is a powerful package that comes with several libraries dedicated to specific tasks, such as:

And also, relevant for our purposes, it contains a graphdrawing library that we can use for the automatic drawing of graphs. TikZ is the standard package we use to draw graphs, and we’ll dedicate it to most of the coded examples.

3.1. Basic Graph and Nodes

Drawings in TikZ are included in the tikzpicture environment. The simplest graph we can draw comprises of one vertex with its label, represented as a circle containing, for example, a variable:

\documentclass{article} 
\usepackage{tikz} 
\begin{document} 
\begin{tikzpicture}[main/.style = {draw, circle}] 
\node[main] (1) {$x_1$}; 
\end{tikzpicture} 
\end{document}

Rendered by QuickLaTeX.com

The word main here refers to a style that we define when introducing the tikzpicture environment. In this case, we use it to tell the compiler to draw the shape of a circle for the nodes.

The most important command in the code above is \node. Its syntax is this:

\node[parameters] (nodeID) {nodeLabel};

We can use this command repeatedly to add more vertices to the graph:

\node[main] (2) [above right of=1] {$x_2$};
\node[main] (3) [below right of=1] {$x_3$}; 
\node[main] (4) [above right of=3] {$x_4$};
\node[main] (5) [above right of=4] {$x_5$}; 
\node[main] (6) [below right of=4] {$x_6$};

Rendered by QuickLaTeX.com

Notice how the term between the second pair of square brackets lets us define the position of the nodes in relation to other nodes. We can do this by using the keywords right, left, above, below, followed by a blank space, and then the keyword of and the label of the node to which they refer. This is particularly useful if we later need to rearrange the graph on the picture. In fact, by working with relative positions as opposed to absolute coordinates, we can move one anchor node around to move all others.

3.2. Adding Edges

We can also add edges by using the \draw command:

\draw[parameters] (fromWhere) -- (toWhere);

If we, for example, want to draw a line corresponding to an undirected edge between nodes (2) and (4), we can write:

\draw (2) -- (4);

Rendered by QuickLaTeX.com

If instead, we want to add an arrow for a directed edge, we can give the parameter -> to the \draw command:

\draw[->] (1) -- (2);

Rendered by QuickLaTeX.com

3.3. Distances and Widths

We can also notice that the lines appear to be too thin and that it’s difficult to distinguish between directed and undirected edges. We can make the graph more readable by passing the parameter thick to the tikzpicture environment, upon its introduction:

\begin{tikzpicture}[thick, main/.style = {draw, circle}]
...
\end{tikzpicture}

Rendered by QuickLaTeX.com

If the vertices appear too close to one another, we can also specify the parameter node distance to the tikzpicture environment to spread them further:

\begin{tikzpicture}[node distance={15mm}, thick, main/.style = {draw, circle}]
...
\end{tikzpicture}

Rendered by QuickLaTeX.com

3.4. More Challenging Edges

We may also want to connect with an edge some nodes for which the straight path intersects other edges or nodes. Say we try to connect with a straight path the nodes (1) and (5):

Rendered by QuickLaTeX.com

It doesn’t look good. Instead, we want to loop around the graph, from the outside and above node 2, and then descend back towards the graph. Luckily, we can do that by specifying a parameter looseness after declaring the initial point of a line. To better clarify where we want the edge to go, we also specify the angles out and in which indicate, respectively, the angle of the outgoing and ingoing edges:

\draw (1) to [out=135,in=90,looseness=1.5] (5);

Rendered by QuickLaTeX.com

3.5. Loops

We can use the same technique to draw loops in the graph, by indicating twice the same node as the starting and ending points of a loose line:

\draw (1) to [out=180,in=270,looseness=5] (1);

Rendered by QuickLaTeX.com

3.6. Draw Weighted Edges

If our graph is a weighted graph, we can add weighted edges as phantom nodes inside the \draw command:

\draw[->] (6) -- node[midway, above right, sloped, pos=1] {+1} (4);

Rendered by QuickLaTeX.com

With this command, we’re adding an invisible node halfway between vertices (6) and (4), and then to the top right of the edge’s middle point. The label {+1} indicates the weight of the graph. The parameters sloped and pos indicate, respectively, that we want the weight to be orthogonal to the edge, and shifted by a certain amount along the edge. We can determine by trial and error what is the correct amount, according to the size of our image.

3.7. The Full Graph

And finally, we can repeat all the instructions above to populate the graph with all edges we need:

\documentclass{article} 
\usepackage{tikz} 
\begin{document} 
\begin{tikzpicture}[node distance={15mm}, thick, main/.style = {draw, circle}] 
\node[main] (1) {$x_1$}; 
\node[main] (2) [above right of=1] {$x_2$}; 
\node[main] (3) [below right of=1] {$x_3$}; 
\node[main] (4) [above right of=3] {$x_4$}; 
\node[main] (5) [above right of=4] {$x_5$}; 
\node[main] (6) [below right of=4] {$x_6$}; 
\draw[->] (1) -- (2); 
\draw[->] (1) -- (3); 
\draw (1) to [out=135,in=90,looseness=1.5] (5); 
\draw (1) to [out=180,in=270,looseness=5] (1); 
\draw (2) -- (4); 
\draw (3) -- (4); 
\draw (5) -- (4); 
\draw[->] (5) to [out=315, in=315, looseness=2.5] (3); 
\draw[->] (6) -- node[midway, above right, sloped, pos=1] {+1} (4); 
\end{tikzpicture} 
\end{document}

Rendered by QuickLaTeX.com

4. Neuralnetwork

Another useful package for generating graphs is Neuralnetwork. This package, as the name suggests, is incredibly helpful to draw the architecture of a neural network, and in particular of feedforward neural networks.

The package simplifies the construction of layers and their manipulation. It does so by shortening all commands for a single layer to one line.

Its main advantage is in the rapidity of describing a full graph with only a few lines of code. Instead, its main disadvantage lies in the scarce customizability of the individual characteristics of the graph.

4.1. Basics of the Package

In the LaTeX package Neuralnetwork, we define graphs inside an environment with the same name:

\begin{neuralnetwork}
...
\end{neuralnetwork}

Inside this environment, we can then add layers by using the \inputlayer, \hiddenlayer, and \outputlayer commands, according respectively to whether we refer to the first, hidden, or last layer of a neural network. The syntax is similar for all three commands:

\inputlayer[count=howManyNodes, bias=trueOrFalse, nodeclass={classOfNode}] {}

The parameter count indicates the number of nodes in the given layer. The term bias indicates instead whether the bias for that layer should be counted as a separate element. In that case, this bias wouldn’t be connected to the previous layer, when links are established. Lastly, the class of the node consists of either one of the predefined classes input node, hidden node, or output node, or also any of our custom classes.

4.2. Drawing a Neural Network

We can draw a simple neural network comprising of three features in the input, a hidden layer with two neurons and a bias term, and a single neuron in the output layer. This resembles closely the structure of a neural network for XOR classification:

\documentclass{article} 
\usepackage{neuralnetwork} 
\begin{document} 
\begin{neuralnetwork} 
\inputlayer[count=3, bias=false]{} 
\hiddenlayer[count=2]{} 
\outputlayer[count=1]{} 
\end{neuralnetwork} 
\end{document}

Rendered by QuickLaTeX.com

4.3. Adding Edges and Labels

We can also add edges between each layer, by following each layer that we want to connect with its preceding layer by the \linklayers command:

...
\inputlayer[count=3, bias=false]{} \linklayers
\hiddenlayer[count=2]{} \linklayers
\outputlayer[count=1]{}
...

Rendered by QuickLaTeX.com

Notice how the yellow node, indicating the bias term in the intermediate layer, isn’t connected to the input layer. We can also add labels to the nodes, though this is somewhat tricky. The way to do it is by defining a new LaTeX command, and passing it as a parameter text to a layer:

...
\newcommand{\x}[2]{$x_#2$}
\inputlayer[count=3, bias=false, text=\x]
...

Rendered by QuickLaTeX.com

We can also follow the same criterion with the hidden layer and the output layer by creating appropriate commands:

...
  \newcommand{\h}[2]{$h_#2$}
  \newcommand{\y}[2]{$y_#2$}
...
  \hiddenlayer[count=2, text=\h]{} \linklayers
  \outputlayer[count=1, text=\y]{} \linklayers
...

Rendered by QuickLaTeX.com

The bias term in the hidden layer automatically takes the index of h_0, as is common in the literature, without having to specify any particular instructions.

4.4. Weights

We can also add weights to the edges by using a formula like the one below. We have to define a new command first, and then assign it to the default text for links:

\newcommand{\w}[4] {$w_{#2,#4}$}
\setdefaultlinklabel{\w}

Rendered by QuickLaTeX.com

Here, #1 indicates the layer of origin, #2 the node of origin, and #3 and #4 indicate layer and node of destination, respectively. Notice that, while the weights of the hidden layer look normal, some weights in the previous layer are however missing.

This is because they’re automatically rewritten by some other weights, and as a consequence, we only see some of them. The only way to address this problem is by defining all links individually and then giving them the appropriate label. We can do this by using the \link command, instead of \linklayers:

...
\inputlayer[count=3,bias=false, text=\x]{}
\hiddenlayer[count=2, text=\h]{}
\link[style={}, labelpos=near start, from layer=0, from node=1, to layer=1, to node=1]
...

Rendered by QuickLaTeX.com

The parameter labelpos is the one we use to shift towards the node of origin. In this case, the label is assumed by the edge. This, in turn, avoids the overlapping between the edges’ labels.

4.5. Finishing Touches

We can then repeat this operation with two nested \foreach loops, which will let us place all labels in the correct, readable positions:

\foreach \n in {1,...,3}{ 
    \foreach \m in {1,2}{ 
        \link[style={}, labelpos=near start, from layer=0, from node=\n, to layer=1, to node=\m] 
    } 
}

Rendered by QuickLaTeX.com

The network is now complete. We can replicate it in a LaTeX editor with this full code:

\documentclass{article}
\usepackage{neuralnetwork}
\begin{document}
\begin{neuralnetwork}
\newcommand{\x}[2]{$x_#2$}
\newcommand{\y}[2]{$y_#2$}
\newcommand{\h}[2]{$h_#2$}
\newcommand{\w}[4] {$w_{#2,#4}$}
\setdefaultlinklabel{\w}
\inputlayer[count=3, bias=false, text=\x]
\hiddenlayer[count=2, text=\h] 
\foreach \n in {1,...,3}{
    \foreach \m in {1,2}{
        \link[style={}, labelpos=near start, from layer=0, from node=\n, to layer=1, to node=\m]
    }
}
\outputlayer[count=1, text=\y] \linklayers
\end{neuralnetwork}
\end{document}

5. Converting to LaTeX Through Extensions

There’s also another option to mention that relates not so much to LaTeX packages themselves but, instead, to the automatic conversion into LaTeX code of graphs created in other graphical editors. This is particularly convenient if we’re used to drawing the graphs in other programming languages, and we’re still learning how to draw graphs in LaTeX.

There are, in fact, libraries or extension for the automatic conversion into LaTeX code of the graphical output of another editor:

  • In Python, we can convert graphs created with matplotlib into LaTeX, thanks to the library tikzplotlib
  • In MatLab, we can use the scripts from matlab2tikz to perform a similar operation
  • In Blender 2.4, we can use blend2tikz to export Blender curves into LaTeX code

6. Conclusion

In this article, we studied how to draw graphs using LaTeX.


» 下一篇: Top-N 准确率指标