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}
  • it is far more simple to draw header as pure TikZ image ... welcome to TeX.SE! – Zarko May 24 '17 at 19:13
  • @noodles do you know the bytefield package? Because your example looks like the perfect job for it. – Mike May 24 '17 at 19:25
  • @Mike I wish I had known before^^ – noodles May 24 '17 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 '17 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. – John Kormylo May 24 '17 at 21:44
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

  • 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 '17 at 21:26
  • Not really. You can use a \makebox inside the node, but you still have to give it the width. – John Kormylo May 24 '17 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 '17 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. – John Kormylo May 24 '17 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 '17 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}
  • 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 '17 at 20:53

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.