5

We have already seen how to create connected graphs with nodes: Easiest way to create simple connected graphs?

Where Ross, Bernard and Michael Palmer offered very good answers.

enter image description here My question is now how to do the same with a table, without nodes but linking its elements.

Say we have this table:

\documentclass[10pt,a4paper]{article}
\usepackage{graphicx}
\begin{document}
    \begin{tabular}{c|c}
        \hline 
        ID & COLOR \\ 
        \hline 
        1 & blue \\ 
        1 & red \\ 
        1 & green \\ 
        1 & white \\ 
        \hline 
        2 & red \\ 
        2 & green \\        
    \end{tabular} 
\end{document}

What would be the easiest way to get something like this

enter image description here

PD: OK, that seems to be too easy for you. Let's complicate it a little bit, to break ties, with two tables:

enter image description here

PD2: One question, is it advisable to embed all these code in the same document or "include" it or is it better to create the picture and save it as another pdf file?

  • Perso,ally, I would make a standalone image and include the resulting .pdf via \includegraphics. – Bernard Nov 9 '17 at 23:54
  • @Bernard I find the externalize feature of tikz/pgf to be quite useful if I want to implement the image as code, as it will do the external generation and inclusion for you. – JAB Nov 9 '17 at 23:57
  • I would compile in a standalone (with the same font font size and so on, as in the main preamble.) Then include as pdf. This would speed up compilation in big projects. I would not resize in my compilation (such that font size is consistent). If I only compiled really rarely, or had a super computer just for compiling LaTeX I would include it in the main document. – Thorbjørn E. K. Christensen Nov 10 '17 at 12:15
  • I've created a new question about how to get all this with a GUI tex.stackexchange.com/questions/401264/… – skan Nov 14 '17 at 13:38
8

tikzmark is the most common method.

output of code

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\begin{document}
    \begin{tabular}{c|c}
        \hline 
        ID & COLOR \\ 
        \hline 
        1 & \tikzmark{b1}  blue  \tikzmark{b2} \\ 
        1 & \tikzmark{r1}  red  \tikzmark{r2} \\ 
        1 & \tikzmark{g1}  green  \tikzmark{g2} \\ 
        1 & \tikzmark{w1}  white  \tikzmark{w2} \\ 
        \hline 
        2 & red \\ 
        2 & green \\        
    \end{tabular}
\begin{tikzpicture}[remember picture,overlay,bend angle=45]
\draw [->] ([yshift=1ex]pic cs:b1) to[bend right] ([yshift=1ex]pic cs:w1);
\draw [->] ([yshift=1ex]pic cs:b2) to[bend left] ([yshift=1ex]pic cs:g2);
\draw [->,preaction={very thick,-,draw=white}] ([yshift=1ex]pic cs:r2) to[bend left=60,looseness=1.2] ([yshift=1ex]pic cs:w2);    
\end{tikzpicture}

\end{document}

There's really not much more to it even for your complication, place a \tikzmark{foo} where you want an arrow to start or finish, and use (pic cs:foo) as a coordinate in a tikzpicture with remember picture,overlay.

output of code

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\begin{document}

\begin{table}
    \begin{minipage}{0.45\linewidth}
    \centering
    \begin{tabular}{c|c}
        \hline 
        ID & COLOR \\ 
        \hline 
        1 & \tikzmark{b1}  blue  \tikzmark{b2} \\ 
        1 & \tikzmark{r1}  red  \tikzmark{r2} \\ 
        1 & \tikzmark{g1}  green  \tikzmark{g2} \\ 
        1 & \tikzmark{w1}  white  \tikzmark{w2} \\ 
        \hline 
        2 & red \\ 
        2 & green \\        
    \end{tabular}\tikzmark{T1}
    \caption{Foo}
    \end{minipage}
    \begin{minipage}{0.45\linewidth}
    \centering
        \tikzmark{T2}\begin{tabular}{c|c}
        \hline 
        ID & COLOR \\ 
        \hline 
        1 & \tikzmark{b2-1}  blue  \tikzmark{b2-2} \\ 
        1 & \tikzmark{r2-1}  red  \tikzmark{r2-2} \\ 
        1 & \tikzmark{g2-1}  green  \tikzmark{g2-2} \\ 
        1 & \tikzmark{w2-1}  white  \tikzmark{w2-2}
        \end{tabular}
       \caption{Bar}

        \vspace{2cm}        

        \tikzmark{T3}\begin{tabular}{c|c}
        \hline 
        2 & red \\ 
        2 & green \\        
       \end{tabular}
    \caption{Baz}
    \end{minipage}
