6

I am trying to create a latex table the way i am used to (no tikz matrices), but now want to use that table in tikz and draw lines from specific cells to others. Therefore I need to fit tikz nodes to my cells which also contain multicolumns and multirows.

I wonder if I can, somehow, determine the row height of the table to set the nodes minimum height to that. This at least worked for the width (since I have fixed cell widths, it was possible to calculate this).

My current code looks like this (might look disturbing):

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture]{ \node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {#4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolumn{16}{|c}{Identification} & \multicolumn{3}{|c}{Flags} & \multicolumn{13}{|c|}{Fragment Offset} \\\hline

        \multicolumn{32}{|c|}{Source Address}\\\hline

        \multicolumn{32}{|c|}{Destination Address}\\\hline

        \multicolumn{24}{|c}{Options} & \multicolumn{8}{|c|}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

Picture: MWE Picture

Is there any way to achieve fitting without expanding the row heights? Preferably using a latex table... But if there is something similar to multicols for tikz matrices I would consider switching :)

Thank you very much in advance

EDIT: With John Kormylo's improvements my line heights are now fine, as you can see: After adding strut and setting node baseline

However since i have changed the remaining multicolumns to my custom multicolx I realized that it wasn't such a great idea to just multiply the length of a "bit" by the number of spanning columns. Now some nodes aren't wide enough to fill the outer multicolumn...

Updated source code:

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{ \node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolx{16}{|c}{tbl-id}{Identification} & \multicolx{3}{|c}{tbl-flag}{Flags} & \multicolx{13}{|c|}{tbl-frag}{Fragment Offset} \\\hline

        \multicolx{32}{|c|}{tbl-src}{Source Address}\\\hline

        \multicolx{32}{|c|}{tbl-dest}{Destination Address}\\\hline

        \multicolx{24}{|c}{tbl-opts}{Options} & \multicolx{8}{|c|}{tbl-pad}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}
5
  • it is far more simple to draw header as pure TikZ image ... welcome to TeX.SE!
    – Zarko
    May 24, 2017 at 19:13
  • @noodles do you know the bytefield package? Because your example looks like the perfect job for it.
    – Mike
    May 24, 2017 at 19:25
  • @Mike I wish I had known before^^
    – noodles
    May 24, 2017 at 20:58
  • Although, I really like the result of Zarko's answer. Before marking the question solved, I would still like to known whether it is possible to expand a nodes dimensions to fit a multicolumn (or how to get a rows height to do that manually).
    – noodles
    May 24, 2017 at 21:04
  • The default row height is \arraystretch\ht\strutbox and the default depth is \arraystretch\dp\strutbox. It appears that the default value of \arraystretch is 1. May 24, 2017 at 21:44

2 Answers 2

5

You can place the baseline correctly using [baseline=(#3.text)]. You can make all the nodes the same height by including a \strut inside the node. The [anchor=base] has no effect here since there is only one node in each tikzpicture.

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{\node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolumn{16}{|c}{Identification} & \multicolumn{3}{|c}{Flags} & \multicolumn{13}{|c|}{Fragment Offset} \\\hline

        \multicolumn{32}{|c|}{Source Address}\\\hline

        \multicolumn{32}{|c|}{Destination Address}\\\hline

        \multicolumn{24}{|c}{Options} & \multicolumn{8}{|c|}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

demo


The problem with the revised MWE has to do with the width of the lines being drawn not being included in the calculation. The following isn't a perfect fit since the correction should differ for {|c|} and {c|}.

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{ \node[inner sep=0pt,draw, color=red,minimum width={#1*4mm-.75pt}] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolx{16}{|c}{tbl-id}{Identification} & \multicolx{3}{|c}{tbl-flag}{Flags} & \multicolx{13}{|c|}{tbl-frag}{Fragment Offset} \\\hline

        \multicolx{32}{|c|}{tbl-src}{Source Address}\\\hline

        \multicolx{32}{|c|}{tbl-dest}{Destination Address}\\\hline

        \multicolx{24}{|c}{tbl-opts}{Options} & \multicolx{8}{|c|}{tbl-pad}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

demo 2

6
  • Yet so simple and yet so useful! Thank you for pointing that out :) I have added both modifications and applied multicolx to all other multicolumn entries... height is fine but my calculated width isn't perfect - especially in longer lines (rounding errors?)... Is there a simple (and more elaborate) trick to force nodes to use the whole line width?
    – noodles
    May 24, 2017 at 21:26
  • Not really. You can use a \makebox inside the node, but you still have to give it the width. May 24, 2017 at 22:00
  • Could it be, that the problem isn't rounding errors (values are treated as lengths->no truncation) but rather I did not regard the widths of the vertical lines :/? My approach becomes less promising every second :P
    – noodles
    May 24, 2017 at 22:20
  • You might find that the [draw] option is making the boxes slightly larger. Tikz centers lines on the edges, so half the line width is outside. May 24, 2017 at 22:31
  • So in the end the calculation I would have to do depends on the number of nodes itself. edit: meh! not on the number of nodes but on their position
    – noodles
    May 24, 2017 at 23:04
3

Far more simple is drawn your table/image:

![enter image description here

For example, your MWE (with correct IP v4 header structure ... consider RFC 1122, RFC 2474 and RFC 2481) as pure TikZ image:

\documentclass[tikz,margin=3mm]{standalone}
\usetikzlibrary{chains, positioning}

\begin{document}
    \begin{tikzpicture}[
node distance = 0mm,
  start chain = going right,
     N/.style = {draw, 
                 minimum width=#1 mm,
                 outer sep=0pt,
                 text height=2ex, text depth=0.5ex,
                 on chain},
                        ]
%--- 1
\node (n11) [N=20,right] at (0,0)        {version};
\node (n12) [N=20]  {IHL};
\node (n13) [N=30]  {DS fiesld};
\node (n14) [N=10]  {ECN};
\node (n15) [N=80]  {Total Length};
%--- 2
\node (n21) [N=80,
      below right=of n11.south west]    {Identification};
\node (n22) [N=15]  {Flags};
\node (n23) [N=65]  {Fragment Offset};
%--- 3
\node (n31) [N=40,
      below right=of n21.south west]    {Time to Leave};
\node (n32) [N=40]  {Protocol};
\node (n33) [N=80]  {Header Checksum};
%--- 4,5,6
\node (n41) [N=160,
      below right=of n31.south west]    {Source Address};
\node (n51) [N=160,below=of n41]        {Destination Address};
\node (n61) [N=160,below=of n51]        {Options + Padding (if any)};
%----------------
\foreach \i in {0,4,8,14,16,19,32}
    \draw (5*\i/10,0.4) -- ++ (0,0.2)
    \ifnum\i<31
                     node[midway,right=-1pt,font=\tiny] {\i}
    \else
                     node[midway,left=-1pt,font=\tiny] {31}
    \fi;
\node (00) [above=4mm of n14.north east] {IPv4 Header};
%---
    \end{tikzpicture}
\end{document}
1
  • Neat :) I would not have thought it could be done that easy by using chains. And thanks for pointing me at the RFC updates... I have just copied the header from the origin of origins RFC791
    – noodles
    May 24, 2017 at 20:53

You must log in to answer this question.

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