Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm having problem with a TikZ picture - I've got rectangles that I've split, but for some reason the split rectangles are a bit larger than the other rectangles, causing the the alignment to get messed up:

enter image description here

Any ideas on how to solve this? I've included the code below.

\documentclass[a4paper, 11pt]{article}

\usepackage[rgb,hyperref]{xcolor}
\usepackage{tikz}

% Define colors
\definecolor{shade1}{rgb}{0.9, 0.9, 0.9}
\definecolor{shade2}{rgb}{0.75, 0.75, 0.75}
\definecolor{shade3}{rgb}{0.5, 0.5, 0.5}
\definecolor{shade4}{rgb}{0.35, 0.35, 0.35}

% Load TikZ libraries
\usetikzlibrary{shapes,arrows}
\usetikzlibrary{fit}
\usetikzlibrary{backgrounds}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}

% Text settings
\newcommand{\figureTextSize}{\tiny}

% Figure element lengths
\newlength{\gpgpuElemSep}
\setlength{\gpgpuElemSep}{1mm}
\newlength{\gpgpuElemSize}
\setlength{\gpgpuElemSize}{8mm}

% TikZ styles
\newcommand{\arrowStyle}{stealth}
\newcommand{\bendAngle}{45}
\newcommand{\lineThickness}{semithick}
\tikzstyle{box} = [%
  draw,
  rectangle,
  \lineThickness,
]



\begin{document}
\begingroup
\figureTextSize
\begin{tikzpicture}[%
    every node/.style={%
      node distance=0.375\gpgpuElemSep,
    },
    component/.style={%
      box,
      minimum size=0.42\gpgpuElemSize,
      inner sep=0pt,
    },
    alu/.style={%
      component,
      fill=shade1,
    },
    controlcache/.style={%
      component,
      rectangle split,
      rectangle split parts=2,
      rectangle split part fill={shade2, shade3},
    },
    memory/.style={%
      box,
      fill=shade3,
      minimum height=0.5\gpgpuElemSize,
      inner sep=0pt,
    },
  ]
  % Rows of ALUs, control logics and caches
  \foreach \i in {1, ..., 7} {%
    \ifnum \i=1
      \node [controlcache] (cc\i) {};
    \else
      \pgfmathtruncatemacro\prevCC{\i-1}
      \node [controlcache, below=of cc\prevCC] (cc\i) {};
    \fi
    \foreach \j in {1, ..., 7} {%
      \ifnum \j=1
        \node [alu, right=of cc\i] (alu\j) {};
      \else
        \pgfmathtruncatemacro\prevAlu{\j-1}
        \node [alu, right=of alu\prevAlu] (alu\j) {};
      \fi

    }
  }

  % Memory
  \path let \p1 = (cc7.south west),
            \p2 = (alu7.north east)
         in
           node [%
             memory,
             minimum width=\x2-\x1-\pgflinewidth,
             below right,
           ] at ([%
             yshift={-2\gpgpuElemSep},
           ] cc7.south west) (memory) {Memory};
\end{tikzpicture}
\endgroup
\end{document}
share|improve this question
3  
May be the problem is related with this comment in pgfmanual (page 500): "When split vertically, the rectangle split will meet any minimum width requirements, but any minimum height will be ignored." –  Ignasi Sep 28 '11 at 7:51
add comment

3 Answers

up vote 10 down vote accepted

You can reset the minimum size options of the rectangle split parts as explained in How to change the height of just one nodepart in TikZ? using

rectangle split every empty part={}

and then, to get the parts to have the correct height, set

rectangle split empty part height=0.21\gpgpuElemSize-\pgflinewidth

(i.e. half the desired height, minus the thickness of the line, to account for the added size).

enter image description here

\documentclass[a4paper, 11pt]{article}

\usepackage[rgb,hyperref]{xcolor}
\usepackage{tikz}

% Define colors
\definecolor{shade1}{rgb}{0.9, 0.9, 0.9}
\definecolor{shade2}{rgb}{0.75, 0.75, 0.75}
\definecolor{shade3}{rgb}{0.5, 0.5, 0.5}
\definecolor{shade4}{rgb}{0.35, 0.35, 0.35}

% Load TikZ libraries
\usetikzlibrary{shapes,arrows}
\usetikzlibrary{fit}
\usetikzlibrary{backgrounds}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}

% Text settings
\newcommand{\figureTextSize}{\tiny}

% Figure element lengths
\newlength{\gpgpuElemSep}
\setlength{\gpgpuElemSep}{1mm}
\newlength{\gpgpuElemSize}
\setlength{\gpgpuElemSize}{8mm}