\begin{tikzpicture}[
   remember picture,overlay,
   bend angle=45,
   smallarrows/.style={-stealth},
   bigarrows/.style={
      shorten >=3mm,shorten <=3mm,
      line width=1mm,
      -stealth
   }
]
\draw [smallarrows] ([yshift=1ex]pic cs:b1) to[bend right] ([yshift=1ex]pic cs:w1);
\draw [smallarrows] ([yshift=1ex]pic cs:b2) to[bend left] ([yshift=1ex]pic cs:g2);
\draw [smallarrows,preaction={very thick,-,draw=white}] ([yshift=1ex]pic cs:r2) to[bend left=60,looseness=1.2] ([yshift=1ex]pic cs:w2);

\draw [smallarrows] ([yshift=1ex]pic cs:b2-1) to[bend right] ([yshift=1ex]pic cs:w2-1);
\draw [smallarrows] ([yshift=1ex]pic cs:b2-2) to[bend left] ([yshift=1ex]pic cs:g2-2);
\draw [smallarrows,preaction={very thick,-,draw=white}] ([yshift=1ex]pic cs:r2-2) to[bend left=60,looseness=1.2] ([yshift=1ex]pic cs:w2-2);    

\draw [bigarrows] (pic cs:T1) -- node[sloped,above] {Transformation} (pic cs:T2);
\draw [bigarrows] (pic cs:T1) -- (pic cs:T3);
\end{tikzpicture}
\end{table}

\end{document}

In hindsight though, it might be easier to add the text to the table as TikZ nodes. I.e. instead of writing blue, write \tikz[baseline=(b.base),remember picture]\node[inner sep=0pt,name=b]{blue};.

\tikz is a shortform for \begin{tikzpicture} .. \end{tikzpicture}, the baseline key is properly align the text vertically on the baseline of the table row. inner sep is set to zero to not add any additional whitespace. \node[name=a] {}; is the same as \node (a) {};.

Much better to make a macro of that of course, so for example:

output of below code

