6

How can I easily create this kind of graphs? (example from the Wikipedia):

enter image description here

Or something simpler such as:

enter image description here

Several nodes aligned horizontally o diagonally, with curved arrows and, if possible, with labels inside.

I'd like to get the result as a vectorial file, either svg, pdf or directly something related with latex (maybe tikz). The result it's going to be embedded in a pdf or maybe a word document.

I've tried many tools, from Inkscape to latexdraw or tikzit or R packages such as Visnetwork (that has the advantage of automatically placing the nodes) but all have some drawback, they don't let me align the nodes or finetune the arrows properly or you need one hour to create the graph. The best I've found so far seem to be Visio.

For example using visnetwork with the input:

from=c("A","A","A","A","B","B","B","C","C","D")
to=c("B","C","D","E","C","D","E","D","E","E")
nodesd=c("A","B","C","D","E")
nodes <- data.frame(id=nodesd, label= nodesd ) 
edges <- data.frame(from=from, to =to, length=150)
visNetwork(nodes,edges, width="100%" , height="100%")  %>% 
visNodes(shape = "circle") %>%  visEdges(arrows = 'to', smooth =T) 

I get this, but I need to place the nodes manually

enter image description here

but the result is not beautiful.

It would be great to get the effect of the arrow broken when it intersects another one.

Using the R library igraph I can get enter image description here

not good either.

library(igraph)
my = cbind(from, to)
g = graph_from_edgelist(my)
Lay = cbind(1:5, 5:1)
CURVE = c(0,0.15, 0.3, 0.45, 0, -0.15, -0.3, 0, 0.15, 0) 
plot(g, layout=Lay, edge.curved=CURVE)

Then, maybe is better to code it directly with some latex or graphical language or package, such as tikz, but I don't know how to start.

How can I do it?

Regards

3

TikZ provides at least two general approaches for drawing graphs. In the first approach, the user defines the placement of coordinates manually in relation to the origin. The second approach is to use a TikZ graph drawing algorithm, in which case, the algorithm determines the node placement. Several algorithms are provided, which can be classified into two broading groups: those that produce graphs of a defined shape (e.g. circular, tree, layered) versus those whose shape is not predefined (e.g. spring). TikZ provides a range of macros for modifying node placement of graphs drawing with a graph drawing algorithm.

The example posted is suitable for using a layered layout. This answer steps through the steps required for creating the graphs. This is illustrated with 5 examples.

Example 1 just grows the graph horizontally. No graph drawing algorithm is used and grow=315 is not respected here. If we want the graph to grow south-east, we have to do something else.

Example 2 uses node anchors to specifically place nodes at known locations on the canvas. Manual intervention is required to achieve the direction of growth by specifically nominating the node placement.

Example 3 introduces the use of the layered layout algorithm. It's fine for the "backbone", but if we try to add other graph elements, the algorithm will move the nodes to accommodate the new information. That's not what we want.

Example 4 uses subgraph nodes to place each of the graph relationships in relation to others. A red edge is added to illustrate how individual edges can be customized.

Example 5 illustrates how to use two different edge styles and customization of the edge bend.

The nodes are labelled to make it easier to follow the code. To turn off the labels, just add empty nodes to the graph options.

enter image description here

This is the MWE. Thanks to Michael and his answer for the node and edge formatting.

% !TeX TS-program = lualatex
\RequirePackage{luatex85}
\documentclass[a3paper]{article}
\usepackage{tikz}
\usepackage[margin=0.75cm]{geometry}

\pagestyle{empty}

\usetikzlibrary{
    graphs,
    graphdrawing
}
\usegdlibrary{
    layered,   % requied for layered layout
    trees
}

% define styles for arrows and text nodes from https://tex.stackexchange.com/a/394946
\tikzset{ 
  majoredges/.style={
    draw=eedge,
    line width=1pt,
    ->,             % alwways draw arrow tip
    >=stealth,      % style of arrow tip
    shorten >=2pt,  % shorten a bit, so that it doesn't quite
    shorten <=2pt,  % touch the nodes
    preaction={     % provide a wider white background for
      draw=white,   % each arrow for the intersection effect
      line width=3pt,
      -,            % no arrow tip for background
      }
    },
  minoredges/.style={
    draw=medge,
    line width=0.25pt,
    ->,             % alwways draw arrow tip
    >=stealth,      % style of arrow tip
    shorten >=2pt,  % shorten a bit, so that it doesn't quite
    shorten <=2pt,  % touch the nodes
    preaction={     % provide a wider white background for
        draw=white,   % each arrow for the intersection effect
        line width=3pt,
        -,            % no arrow tip for background
        }
    },
    every node/.style={
     anchor=center,
     text=black,
     inner sep=2pt,
     shape=circle,
     draw=bbord,           % border
     fill=ffill,        % background
     font=\footnotesize, 
     minimum height=15pt  % assign minimum height to make nodes equally
                          % large, regardless of letter size
   }
}