% TikZ styles
\newcommand{\arrowStyle}{stealth}
\newcommand{\bendAngle}{45}
\newcommand{\lineThickness}{semithick}
\tikzstyle{box} = [%
  draw,
  rectangle,
  \lineThickness,
]



\begin{document}
\begingroup
\figureTextSize
\begin{tikzpicture}[%
    every node/.style={%
      node distance=0.375\gpgpuElemSep,
    },
    component/.style={%
      box,
      minimum size=0.42\gpgpuElemSize,
      inner sep=0pt,
    },
    alu/.style={%
      component,
      fill=shade1,
    },
    controlcache/.style={%
      component,
      rectangle split,
      rectangle split parts=2,
      rectangle split part fill={shade2, shade3},
      rectangle split every empty part={},
      rectangle split empty part height=0.21\gpgpuElemSize-\pgflinewidth,
    },
    memory/.style={%
      box,
      fill=shade3,
      minimum height=0.5\gpgpuElemSize,
      inner sep=0pt,
    },
  ]
  % Rows of ALUs, control logics and caches
  \foreach \i in {1, ..., 7} {%
    \ifnum \i=1
      \node [controlcache] (cc\i) {};
    \else
      \pgfmathtruncatemacro\prevCC{\i-1}
      \node [controlcache, below=of cc\prevCC] (cc\i) {};
    \fi
    \foreach \j in {1, ..., 7} {%
      \ifnum \j=1
        \node [alu, right=of cc\i] (alu\j) {};
      \else
        \pgfmathtruncatemacro\prevAlu{\j-1}
        \node [alu, right=of alu\prevAlu] (alu\j) {};
      \fi

    }
  }

  % Memory
  \path let \p1 = (cc7.south west),
            \p2 = (alu7.north east)
         in
           node [%
             memory,
             minimum width=\x2-\x1-\pgflinewidth,
             below right,
           ] at ([%
             yshift={-2\gpgpuElemSep},
           ] cc7.south west) (memory) {Memory};
\end{tikzpicture}
\endgroup
\end{document}

Addendum (by Andrew Stacey): The fact that the line width correct is \pgflinewidth surprised me; I expected it to be either .5*\pgflinewidth or not needed at all. So I did a little investigation and discovered a crucial difference between the rectangle split empty part height and the minimum height keys. The minimum height key, when given to a rectangular node and assuming that there's no funny business with the inner sep, is the distance between the top and bottom lines of the rectangle. This is independent of the line thickness. The rectangle split empty part height is the height of the internal box which takes into account the line width. So if we set each to be 1cm, then for a rectangular node, PGF will draw a rectangle with height 1cm, then it will look at the options as to whether to draw it or fill it, and (in particular) what line width to use. For a rectangle split, on the other hand, PGF will draw a rectangle such that when it is drawn, the inside of the drawn rectangle has height 1cm.

Here's a picture to show that. The background lines are 1cm apart, the red and cyan lines are guide lines. The first two yellow boxes are drawn using the rectangle split shape (the second only has one part). The second two are drawn as rectangular nodes. In each case, the corresponding key has been set to either 1cm or 2cm as appropriate. The second and third boxes are placed so that their south anchor is at the relevant coordinate, which has been pushed down by half the line width. All of the arrows are 1cm in length.

rectangular nodes

Here's the code (not particularly elegant!):

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{shapes}

\begin{document}
\begin{tikzpicture}[line width=2mm]
\begin{scope}[every path/.style={double=orange,line width=.9mm,double distance=.2mm}]
\draw (-.5,0) -- ++(4,0);
\draw (-.5,-1) -- ++(4,0);
\draw (-.5,1) -- ++(4,0);
\end{scope}
\draw[cyan] (0,0) -- +(0,-1);
\draw[red] (0,0) -- +(0,1);
\node[
  draw=yellow,
  inner sep=0pt,
  minimum width=4mm,
  rectangle split,
  rectangle split parts=2,
  rectangle split part fill={green,green},
  rectangle split every empty part={},
  rectangle split empty part height={1cm},
] at (.75,0) {};
\node[
  draw=yellow,
  inner sep=0pt,
  minimum width=4mm,
  rectangle split,
  rectangle split parts=1,
  rectangle split part fill={green},
  rectangle split every empty part={},
  rectangle split empty part height={1cm},
  anchor=south,
]  at (1.5,-1mm) {};
\node[
  rectangle,
  draw=yellow,
  inner sep=0pt,
  minimum width=4mm,
  minimum height=2cm,
  fill=green,
] at (2.25,0) {};
\node[
  draw=yellow,
  inner sep=0pt,
  minimum width=4mm,
  rectangle,
  minimum height=1cm,
  fill=green,
  anchor=south,
] at (3,-1mm) {};
\draw[thick,<->] (0,0) -- ++(0,1);
\draw[thick,<->] (0,0) -- ++(0,-1);
\draw[thick,<->] (.75,0) ++(0,1mm) -- ++(0,1);
\draw[thick,<->] (.75,0) ++(0,-1mm) -- ++(0,-1);
\draw[thick,<->] (1.5,0) ++(0,1mm) -- ++(0,1);
\draw[thick,<->] (2.25,0) -- ++(0,1);
\draw[thick,<->] (2.25,0) -- ++(0,-1);
\draw[thick,<->] (3,0) -- ++(0,1);
\end{tikzpicture}
\end{document}
share|improve this answer
    