\documentclass[10pt,a4paper]{article}
\usepackage{tikz}
\newcommand{\tablenode}[2]{\tikz[baseline=(#1.base),remember picture]\node[inner sep=0pt,name=#1]{#2};}

\begin{document}
    \begin{tabular}{c|c}
        \hline 
        ID & COLOR \\ 
        \hline 
        1 & \tablenode{b}{blue} \\[10pt]
        1 & \tablenode{r}{red} \\ 
        1 & \tablenode{g}{green} \\ 
        1 & \tablenode{w}{white} \\ 
        \hline 
        2 & red \\ 
        2 & green \\        
    \end{tabular}
\begin{tikzpicture}[
  remember picture,overlay,
  >=stealth
]
\draw [->] (b) -- (r);
\draw [->] (b) to[out=180,in=180,looseness=0.6] (g);
\draw [->] (b.south east) to[out=300,in=60] (w.north east);
\draw [->,preaction={very thick,-,draw=white}] (r) to[out=0,in=0,looseness=2] (w.east);

\end{tikzpicture}
\end{document}
  • I've added a complication to break ties. – skan Nov 9 '17 at 23:28
  • 1
    @skan Moving a tikzmark is like moving a character I think, but there's not really any need to do that. To shorten a line, use shorten >/shorten <, as you mention. But instead, just use different coordinates for the start and end points of those arrows. e.g. ([yshift=1.2ex]pic cs:a) for one, and ([yshift=0.8ex]pic cs:a) for the other. You can of course add an xshift in addition to the yshift, or use ([shift={(x,y)}]pics cs:a). – Torbjørn T. Nov 11 '17 at 1:06
  • 1
    @skan See Andrew's answer. I used bend right/bend left, in my code, and you can specify an angle (e.g. bend left=70), but to explicitly set incoming/outgoing angles, use to[in=0,out=180] or whatever angles you need. – Torbjørn T. Nov 11 '17 at 1:18
  • 1
    (In hindsight, this might have been easier by using \tikz[remember picture] \node (a) {a}; to add the text in the table. Then you could access the anchors of the node directly, and so use e.g. \draw [->] (a.south) -- (b.north -| a.south); ) – Torbjørn T. Nov 11 '17 at 12:54
  • 1
    @skan \path (a) -- node{foobar} (b); – Torbjørn T. Nov 14 '17 at 15:26
8

Here is a proof of concept using a matrix of nodes to produce:

enter image description here

Here is the code:

\documentclass[tikz,border=4mm]{standalone}
\usetikzlibrary{matrix}

\begin{document}

  \begin{tikzpicture}
    \matrix (M)[matrix of nodes,
                column sep={6mm,between borders},
                row sep={1.2em,between origins},
                row 1/.style={font=\bfseries, color=blue},
                column 1/.style={nodes={minimum width=2em}},
                column 2/.style={nodes={minimum width=5em}},
     ]{ ID & COLOR \\
         1 & blue \\
         1 & red \\
         1 & green \\
         1 & white \\
         2 & red \\
         2 & green \\
     };
     \draw[thick,blue](M-1-1.south west)--(M-1-2.south east);
     \draw[blue](M-1-1.north east)--(M-7-1.south east);
     \draw[thin,blue](M-5-1.south west)--(M-5-2.south east);
     \draw[->,red] (M-2-2.east) to [out=-30, in=30]  (M-5-2.east);
     \draw[->,blue](M-3-2.east) to [out=-30, in=30]  (M-7-2.east);
     \draw[->,blue](M-2-2.west) to [out=210, in=150] (M-6-2.west);
  \end{tikzpicture}

\end{document}

Details such as having arrows "go over" other arrows are easily addressed as in the examples given in the original question. For the \matrix the main point is that the (M) after \matrix means that the nodes have labels (M-1-2), (M-1-4) etc. in the non-empty cells (with the option nodes in empty cells you can have nodes in the empty cells too). You can change (M) to anything you like. For more details see section 57.1 of the tikz manual.

By playing around with the styling of the rows and columns you can get different effects. For example, if we instead use

    \matrix (M)[matrix of nodes,
                column sep={14mm,between origins},
                row sep={1.2em,between origins},
                row 1/.style={font=\bfseries, color=blue},
                column 1/.style={nodes={minimum width=2em}},
                column 2/.style={nodes={minimum width=2em}},

then the table looks like:

enter image description here

The only differences in style here that I have used between origin for the column separation, changed the amount of separation, and I have changed the minimum width of the nodes in column 2. The net effect, of course, is that the arrows are closer to the text.

Adding extra horizontal and/or vertical rules is straightforward (although, I recommend reading what the booktabs manual has to say about vertical rulesO. Changing my choice of colours is also recommended!

Edit

If you want to draw arrows between such tables then you need to:

  • add remember picture to the tikzpicture environments
  • you need to use different labels in the different tikzpicture environments
  • you need to add overlay to tikzpicture environments that use labels from other picture environments.

All of this is explained in section 17.13 of the tikz manual (version 3.0.1a).

For example, you can draw

enter image description here

with the code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}

  \begin{tikzpicture}[remember picture]
    \matrix (M1)[matrix of nodes,
                column sep={14mm,between origins},
                row sep={1.2em,between origins},
                row 1/.style={font=\bfseries, color=blue},
                column 1/.style={nodes={minimum width=2em}},
                column 2/.style={nodes={minimum width=2em}},
     ]{ ID & COLOR \\
         1 & blue \\
         1 & red \\
         1 & green \\
         1 & white \\
         2 & red \\
         2 & green \\
     };
     \draw[thick,blue](M1-1-1.south west)--(M1-1-2.south east);
     \draw[blue](M1-1-1.north east)--(M1-7-1.south east);
     \draw[thin,blue](M1-5-1.south west)--(M1-5-2.south east);
     \draw[->,red] (M1-2-2.east) to [out=-30, in=30]  (M1-5-2.east);
     \draw[->,blue](M1-3-2.east) to [out=-30, in=30]  (M1-7-2.east);
     \draw[->,blue](M1-2-2.west) to [out=210, in=150] (M1-6-2.west);
  \end{tikzpicture}

  \hspace*{60mm}
  \begin{tikzpicture}[remember picture, overlay]
    \matrix (M2)[matrix of nodes,
                column sep={14mm,between origins},
                row sep={1.2em,between origins},
                row 1/.style={font=\bfseries, color=blue},
                column 1/.style={nodes={minimum width=2em}},
                column 2/.style={nodes={minimum width=2em}},
     ]{ ID & COLOR \\
         1 & blue \\
         1 & red \\
         1 & green \\
         1 & white \\
         2 & red \\
         2 & green \\
     };
     \draw[thick,blue](M2-1-1.south west)--(M2-1-2.south east);
     \draw[blue](M2-1-1.north east)--(M2-7-1.south east);
     \draw[thin,blue](M2-5-1.south west)--(M2-5-2.south east);
     \draw[->,red] (M2-2-2.east) to [out=-30, in=30]  (M2-5-2.east);
     \draw[->,blue](M2-3-2.east) to [out=-30, in=30]  (M2-7-2.east);
     \draw[->,blue](M2-2-2.west) to [out=210, in=150] (M2-6-2.west);
     \draw[ultra thick,orange,->](M1-3-2.east)--node[above,sloped]{transform}(M2-1-1.west);
  \end{tikzpicture}

\end{document}
  • I've added a complication to break ties. – skan Nov 9 '17 at 23:28
  • This is surely applicable to question tex.stackexchange.com/questions/400806/… ... – user4686 Nov 11 '17 at 18:03
  • @jfbu You could certainly draw the "pictures" using tikz but I don't see an easy way to use a tikz \matrix1 since the size will depend on the input. I am tempted to play with it but I spend too much time here already! :) – Andrew Nov 11 '17 at 19:07
  • 1
    @skan You accepted another answer so not sure why you’d need to know:) 1) add nodes in empty cells to the \matrix options to reference empty cells 2) load the tiklibrary calc package and then you can use ($ (M-1-1)!0.5!(M-2-1) $) for the point halfway between (M-1-1-1) and (M-2-1) 3) you can use \vspace for vertical space. The best way of arranging many of these tables probably depends on the configuration. It might be easier to put them all in one tikz \matrix, or in one tikzpicture environment, or in a tabular environment or ... It really depends on what you are doing... – Andrew Nov 14 '17 at 20:38
  • 1
    @skan :) Drawings are always a little complicated. If you are going to use many of these I would define an environment to hide most of the details. This would also simplify things slightly and make the code easier to read and debug. Happy to add details if you want them – Andrew Nov 14 '17 at 21:03
