3

I want to have rectangular nodes exactly one above the other. I tried using fit and it seems to make the nodes larger than the input, so the nodes overlap.

This is for something like a vertical stacked bar chart. So one element has to have the smallest size, and the others need to have an exact size relative to that one. In order to have the whole graphic as low as possible, I want the smallest size to just be able to accommodate a single line label. All other heights are calculated relative to the smallest size.

As a consequence, I need to use a library which lets me calculate relative sizes, I can't just put in the exact size as a number.

The whole stack is also to the right of another part of the grapic, and it is connected by lines to it. So I need nodes (which have anchors) and cannot use simple rectangles.


\documentclass[a4paper,10pt]{article}

\usepackage{tikz}
\usetikzlibrary{fit}

\begin{document}



    \begin{tikzpicture}[x=1pt, y=1pt]
 [align=center, node distance=0pt]


  \newlength{\distanceFromLeft}
  \setlength{\distanceFromLeft}{150pt}


  \node[fit={(0,25) (\distanceFromLeft, 50)}, draw, align=center, label=center:placeholder for left part of picture] (placeholder) {};


  \newlength{\stackWidth}
  \setlength{\stackWidth}{100pt}

  \newlength{\smallestHeight}
  \setlength{\smallestHeight}{11pt} % to accomodate a 10 pt label

  \node[fit={(\distanceFromLeft+25,0) (\distanceFromLeft+25+\stackWidth,160/51*\smallestHeight)}, draw, align=center, label=center:first node -- 160] (first) {}; % The first node represents 160 units
  \node[fit={(\distanceFromLeft+25,160/51*\smallestHeight) (\distanceFromLeft+25+\stackWidth,221/51*\smallestHeight)}, draw, align=center, label=center:second node -- 51] (second) {}; % The second node is the smallest, it has 51 units. It starts where the old node ends (height 160/51) and is 51/51 high, so its upper right corner is at height (160 + 51)/51 = 221/51 of the smallest height 
   \node[fit={(\distanceFromLeft+25,221/51*\smallestHeight) (\distanceFromLeft+25+\stackWidth,426/51*\smallestHeight)}, draw, align=center, label=center:third node -- 206] (third) {}; % The third node represents 206 units

   \draw [dashed] (placeholder.south east) -- (first.south west);
   \draw [dashed] (placeholder.north east) -- (third.north west);
 \end{tikzpicture}   

\end{document}

overlapping nodes

3

Just using positioning TikZ library and a well defined node style.

Code

\documentclass[border=2pt,tikz]{standalone}
\usetikzlibrary{positioning}

\begin{document}
    \tikzset{block/.style={shape=rectangle, draw, node distance=-1pt, minimum width = 10em, line width=1pt}}
    \begin{tikzpicture}
        \node[block] (first) {first node};
        \node[block,below=of first] {second node};
    \end{tikzpicture}
\end{document}

Result

enter image description here

Update 1

You can get such stacked nodes with relative positioning and variable height by using positioning and minimum width/height too. The rest of the figure can be drawn by placing lines between nodes anchors.

    \newlength{\stackWidth}
    \setlength{\stackWidth}{100pt}

    \newlength{\smallestHeight}
    \setlength{\smallestHeight}{11pt}

    \tikzset{block2/.style={shape=rectangle, draw, node distance=-1pt, minimum width = \stackWidth, line width=1pt, inner sep=0pt}}
    \begin{tikzpicture}
        \begin{scope}[every node/.style={block2}]
            \node[minimum height=\smallestHeight] (second) {second node};
            \node[minimum height=3\smallestHeight,below=of second] (first) {first node};
            \node[minimum height=4\smallestHeight,above=of second] (third) {third node};
        \end{scope}
    \end{tikzpicture}

enter image description here

Update 2

From your code, to get non overlapping nodes add \tikzset{every node/.append style={inner sep=0pt}}.

enter image description here

  • And how do I define the exact size and coordinates of the rectangle when using the positioning library? – rumtscho Jul 6 '16 at 16:35
  • Positioning just offers more convenient placement options. You can control the rectangle size with minimum width and minimum height, but with these two keys you can't fix the rectangle size if node's content exceed the minimums. – OSjerick Jul 6 '16 at 16:47
  • I need an exact size, not a minimum size. This is why I used fit and not positioning - it was my understanding that fit gives me an exact size. – rumtscho Jul 6 '16 at 16:48
  • Do you need a fixed size in centimeters or something, or in function of the largest content between nodes? – OSjerick Jul 6 '16 at 16:48
  • 1
    Coordinates, size and relative position are linked. Which of these can you act upon ? OSjerick answer seems very much OK with your question. Maybe you should give more details of what you have and what you want to achieve. EDIT: plus your question title "stacking nodes" is clearly what he does and what you apparently don't want to do. – Christoph Frings Jul 6 '16 at 16:49
4

I understand, that nodes in stack differs in its heights, which you like to calculate from relative size (in provided picture are written in nodes in stack) of something, i.e. you like to obtain something like this:

enter image description here

Code for this can be quite simple and concise, if you employ two more TikZ libraries: calc and chains

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

\newlength{\smallestHeight}
\setlength{\smallestHeight}{0.2pt} % <-- define units of nodes heights

\begin{document}
    \begin{tikzpicture}[
node distance = 0pt and 22mm,
  start chain = A going above,
 block/.style = {shape=rectangle, draw, line width=1pt,
                 minimum height=#1\smallestHeight, minimum width = 100pt,  
                 inner sep=0pt, outer sep=0pt, on chain=A}
                        ]
\node[block=160]    {first node - 160};    %A-1
\node[block=51]     {second node - 51};
\node[block=206]    {third node - 206};    %A-3
%
\node[block=100, left=of $(A-1.north west)!0.5!(A-3.south west)$]   {placeholder};
%
\draw[dashed]   (A-4.north east) -- (A-3.north west)
                (A-4.south east) -- (A-1.south west);
    \end{tikzpicture}
\end{document}
  • @rumtscho, I wonder, if my answer fit some of your expectations. Please, notify me. – Zarko Jul 6 '16 at 18:34
  • yes, this seems to do what I need. I need to read some more about chain to see how I can create the stuff which actually goes where the placeholder is. – rumtscho Jul 8 '16 at 7:01
  • glad to hear this. happy TeX-ing! – Zarko Jul 8 '16 at 7:17
2

Another solution with a rectangle split shape. As this kind of shapes doesn't consider a minimum height for vertically split nodes, a \parbox has been used to define different heights in each part.

\documentclass[tikz,border=2mm]{standalone} 
\usetikzlibrary{positioning,shapes.multipart}

\newcommand{\textbox}{\parbox[c][1cm][c]{3cm}{\centering #1}}
\begin{document}
\begin{tikzpicture}

\node[draw] (ph) {placeholder};

\node[rectangle split, rectangle split parts=3, draw, right=2cm of ph] (mem) 
       {\parbox[c][1cm][c]{3cm}{\centering third node - 206}
        \nodepart{two}second node - 51
        \nodepart{three}\parbox[c][1cm][c]{3cm}{\centering first node - 160}};

\draw[dashed] (ph.north east)--(mem.north west);
\draw[dashed] (ph.south east)--(mem.south west);
\end{tikzpicture}
\end{document}

enter image description here

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.