\definecolor{bbord}{RGB}{70,78,82}     % node border
\definecolor{ffill}{RGB}{171,213,238}  % node fill
\definecolor{eedge}{RGB}{27,128,196}   % major edge
\definecolor{medge}{RGB}{96,15,36}     % minor edge

\begin{document}

\textbf{Example 1}\par
Grow horizontally

\begin{tikzpicture}
\graph [
%                     % no graph drawing algorithm
%empty nodes,         % show node labels
grow=315,             % Not respected here
edges=majoredges         % use edge style defined with tikzset
]
{
a -> b -> c -!- d -> e -!- f -> g -> h -!- i; 
a ->[bend right] d; 
b ->[bend left] g;
d ->[bend left] f;
d ->[bend right] i;
e ->[bend right] h;
e ->[bend left] i;
}
;
\end{tikzpicture}



\textbf{Example 2:}\par
Anchor the nodes on the canvas (TikZ manual §27.4)

\begin{tikzpicture}[x=0.75cm,y=1.5cm]
\graph [
%                     % no graph drawing algorithm
%empty nodes,         % show node labels
grow=315,             % Not respected here
edges=majoredges         % use edge style defined with tikzset
]
{
    a -> b[x=0.5,y=-0.5] -> c[x=1,y=-1] -!- d[x=1.5,y=-1.5] -> e[x=2,y=-2] -!- f[x=2.5,y=-2.5] -> g[x=3,y=-3] -> h[x=3.5,y=-3.5] -!- i[x=4,y=-4]; 
    a ->[bend right] d; 
    b ->[bend left] g;
    d ->[bend left] f;
    d ->[bend right] i;
    e ->[bend right] h;
    e ->[bend left] i;
}
;
\end{tikzpicture}

\bigskip
\textbf{Example 3:}\par
While we can get the nodes, positioned as required using layered layout + \par grow=315 (left),
as soon as we add an extra edge a -> d,\par the structure is altered (right).

\begin{tikzpicture}
\graph [
layered layout,                     % no graph drawing algorithm
%empty nodes,         % show node labels
grow=315,             % Not respected here
edges=majoredges         % use edge style defined with tikzset
]
{
    {a -> b -> c --[draw=none] d -> e --[draw=none] f -> g -> h --[draw=none] i}; 
}
;
\end{tikzpicture}%
\begin{tikzpicture}
\graph [
layered layout,                     % no graph drawing algorithm
%empty nodes,         % show node labels
grow=315,             % Not respected here
edges=majoredges         % use edge style defined with tikzset
]
{
    {a -> b -> c --[draw=none] d -> e --[draw=none] f -> g -> h --[draw=none] i}; 
    {a ->[bend right] d}; 
}
;
\end{tikzpicture}

\textbf{Example 4:}\par
Grow south east and add subgraph nodes (TikZ manual §27.10.2)

\begin{tikzpicture}
\graph [
layered layout,      % graph drawing algorithm
%empty nodes,
grow=315,            % direction of growth of the graph
edges=majoredges
]
{
% cannot use -!- syntax here to hide the edge. compilation is in endless loop.
// [layered layout] {a -> b -> c --[draw=none] d -> e
                     --[draw=none] f -> g -> h --[draw=none] i};
// [layered layout] {a ->[bend left,red] d};
// [layered layout] {b ->[bend left] g};
// [layered layout] {d ->[bend left] f};
// [layered layout] {d ->[bend right] i};
// [layered layout] {e ->[bend right] h};
// [layered layout] {e ->[bend left] i};
};
\end{tikzpicture}

\bigskip
\textbf{Example 5:}\par
Wikipedia example: two edge types and modified edge bends

\begin{tikzpicture}
\graph [
layered layout,      % graph drawing algorithm
sibling distance=1.5cm,
layer distance=1.5cm,
%empty nodes,
grow=315,            % direction of growth of the graph
edges=majoredges
]
{
    % cannot use -!- syntax here to hide the edge. compilation is in endless loop.
    // [layered layout] {a -> b -> c --[draw=none] d -> e
        --[draw=none] f -> g -> h --[draw=none] i};
    // [layered layout] {a ->[bend right=50,red] d};
    // [layered layout] {b ->[bend left=50] g};
    // [layered layout] {d ->[bend left=30] f};
    // [layered layout] {d ->[bend right=40] g};
    // [layered layout] {d ->[bend right=50] i};
    // [layered layout] {e ->[bend left=40] h};
    // [layered layout] {e ->[bend left=40] i};
    // [layered layout] {a ->[bend left=50,minoredges] c};
    // [layered layout] {a ->[bend right=60,minoredges] e};
    // [layered layout] {a ->[bend left=50,minoredges] f};
    // [layered layout] {a ->[bend left=70,minoredges] g};
    // [layered layout] {a ->[bend left=80,minoredges] h};
    // [layered layout] {a ->[bend right=70,minoredges] i};
    // [layered layout] {b ->[bend left=70,minoredges] h};
    // [layered layout] {d ->[bend left=50,minoredges] h};
    // [layered layout] {f ->[bend right,minoredges] h};
};
\end{tikzpicture}
\end{document}
  • 1
    Hello. If I try to run it I get the error "bad box line 71 Overfull \hbox (14.35pt too wide) in paragraph. I need to split it in two. – skan Oct 9 '17 at 23:07
  • 1
    How can I use different colors for each arrow (links)? – skan Oct 9 '17 at 23:09
  • 1
    What's the advantage of using layers here? – skan Oct 9 '17 at 23:11
  • 2
    @skan The preaction code for the majoredge (row 27-31) and minoredge (row ) styles (rows 40-44). – Ross Oct 10 '17 at 10:13
  • 2
    Just replace -> with — (two minus signs) where that is required. – Ross Oct 15 '17 at 13:52
