13

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:

image of hypergraph

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:

attempt

4
  • 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. Commented Apr 11, 2013 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? Commented Apr 11, 2013 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). Commented Apr 14, 2013 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
    Commented Apr 14, 2013 at 15:56

2 Answers 2

9

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

enter image description here

2
  • Ergh... @ I hate it already! ;) +1!
    – hpesoj626
    Commented Apr 11, 2013 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. Commented Apr 11, 2013 at 9:47
10

enter image description here

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]);
}

add(
  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[1].bottomleft(t) .. {dir(-30)}t*e[1].center{dir(-30)} ..v[3].bottomleft(t),Arrow(HookHead));
     draw(pic,v[2].top(t){dir(80)} .. {dir(-30)}t*e[1].center{dir(-30)} ..v[4].top(t),Arrow(HookHead));
     draw(pic,v[1].right(t) .. t*e[2].center ..v[5].bottom(t),Arrow(HookHead));
     draw(pic,v[3].topleft(t){dir(120)} .. {dir(20)}(t*pe[2][0]));

     tg=-30;
     draw(pic,v[5].right(t) .. {dir(tg)}t*e[4].center{dir(tg)} ..v[6].top(t),Arrow(HookHead));
     draw(pic,v[5].right(t) .. {dir(tg)}t*e[4].center{dir(tg)} ..v[7].topright(t),Arrow(HookHead));

     tg=90;
     draw(pic,v[7].top(t) .. {dir(tg)}t*e[3].center{dir(tg)} ..v[3].right(t),Arrow(HookHead));
     draw(pic,v[7].top(t) .. {dir(tg)}t*e[3].center{dir(tg)} ..v[4].topright(t),Arrow(HookHead));

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

To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

and run latexmk -pdf hypg.tex.

2
  • Why didn't you use standalone document class? Commented Apr 11, 2013 at 10:46
  • 2
    @Karl's students: Because a standalone eps, pdf or png can be obtained simply by compiling the .asyfile?
    – g.kov
    Commented Apr 11, 2013 at 10:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .