8

I am new here to Tikz and I need to draw 2 rows of nodes that are identical in size but having different text of different length in it. Sure the upper and lower nodes should have enough room for the longest of the two texts. The upper nodes should be aligned to the lower ones and have the same size.

To be specific, I need to draw the following picture using Tikz:

enter image description here

2
  • 1
    Welcome to TeX.SX! Please provide a MWE showing some code illustrating your problem. A MWE begins with \documentclass{...}, the required \usepackage's, \begin{document}, and \end{document}. That may seem not easy for you, but think of the extra work it represents for TeX.SX users willing to give you a hand. Help them help you.
    – AboAmmar
    Aug 7, 2014 at 0:16
  • 1
    Please see my updated answer for a solution without hard-coded widths; LaTeX does all the calculations. Aug 7, 2014 at 1:50

4 Answers 4

5

A possible TikZ free solution with automatic width calculation and allowing multi-line texts (a TikZ solution is below):

enter image description here

The command \EightTexts has eight mandatory arguments and LaTeX performs all necessary calculations using simple conditional tests on the length of the corresponding strings. The code in the image was produced using

\EightTexts{Small}{Medium}{Large}{Larger}{AA}{Even larger}{B}{The largest}

\vskip1cm

\EightTexts{AAAA}{B}{CCCCC}{DD}{EEEEEEEEE}{FFFFF}{GG}{HHHHHHHH}

The complete code:

\documentclass{article}
\usepackage{varwidth}

\newlength\mylenai
\newlength\mylenbi
\newlength\mylenMaxi
\newlength\mylenaii
\newlength\mylenbii
\newlength\mylenMaxii
\newlength\mylenaiii
\newlength\mylenbiii
\newlength\mylenMaxiii
\newlength\mylenaiv
\newlength\mylenbiv
\newlength\mylenMaxiv

\newsavebox\myboxi
\newsavebox\myboxii
\newsavebox\myboxiii
\newsavebox\myboxiv
\newsavebox\myboxv
\newsavebox\myboxvi
\newsavebox\myboxvii
\newsavebox\myboxviii