Ah! I had tried using rectangle split empty part height, but apparently it doesn't work unless you also specify rectangle split every empty part={}! Thank you very much! –  gablin Sep 28 '11 at 8:34
    
Jake, I'd like to add something to your answer. The fact that you have to use \pgflinewidth surprised me (I would have expected .5*\pgflinewidth) so I did some investigating and found that you are completely right. I'd like to add the picture that I produced to your answer so that anyone else who thinks the same can see what is going on. Would that be okay? –  Andrew Stacey Sep 28 '11 at 8:47
    
@AndrewStacey: I had to try both variants as well. By all means, go ahead! –  Jake Sep 28 '11 at 8:48
    
Done. Hope that's okay. –  Andrew Stacey Sep 28 '11 at 9:10
add comment

PGF/TikZ seem to ignore the minimum height for split rectangle nodes. IMHO you should simply avoid (mis-)using this kind of nodes just to get that effect. Just draw two separate normal rectangle nodes.

Anyway, the issue here seems to be cause because the split nodes are empty. The manual states the following two settings to select the sizes for this case but they seem to have no effect when set to zero:

rectangle split empty part height=0ex,
rectangle split empty part depth=0ex,

Setting them higher however increases the (total) height. There seems to still be something which causes some height. Neither setting minimum height nor inner sep helps here.

So my solution is to insert some content with the correct height:

\documentclass[a4paper, 11pt]{article}

\usepackage[rgb,hyperref]{xcolor}
\usepackage{tikz}

% Define colors
\definecolor{shade1}{rgb}{0.9, 0.9, 0.9}
\definecolor{shade2}{rgb}{0.75, 0.75, 0.75}
\definecolor{shade3}{rgb}{0.5, 0.5, 0.5}
\definecolor{shade4}{rgb}{0.35, 0.35, 0.35}

% Load TikZ libraries
\usetikzlibrary{shapes,arrows}
\usetikzlibrary{fit}
\usetikzlibrary{backgrounds}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}

% Text settings
\newcommand{\figureTextSize}{\tiny}

% Figure element lengths
\newlength{\gpgpuElemSep}
\setlength{\gpgpuElemSep}{1mm}
\newlength{\gpgpuElemSize}
\setlength{\gpgpuElemSize}{8mm}

% TikZ styles
\newcommand{\arrowStyle}{stealth}
\newcommand{\bendAngle}{45}
\newcommand{\lineThickness}{semithick}
\tikzstyle{box} = [%
  draw,
  rectangle,
  \lineThickness,
]

\newcommand{\controlcachecontent}{%
    \pgfmathparse{0.21\gpgpuElemSize-\pgflinewidth}%
    \rule{0pt}{\pgfmathresult pt}%
    \nodepart{two}%
    \pgfmathparse{0.21\gpgpuElemSize-\pgflinewidth}% needs to be done twice because of grouping
    \rule{0pt}{\pgfmathresult pt}%
}