4

Here is an easy solution with pstricks:

\documentclass[border=3pt, x11names]{standalone}%

\usepackage{pst-node}
\usepackage{auto-pst-pdf}

\begin{document}
\sffamily
\psset{algebraic, yunit = -1, arrows=->, arrowinset=0.12, linecolor=SteelBlue3, fillcolor=SlateGray3!60, nodesepB=1pt}
\begin{pspicture*}
  \foreach \X[count=\I] in {A, B, C, D, E} {\Cnodeput[linecolor=SteelBlue4, fillstyle=solid]{0}(\I, \I){\X}{\X}}
  \foreach \X/\Y in{A/B, B/C, C/D, D/E}{\ncline{\X}{\Y}}
  \ncarc[arcangle=-25]{A}{D}
  \ncarc[arcangle=25]{A}{C}
  \psset{border=1pt}
  \ncarc[arcangle=-45]{A}{B}
  \ncarc[arcangle=45]{B}{C}
  \ncarc[arcangle=45]{C}{D}
  \ncarc[arcangle=-35]{B}{D}
  \ncarc[arcangle=-45]{D}{E}
\end{pspicture*}

\end{document} 

enter image description here

  • What's the parameter that controls the inclination angle of the whole series of nodes? Can I also export it to a format that MS Word can import? – skan Oct 7 '17 at 11:05
  • What's the option to prevent the arrows from touching the nodes? (add some clearance) – skan Oct 7 '17 at 11:09
  • 1
    @skan: you can add nodesepB=1pt (see the result in the updated answer). In this respect, node connections use 3 parameters: nodesep (for both ends), nodesepA (for the origin), and nodesepB (for the end). You can read more details in the documentation of pst-node. – Bernard Oct 7 '17 at 11:50
  • 1
    Yes: you have to replace \Cnodeput* with \Cnodeput[linecolor=black, fillstyle=solid]. I took the liberty to choose a dark blue colour, 'cause I find it matches better the filling colour, but of course, it's up to you… – Bernard Oct 7 '17 at 12:22
  • 1
    border (=1pt here). – Bernard Oct 10 '17 at 1:06
2

Here is a start:

\documentclass[crop,border=1pt]{standalone}

\usepackage{tikz,xcolor}

% define styles for arrows and text nodes
\tikzset{
  myarrow/.style={
    draw=blue,
    line width=1pt,
    ->,             % alwways draw arrow tip
    >=stealth,      % style of arrow tip
    shorten >=2pt,  % shorten a bit, so that it doesn't quite
    shorten <=2pt,  % touch the nodes
    preaction={     % provide a wider white background for
      draw=white,   % each arrow for the intersection effect
      line width=3pt,
      -,            % no arrow tip for background
      }
    }
}

\tikzstyle{every node}=[
     anchor=center,
     text=black,
     fill=white,
     inner sep=2pt,
     shape=circle,
     draw=blue,           % border
     fill=blue!20,        % background - blue!20 is 20% blue, 80% white
     font=\footnotesize, 
     minimum height=15pt  % assign minimum height to make nodes equally
                          % large, regardless of letter size
]


\begin{document}

\begin{tikzpicture}[x=1cm,y=1cm]  % scale coordinate system

\path                             % define points. 
(0,10) node (a) {a}               % (a) is a label that we refer to when 
(2,8)  node (b) {b}               % adding the arrows, {a} is the text content
(4,6)  node (c) {c}
(6,4)  node (d) {d}
(8,2)  node (e) {e}
;

\draw[myarrow] (a) -- (b);                % draw a straight arrow 

\draw[myarrow] (b) to [out=0,in=90] (d);  % draw a bezier-shaped arrow, specifying 
                                          % angles of departure and arrival
\draw[myarrow] (c) to [out=0,in=90,looseness=1.25] (e); % looseness tweaks the bezier shape 


\end{tikzpicture}
\end{document}

enter image description here

You can easily declare additional styles, say, myredarrow by just changing draw=blue to draw=red. If you have multiple style declarations in the same \tikzset clause, they must be separated by commas.

You can also have finer control of your bezier curves by declaring explicit control points, like so:

\draw[myarrow] (a) .. controls (c1) and (c2) .. (b);

This assumes that you have declared c1 and c2 as coordinates, like so:

\path 
(3,5) coordinate (c1)
(6,8) coordinate (c2)
;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.