\newcommand\TikZEightTexts[8]{%
% Save the texts in boxes so we can measure their widths. 
\savebox\myboxi{\begin{varwidth}{\textwidth}#1\end{varwidth}}
\savebox\myboxii{\begin{varwidth}{\textwidth}#2\end{varwidth}}
\savebox\myboxiii{\begin{varwidth}{\textwidth}#3\end{varwidth}}
\savebox\myboxiv{\begin{varwidth}{\textwidth}#4\end{varwidth}}
\savebox\myboxv{\begin{varwidth}{\textwidth}#5\end{varwidth}}
\savebox\myboxvi{\begin{varwidth}{\textwidth}#6\end{varwidth}}
\savebox\myboxvii{\begin{varwidth}{\textwidth}#7\end{varwidth}}
\savebox\myboxviii{\begin{varwidth}{\textwidth}#8\end{varwidth}}
% Choose maximum width between width of first box and fifth box
% store the maximum in `\mylenMaxi`
\setlength\mylenMaxi{\the\wd\myboxi}%
\setlength\mylenai{\the\wd\myboxi}%
\setlength\mylenbi{\the\wd\myboxv}%
\ifdim\mylenbi>\mylenai\relax
  \setlength\mylenMaxi{\mylenbi}
\fi
% Choose maximum width between the width of second box and the 
% width of sixth box; store the maximum in `\mylenMaxii`
\setlength\mylenMaxii{\the\wd\myboxii}%
\setlength\mylenaii{\the\wd\myboxii}%
\setlength\mylenbii{\the\wd\myboxvi}%
\ifdim\mylenbii>\mylenaii\relax
  \setlength\mylenMaxii{\mylenbii}
\fi
% Choose maximum width between the width of third box and the 
% width of seventh box; store the maximum in `\mylenMaxiii`
\setlength\mylenMaxiii{\the\wd\myboxiii}%
\setlength\mylenaiii{\the\wd\myboxiii}%
\setlength\mylenbiii{\the\wd\myboxvii}%
\ifdim\mylenbiii>\mylenaiii\relax
  \setlength\mylenMaxiii{\mylenbiii}
\fi
% Choose maximum width between the width of fourth box and the 
% width of eighth box; store the maximum in `\mylenMaxiv`
\setlength\mylenMaxiv{\the\wd\myboxiv}%
\setlength\mylenaiv{\the\wd\myboxiv}%
\setlength\mylenbiv{\the\wd\myboxviii}%
\ifdim\mylenbiv>\mylenaiv\relax
  \setlength\mylenMaxiv{\mylenbiv}
\fi
\noindent
\fbox{\parbox[c][1.2cm][c]{\mylenMaxi}{\centering#1}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxii}{\centering#2}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxiii}{\centering#3}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxiv}{\centering#4}}%
\bigskip\par\noindent
\fbox{\parbox[c][1.2cm][c]{\mylenMaxi}{\centering#5}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxii}{\centering#6}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxiii}{\centering#7}}\hfill
\fbox{\parbox[c][1.2cm][c]{\mylenMaxiv}{\centering#8}}\par
}

\begin{document}

\TikZEightTexts{Small}{Medium}{Large}{Larger}{AA}{Even larger}{B}{The 3 lines\\largest solution\\ever}

\vskip1cm

\TikZEightTexts{AAAA \\ AAAAAAAA \\ AAA}{B}{CCCCC}{DD}{EEEEEEE}{FFFFF}{GG \\ GGG }{HH \\ HH}

\end{document}

A solution using TikZ has been required in comments; here it is:

\documentclass{article}
\usepackage{varwidth}
\usepackage{tikz}
\usetikzlibrary{positioning}

\newlength\mylenai
\newlength\mylenbi
\newlength\mylenMaxi
\newlength\mylenaii
\newlength\mylenbii
\newlength\mylenMaxii
\newlength\mylenaiii
\newlength\mylenbiii
\newlength\mylenMaxiii
\newlength\mylenaiv
\newlength\mylenbiv
\newlength\mylenMaxiv

\newsavebox\myboxi
\newsavebox\myboxii
\newsavebox\myboxiii
\newsavebox\myboxiv
\newsavebox\myboxv
\newsavebox\myboxvi
\newsavebox\myboxvii
\newsavebox\myboxviii

\newcommand\TikZEightTexts[8]{%
% Save the texts in boxes so we can measure their widths. 
\savebox\myboxi{\begin{varwidth}{\textwidth}#1\end{varwidth}}
\savebox\myboxii{\begin{varwidth}{\textwidth}#2\end{varwidth}}
\savebox\myboxiii{\begin{varwidth}{\textwidth}#3\end{varwidth}}
\savebox\myboxiv{\begin{varwidth}{\textwidth}#4\end{varwidth}}
\savebox\myboxv{\begin{varwidth}{\textwidth}#5\end{varwidth}}
\savebox\myboxvi{\begin{varwidth}{\textwidth}#6\end{varwidth}}
\savebox\myboxvii{\begin{varwidth}{\textwidth}#7\end{varwidth}}
\savebox\myboxviii{\begin{varwidth}{\textwidth}#8\end{varwidth}}
% Choose maximum width between width of first box and fifth box
% store the maximum in `\mylenMaxi`
\setlength\mylenMaxi{\the\wd\myboxi}%
\setlength\mylenai{\the\wd\myboxi}%
\setlength\mylenbi{\the\wd\myboxv}%
\ifdim\mylenbi>\mylenai\relax
  \setlength\mylenMaxi{\mylenbi}
\fi
% Choose maximum width between the width of second box and the 
% width of sixth box; store the maximum in `\mylenMaxii`
\setlength\mylenMaxii{\the\wd\myboxii}%
\setlength\mylenaii{\the\wd\myboxii}%
\setlength\mylenbii{\the\wd\myboxvi}%
\ifdim\mylenbii>\mylenaii\relax
  \setlength\mylenMaxii{\mylenbii}
\fi
% Choose maximum width between the width of third box and the 
% width of seventh box; store the maximum in `\mylenMaxiii`
\setlength\mylenMaxiii{\the\wd\myboxiii}%
\setlength\mylenaiii{\the\wd\myboxiii}%
\setlength\mylenbiii{\the\wd\myboxvii}%
\ifdim\mylenbiii>\mylenaiii\relax
  \setlength\mylenMaxiii{\mylenbiii}
\fi
% Choose maximum width between the width of fourth box and the 
% width of eighth box; store the maximum in `\mylenMaxiv`
\setlength\mylenMaxiv{\the\wd\myboxiv}%
\setlength\mylenaiv{\the\wd\myboxiv}%
\setlength\mylenbiv{\the\wd\myboxviii}%
\ifdim\mylenbiv>\mylenaiv\relax
  \setlength\mylenMaxiv{\mylenbiv}
\fi
\noindent
\begin{tikzpicture}[every node/.append style={
draw,minimum height=1.3cm,align=center}
]
\node[text width=\mylenMaxi] (11) {#1};
\node[text width=\mylenMaxii,right= of 11] (12) {#2};
\node[text width=\mylenMaxiii,right= of 12] (13) {#3};
\node[text width=\mylenMaxiv,right= of 13] (14) {#4};
\node[text width=\mylenMaxi,below=of 11] (21) {#5};
\node[text width=\mylenMaxii,right= of 21] (22) {#6};
\node[text width=\mylenMaxiii,right= of 22] (23) {#7};
\node[text width=\mylenMaxiv,right= of 23] (24) {#8};
\end{tikzpicture}%
}

\begin{document}

\TikZEightTexts{Small}{Medium}{Large}{Larger}{AA}{Even larger}{B}{The 3 lines\\largest solution\\ever}

\vskip1cm

\TikZEightTexts{AAAA \\ AAAAAAAA \\ AAA}{B}{CCCCC}{DD}{EEEEEEE}{FFFFF}{GG \\ GGG }{HH \\ HH}

\end{document}

enter image description here

11
  • Thank you Medina, but here you have made all boxes of the same size. Besides, in your first solution you don't know the width in advance.
    – user59280
    Aug 7, 2014 at 1:28
  • 1
    @Power_Project Ah, I think I know what you want. Please see my updated answer. No need to do anything. LaTeX can do all the measurements for you :) Aug 7, 2014 at 1:45
  • Thank you for this great and very helpful solution. Please do not remove it but I need to perform this within Tikz because this is part of a larger picture that is written in a \tikzpicture environment. I will be thankful if you can add the tikz approach.
    – user59280
    Aug 7, 2014 at 1:55
  • 1
    @Power_Project TikZ approach added :) Aug 7, 2014 at 2:01
  • 1
    @Power_Project You're welcome. The code is fairly easy once you know how it works: looking at this bit: \settowidth\mylenMaxi{#1}% \settowidth\mylenai{#1}% \settowidth\mylenbi{#5}% \ifdim\mylenbi>\mylenai\relax \setlength\mylenMaxi{\mylenbi} \fi the idea is to compare the widths og the first and fifth strings; initially the max width is set to be the one of the first string and then a conditional test is used; if the width of the fifth string is bigger thatn the one of the first string, the max is updated to be the one of the fifth string. Aug 7, 2014 at 2:35
7

You can use a tikz matrix which simplifies the placement, and creation of node markers, and then \draw the boxes after:

enter image description here

Code:

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

% http://tex.stackexchange.com/questions/33703/extract-x-y-coordinate-of-an-arbitrary-point-in-tikz
\newdimen\XCoordA
\newdimen\XCoordB
\newdimen\YCoordA
\newdimen\YCoordB
\newcommand{\ExtractMinX}[3]{%
    % #1 = csname to hold min x value
    % #2 = coordinate 1
    % #3 = coordinate 2
    \path (#2); \pgfgetlastxy{\XCoordA}{\YCoordA};%
    \path (#3); \pgfgetlastxy{\XCoordB}{\YCoordB};%
    \ifdim\XCoordA<\XCoordB
        \edef#1{\XCoordA}%
    \else
        \edef#1{\XCoordB}%
    \fi
}%
\newcommand{\ExtractMaxX}[3]{%
    % #1 = csname to hold max x value
    % #2 = coordinate 1
    % #3 = coordinate 2
    \path (#2); \pgfgetlastxy{\XCoordA}{\YCoordA};%
    \path (#3); \pgfgetlastxy{\XCoordB}{\YCoordB};%
    \ifdim\XCoordA>\XCoordB
        \edef#1{\XCoordA}%
    \else
        \edef#1{\XCoordB}%
    \fi
}%

\tikzset{My Matrix Node Style/.style={every node/.style={draw=none, minimum height=5ex, anchor=base, row sep=15.0ex, column sep=5.0em}}}


\begin{document}
\begin{tikzpicture}
\pgfsetmatrixcolumnsep{2.0em}
\matrix (M) [matrix of nodes, My Matrix Node Style] {
    Small & Medium & Larger Text & Even Larger Text \\[2.0ex]
    Even larger text & Larger Text & Medium & Small \\
};
% Now draw the boxes based on the min and max x value for each column
\foreach \x in {1,...,4} {% for each column
    \ExtractMinX{\MinX}{M-1-\x.south west}{M-2-\x.south west}%
    \ExtractMaxX{\MaxX}{M-1-\x.north east}{M-2-\x.north east}%
    \foreach \y in {1,...,2} {% for each row
        \coordinate (Left Bottom) at (\MinX,\YCoordA |- M-\y-\x.south west);
        \coordinate (Right Top) at   (\MaxX,\YCoordB |- M-\y-\x.north east);
        \draw [red, rounded corners=3pt, thick]
            (Left Bottom) rectangle (Right Top);
    }
}
\end{tikzpicture}
\end{document}
1

This simple thing needs no tikz:

\documentclass{article}
\usepackage{calc}
\newlength\mylen

\settowidth\mylen{Even larger text}

\newcommand{\row}[4]{%
\fbox{\makebox[\mylen][c]{\rule[-0.55ex]{0ex}{1.2em}#1}}%
\hfill
\fbox{\makebox[\mylen][c]{\rule[-0.55ex]{0ex}{1.2em}#2}}%
\hfill
\fbox{\makebox[\mylen][c]{\rule[-0.55ex]{0ex}{1.2em}#3}}%
\hfill
\fbox{\makebox[\mylen][c]{\rule[-0.55ex]{0ex}{1.2em}#4}}%
}

\begin{document}

\noindent
\row{Small}{Medium}{Larger text}{Even larger text}

\vspace{1cm}
\noindent
\row{Even larger text}{Larger text}{Medium}{Small}

\end{document}

enter image description here

1
  • Thank you Kumar, but you have fixed the width of the box at first. What I need is a stretchable box which can accommodate for the longer text.
    – user59280
    Aug 7, 2014 at 1:24
0

So, probably you need to use the \phantom{} command. Here is a MWE but I am sure you will get the idea:

\documentclass[border=0.125cm,tikz]{standalone}
\usetikzlibrary{positioning,calc}
\begin{document}
\begin{tikzpicture}[blk/.style={rounded corners, minimum height=.7cm,draw,align=center},node distance=2cm,line width=1pt]

\node (a) [blk] at (0,0){\phantom{small no 2}\\Small\\ \phantom{small no 2}};
\node (b) [blk,below=of a] {\phantom{Small}\\small no 2\\ \phantom{Small;/}};
\node (c) [blk,right=of a] at (0,0){\phantom{short}\\very long text\\ \phantom{short}};
\node (d) [blk,below=of c] {\phantom{very long text}\\short\\ \phantom{very long text}};

\end{tikzpicture}
\end{document}

The out as you need is:

enter image description here

1
  • Simplest and smartest!! But I have learned a lot from the above solutions. Thanks @AboAmmar.
    – user59280
    Oct 25, 2014 at 23:22

You must log in to answer this question.