3

Here is a short solution with pstricks and eqmakebox:

   \documentclass[10pt, a4paper, table]{article}
    \usepackage[utf8]{inputenc}
    \usepackage{array, multirow, eqparbox, booktabs}

    \usepackage{graphicx}
    \usepackage{pst-node, pst-arrow}
    \usepackage{auto-pst-pdf}

    \begin{document}

     \begin{pspicture}
     \psset{linewidth=0.5pt, arrows=->, arrowinset=0.12}
        \setlength{\extrarowheight}{3pt}\fboxsep = 0pt
    \begin{tabular}{c@{\hspace{3cm}}c}
    \multirow{7.5}{*}{ \begin{tabular}{c|c}
     \hline
     ID & COLOR \\
     \hline
     1 & \pnode[0pt, 0.6ex]{B1}\eqmakebox[L]{~blue~}\pnode[0pt, 0.6ex]{B2} \\
     1 & \eqmakebox[L]{~red~}\pnode[0pt, 0.6ex]{R} \\
     1 & \eqmakebox[L]{~green~}\pnode[0pt, 0.6ex]{G}\pnode[1.5em, 0pt]{LTable} \\
     1 & \pnode[0pt, 0.6ex]{W1}\eqmakebox[L]{~white~}\pnode[0pt, 0.6ex]{W2} \\
     \hline
     2 & red \\
     2 & green
     \end{tabular}
     % node connections
     \ncarc[arcangle=-40]{B1}{W1}%
     \ncarc[arcangle=50]{R}{W2}
     \ncarc[arcangle=50, border=1pt]{B2}{G}}
     &%
     \begin{tabular}{c!{\color{red}\vrule}c}
    \arrayrulecolor{red}\specialrule{1pt}{0pt}{0pt}
     ID & COLOR \\
     \hline
     1 & \pnode[0pt, 0.6ex]{C1}\eqmakebox[L]{~blue~}\pnode[0pt, 0.6ex]{C2} \\
     1 & \eqmakebox[L]{~red~}\pnode[0pt, 0.6ex]{S} \\
    \pnode[-1em, 0pt]{RTable1} 1 & \eqmakebox[L]{~green~}\pnode[0pt, 0.6ex]{H} \\
     1 & \pnode[0pt, 0.6ex]{X1}\eqmakebox[L]{~white~}\pnode[0pt, 0.6ex]{X2} \\
     \end{tabular}
      % node connections
     \psset{linewidth=1pt}
     \ncarc[arcangle=-40]{C1}{X1}%
     \ncarc[arcangle=50]{S}{X2}
     \ncarc[arcangle=50, border=1pt]{C2}{H}
    \bigskip\\
     &
  \begin{tabular}{c!{\color{blue}\vrule}c}
    \arrayrulecolor{blue} \specialrule{1pt}{0pt}{0pt}
     ID & COLOR \\
     \hline
     1 & \pnode[0pt, 0.6ex]{C1}\eqmakebox[L]{~blue~}\pnode[0pt, 0.6ex]{C2} \\
     \pnode[-1em, 0pt]{RTable2}1 & \eqmakebox[L]{~red~}\pnode[0pt, 0.6ex]{T} \\
     1 & \eqmakebox[L]{~green~}\pnode[0pt, 0.6ex]{I} \\
     1 & \pnode[0pt, 0.6ex]{Y1}\eqmakebox[L]{~white~}\pnode[0pt, 0.6ex]{Y2} \\
     \end{tabular}
     % node connections
     \psset{linewidth=1pt}
     \ncarc[arcangle=-40]{C1}{Y1}%
     \ncarc[arcangle=50]{T}{Y2}
     \ncarc[arcangle=50, border=1pt]{C2}{I}
    \end{tabular}
    \psset{linewidth = 6pt, linecolor=red!80, arrowinset=0, arrowlength=0.8, opacity=0.2}%
    \ncline{LTable}{RTable1}\naput[nrot=:U]{\sffamily\color{red} Transformation 1}
    \ncline[linecolor =blue!80]{LTable}{RTable2}\nbput[nrot=:U]{\sffamily\color{blue} Transformation 2}
     \end{pspicture}

    \end{document}

enter image description here

  • I've added a complication to break ties. – skan Nov 9 '17 at 23:28
  • I see… Where is the downwards arrow supposed to point to? And how are the two tables placed with respect to each other? – Bernard Nov 9 '17 at 23:39
  • Anywhere you want, is an example – skan Nov 10 '17 at 11:18
  • Is the example I've added like you want? – Bernard Nov 10 '17 at 11:36
  • Unfortunatelly I can't run your codes. it says Error: Ghostscript exited with error code 127! C:\texlive\2017\bin\win32\runscript.tlu:708: command failed with exit code 127: perl.exe c:\texlive\2017\texmf-dist\scripts\pdfcrop\pdfcrop.pl "texstudio_BM5676-autopp.pdf" "texstudio_BM5676-pics.pdf". , I guess it has to do with the postscript, can we do it in a different way? – skan Nov 10 '17 at 11:52

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.