\begin{document}
\begingroup
\figureTextSize
\begin{tikzpicture}[%
    every node/.style={%
      node distance=0.375\gpgpuElemSep,
    },
    component/.style={%
      box,
      minimum size=0.42\gpgpuElemSize,
      inner sep=0pt,
    },
    alu/.style={%
      component,
      fill=shade1,
    },
    controlcache/.style={%
      component,
      rectangle split,
      rectangle split parts=2,
      rectangle split part fill={shade2, shade3},
    },
    memory/.style={%
      box,
      fill=shade3,
      minimum height=0.5\gpgpuElemSize,
      inner sep=0pt,
    },
  ]
  % Rows of ALUs, control logics and caches
  \foreach \i in {1, ..., 7} {%
    \ifnum \i=1
    \node [controlcache] (cc\i) {\controlcachecontent};
    \else
      \pgfmathtruncatemacro\prevCC{\i-1}
      \node [controlcache, below=of cc\prevCC] (cc\i) {\controlcachecontent};
    \fi
    \foreach \j in {1, ..., 7} {%
      \ifnum \j=1
        \node [alu, right=of cc\i] (alu\j) {};
      \else
        \pgfmathtruncatemacro\prevAlu{\j-1}
        \node [alu, right=of alu\prevAlu] (alu\j) {};
      \fi

    }
  }

  % Memory
  \path let \p1 = (cc7.south west),
            \p2 = (alu7.north east)
         in
           node [%
             memory,
             minimum width=\x2-\x1-\pgflinewidth,
             below right,
           ] at ([%
             yshift={-2\gpgpuElemSep},
           ] cc7.south west) (memory) {Memory};
\end{tikzpicture}
\endgroup
\end{document}

Result

share|improve this answer
add comment

This is not an answer to this question but another way of drawing it. I thought that a matrix of nodes with nodes in empty cells option was an easier way of constructing such a regular picture because I could avoid \foreach loops. My initial idea had some problems solved with Andrew Stacey's help and here you have the result.

\documentclass[border=3mm]{standalone}

\usepackage[rgb,hyperref]{xcolor}
\usepackage{tikz}

% Define colors
\definecolor{shade1}{rgb}{0.9, 0.9, 0.9}
\definecolor{shade2}{rgb}{0.75, 0.75, 0.75}
\definecolor{shade3}{rgb}{0.5, 0.5, 0.5}
\definecolor{shade4}{rgb}{0.35, 0.35, 0.35}

% Load TikZ libraries
\usetikzlibrary{shapes,matrix}
\usetikzlibrary{positioning}

% Text settings
\newcommand{\figureTextSize}{\tiny}

% Figure element lengths
\newlength{\gpgpuElemSep}
\setlength{\gpgpuElemSep}{1mm}
\newlength{\gpgpuElemSize}
\setlength{\gpgpuElemSize}{8mm}

% TikZ styles
\newcommand{\arrowStyle}{stealth}
\newcommand{\bendAngle}{45}
\newcommand{\lineThickness}{semithick}
\tikzstyle{box} = [%
  draw,
  rectangle,
  \lineThickness,
]

\begin{document}
\begingroup
\figureTextSize
\begin{tikzpicture}[%
    every node/.style={%
      node distance=0.375\gpgpuElemSep,
    },
    component/.style={%
      box,
      minimum size=0.42\gpgpuElemSize,
      inner sep=0pt,
    },
    alu/.style={%
      component,
      fill=shade1,
        outer sep=0pt
    },
    controlcache/.style={%
      component,
      rectangle split,
      rectangle split parts=2,
      rectangle split part fill={shade2, shade3},
      rectangle split every empty part={},
      rectangle split empty part height=0.21\gpgpuElemSize-\pgflinewidth,
    },
     layoutalu/.style={%
        matrix of nodes,
        nodes in empty cells,
        nodes=alu,
        column sep=\gpgpuElemSep,
        row sep=\gpgpuElemSep
    },
     layoutcc/.style={%
        matrix of nodes,
        nodes in empty cells,
        nodes=controlcache,
        column sep=\gpgpuElemSep,
        row sep=\gpgpuElemSep
    }
  ]

    \matrix (alu) [layoutcc, 
        column 3/.style={nodes={alu,yshift=-.5\pgflinewidth}},
        row 2 column 5/.style={nodes={alu,fill=blue!15}}]
    { & & & & & & & \\ 
      & & & & & & & \\
      & & & & & & & \\
      & & & & & & & \\
      & & & & &|[alu,fill=blue!15]| & & \\
      & & & & & & & \\
      & & & & & & & \\
};

    \matrix[right = 1cm of alu.east] (alu2) 
        [layoutalu, 
        column 3/.style={nodes={controlcache,fill=red!30,yshift=.5\pgflinewidth}},
column 5/.style={nodes={rectangle split part fill={red,blue},controlcache}}]
    { & & & & & & & \\ 
      & & & & & & & \\
      & & & & & & & \\
      & & & & & & & \\
      & & & & & & & \\
      & & & & & & & \\
      & & & & & & & \\
};
\end{tikzpicture}
\endgroup
\end{document}

enter image description here

I hope it's not wrong to post it.

share|improve this answer
    
Absolutely right to post it. Alternative solutions are always a good way to find out more. –  Andrew Stacey Oct 4 '11 at 9:05
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.