# Typesetting a directed hypergraph in tikz

Similar to several other questions, I am trying to draw hypergraphs in tikz. I want to draw a directed hypergraph that looks something like those in this image from here:

As opposed to other questions, I do not want to draw an arc between the associated edges. Instead I want the edges to join for a segment and then split again.

I don't mind specifying the position of the join point, but I would rather not have to manually specify the angle of the incoming and outgoing edges. I would prefer that lines smoothly separate from the join point.

This is my poor attempt at recreating this figure:

\documentclass{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{tikz}

\begin{document}
\tikz{
\node [circle,draw] (v1) at (0,0)   { $v_1$ };
\node [circle,draw] (v2) at (-1,-3) { $v_2$ };
\node [circle,draw] (v3) at (2,-2)  { $v_3$ };
\node [circle,draw] (v4) at (1,-4)  { $v_4$ };
\node [circle,draw] (v5) at (3,1)   { $v_5$ };
\node [circle,draw] (v6) at (5,-1)  { $v_6$ };
\node [circle,draw] (v7) at (4,-5)  { $v_7$ };
\node [] (e1) at (1,-2) { $e_1$ };
\node [] (e2) at (2,0) { $e_2$ };
\node [] (e3) at (3,-3) { $e_3$ };
\node [] (e4) at (4,0) { $e_4$ };
%
\path
% edge 1
(v1) [-]  edge node { } (e1)
(v2) [-]  edge node { } (e1)
(e1) [->] edge node { } (v3)
(e1) [->] edge node { } (v4)
% edge 2
(v1) [-]  edge node { } (e2)
(v3) [-]  edge node { } (e2)
(e2) [->] edge node { } (v5)
% edge 3
(v7) [-]  edge node { } (e3)
(e3) [->] edge node { } (v3)
(e3) [->] edge node { } (v4)
% edge 4
(v5) [-]  edge node { } (e4)
(e4) [->] edge node { } (v6)
(e4) [->] edge node { } (v7)
;
}
\end{document}


This produces this figure:

• This is an interesting question, but would really be helpful if you composed a fully compilable MWE including \documentclass and the appropriate packages that sets up the problem. While solving problems can be fun, setting them up is not. Then, those trying to help can simply cut and paste your MWE and get started on solving the problem. – Peter Grill Apr 11 '13 at 5:25
• This recently active question and its answers will be helpful: How to draw tangent line of an arbitrary point on a path in TikZ — I’m thinking of a small modification to Jake’s answer. — You might specify how you want to input the actual connection. Do you specify one edge and say at which position the other should join continuous? Do you only want to give a point somewhere that should be connected from all three nodes? What are the specifications of these lines? – Qrrbrbirlbel Apr 11 '13 at 6:36
• You can also use the tkz-graph package: look at its documentation on page 43 (an example very similar to the first picture). – Claudio Fiandrino Apr 14 '13 at 9:52
• @ClaudioFiandrino The graphics in the tkz-graph package documentation look nice, but I do not see any hypergraphs in the produced images. Perhaps there is some hypergraph support, but I cannot read the French documentation. – Arlen Cox Apr 14 '13 at 15:56

## Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\makeatletter
\tikzset{
@pos/.style={@pos1={#1},@pos2={#1}},
@ratio/.style={@ratio1={#1},@ratio2={#1}},
@delta/.style={@delta1={#1},@delta2={#1}},
@edge/.style={@@edge/.append style={#1}},
@edge 0/.style={@@edge 0/.append style={#1}},
@edge 1/.style={@@edge 1/.append style={#1}},
@edge 2/.style={@@edge 2/.append style={#1}},
@edge 3/.style={@@edge 3/.append style={#1}},
@edge 4/.style={@@edge 4/.append style={#1}},
% and for four:
@pos1/.store in=\qrr@posA,
@pos2/.store in=\qrr@posB,
@ratio1/.store in=\qrr@ratioA,
@ratio2/.store in=\qrr@ratioB,
@delta1/.store in=\qrr@deltaA,
@delta2/.store in=\qrr@deltaB,
@pos=.5,
@ratio=.5,
@delta=.1,
}
\newcommand*{\connectThree}[4][]{
\begingroup
\tikzset{#1}
\coordinate (@aux1) at ($(#2)!\qrr@ratioA!(#3)$);
\coordinate (@aux2) at ($(#4)!\qrr@posA!(@aux1)$);
\path (@aux2) edge[@@edge/.try, @@edge 0/.try, @@edge 3/.try] (#4);
\draw[@@edge/.try, @@edge 1/.try] (@aux2) .. controls ($(#4)!\qrr@posA+\qrr@deltaA!(@aux1)$) .. (#2);
\draw[@@edge/.try, @@edge 2/.try] (@aux2) .. controls ($(#4)!\qrr@posA+\qrr@deltaA!(@aux1)$) .. (#3);
\endgroup
}
% \renewcommand*{\connectThree}[4][]{\connectFour[#1, @@edge 4/.style={draw=none}, @ratio2=0]{#2}{#3}{#4}{0,0}}

\newcommand*{\connectFour}[5][]{
\begingroup
\tikzset{#1}
\coordinate (@aux1a) at ($(#2)!\qrr@ratioA!(#3)$);
\coordinate (@aux1b) at ($(#4)!\qrr@ratioB!(#5)$);
\coordinate (@aux2a) at ($(@aux1b)!\qrr@posA!(@aux1a)$);
\coordinate (@aux2b) at ($(@aux1a)!\qrr@posB!(@aux1b)$);
\path (@aux2a) edge[@@edge/.try,@@edge 0/.try] (@aux2b);
\draw[@@edge/.try,@@edge 1/.try] (@aux2a) .. controls ($(@aux1b)!\qrr@posA+\qrr@deltaA!(@aux1a)$) .. (#2);
\draw[@@edge/.try,@@edge 2/.try] (@aux2a) .. controls ($(@aux1b)!\qrr@posA+\qrr@deltaA!(@aux1a)$) .. (#3);
\draw[@@edge/.try,@@edge 3/.try] (@aux2b) .. controls ($(@aux1a)!\qrr@posB+\qrr@deltaB!(@aux1b)$) .. (#4);
\draw[@@edge/.try,@@edge 4/.try] (@aux2b) .. controls ($(@aux1a)!\qrr@posB+\qrr@deltaB!(@aux1b)$) .. (#5);
\draw[help lines] (@aux1a) -- (@aux1b) node[midway,above,sloped,font=\tiny,shape=rectangle,inner xsep=+0pt,draw=none,align=center,fill=white,fill opacity=.75,outer ysep=\pgflinewidth,text opacity=1] {ratio: \qrr@ratioA/\qrr@ratioB\\pos: \qrr@posA/\qrr@posB\\delta: \qrr@deltaA/\qrr@deltaB};
\endgroup
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node [circle,draw] (v1) at (0,0)   { $v_1$ };
\node [circle,draw] (v2) at (-1,-3) { $v_2$ };
\node [circle,draw] (v3) at (2,-2)  { $v_3$ };
\node [circle,draw] (v4) at (1,-4)  { $v_4$ };
\node [circle,draw] (v5) at (3,1)   { $v_5$ };
\node [circle,draw] (v6) at (5,-1)  { $v_6$ };
\node [circle,draw] (v7) at (4,-5)  { $v_7$ };
\connectThree[
@edge 3=->
]{v1}{v3}{v5}
\connectThree[
@ratio=0,
@edge 1=->,
@edge 2=->
]{v6}{v7}{v5}
\connectThree[
@edge 1=->,
@edge 2=->
]{v3}{v4}{v7}
\connectFour[
@ratio=.4,
@pos1=.7,
@pos2=.5,
@edge 3=->,
@edge 4=->,
@edge=thick
]{v1}{v2}{v3}{v4}
\connectFour[@edge=blue,@edge 3=->, @edge 4={draw}, @ratio2=0]{v3}{v5}{v6}{v7}
\end{tikzpicture}
\end{document}


## Output

• Ergh... @ I hate it already! ;) +1! – hpesoj626 Apr 11 '13 at 7:54
• The lines are pretty straight because a) there only exist one control point and b) this control point is very far away from the nodes. Adding one additional control point introduces more variables to the problem. – Qrrbrbirlbel Apr 11 '13 at 9:47

Hypergraph with inline Asymptote, using flowchart module, hypg.tex:

\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}

\begin{asy}
size(0,200);
import flowchart;

pair[]pv={
(0,0)   , // pv[0], not used, included for convenient indexing nodes from pv[1]
(0,0)   ,
(-1,-3) ,
(2,-2)  ,
(1,-4)  ,
(3,1)   ,
(5,-1)  ,
(4,-5)  ,
};

pair[][] pe={  // point coordinates and a relative position of the label (N=North etc)
{(0,0),  N}  , // ev[0], not used, included for convenient indexing nodes from ev[1]
{(0.2,-2) ,N}  ,
{(2,0)  ,SE}  ,
{0.1pv[3]+0.2pv[6]+0.7pv[7],E},
{(4.5,0.75)  ,SW} ,
};

pen nodeFill=yellow+opacity(0.8);
pen nodeLine=darkblue+1.2pt+opacity(0.5);

block[] v=new block[pv.length];
block[] e=new block[pe.length];

for(int i=1;i<pv.length;++i){
v[i]=circle("$v_"+string(i)+"$",pv[i],nodeFill,nodeLine);
draw(v[i]);
}

string s;
for(int i=1;i<pe.length;++i){
s="$e_"+string(i)+"$";
e[i]=circle(s,pe[i][0]);
label(s,pe[i][0],pe[i][1]);
dot(pe[i][0]);
}

new void(picture pic, transform t) {
blockconnector operator --=blockconnector(pic,t);
real tg;
pen linePen=darkblue+0.8pt;
currentpen=linePen;
arrowfactor=4;
draw(pic,v[3].topleft(t){dir(120)} .. {dir(20)}(t*pe[2][0]));

tg=-30;

tg=90;

}
);
\end{asy}
\end{document}


To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '\$_[0]'");}

and run latexmk -pdf hypg.tex.
• Why didn't you use standalone document class? – kiss my armpit Apr 11 '13 at 10:46
• @Karl's students: Because a standalone eps, pdf or png can be obtained simply by compiling the .asyfile? – g.kov Apr 11 '13 at 10:52