7

How can you make the matrix cell contents aligned to the top? I am using plain format with XeTeX.

\input tikz
\usetikzlibrary{matrix}
$$\hbox{I'd like for the cells to be top-aligned}\cases{
\tikzpicture[
  a/.style={draw=green!50!black,text width=3.5cm,
    text height=1.5cm,text depth=1.5cm,minimum size=3.5cm,
    anchor=base,
    inner sep=0pt,outer sep=0pt},
  m/.style={matrix of nodes,inner sep=2pt,outer sep=0pt,nodes=a,
    ampersand replacement=\&,row sep=0pt,column sep=0pt,draw=black!50}
  ]
  \parindent0pt
  \matrix[m] (mx) {
    Hey, this is a node with a break\break and stuff\&
    And another one with it. Milkshakes are yummy when the sun is shining\\
    Let's see what happens; I'm trying to find the logic\&
    Does it break when all these cells have different amount of text?\\
  };
  \draw[very thick,red!50] (mx.north)--(mx.south) (mx.west)--(mx.east);
\endtikzpicture
} \hbox{Yes it does}
$$
\bye

enter image description here

After @Gonzalo's comment to change text height/depth:

\input tikz
\usetikzlibrary{matrix}
\tikzpicture[
  a/.style={draw=green!50!black,text width=3.5cm,
    text height=0pt,text depth=2.5cm,minimum size=3.5cm,
    anchor=base,
    inner sep=0pt,outer sep=0pt},
  m/.style={matrix of nodes,inner sep=2pt,outer sep=0pt,nodes=a,
    ampersand replacement=\&,row sep=0pt,column sep=0pt,draw=black!50}
  ]
  \parindent0pt
  \matrix[m] (mx) {
    Hey, this is a node with a break\break and stuff\&
    And another one with it. Milkshakes are yummy when the sun is shining\\
    Let's see what happens; I'm trying to find the logic\&
    Does it break when all these cells have different amount of text?\\
  };
  \draw[very thick,red!50] (mx.north)--(mx.south) (mx.west)--(mx.east);
\endtikzpicture
\bye

enter image description here

Moriambar
  • 11,466
morbusg
  • 25,490
  • 4
  • 81
  • 162

3 Answers3

3

A solution with matrix (version 2)

\input tikz
\usetikzlibrary{arrows,calc,matrix,decorations.pathreplacing} 
\parindent=0pt
\tikzpicture[
  b/.style={
      text width=3.2cm,,minimum height=0pt,,minimum width=0pt
      inner sep =.2cm,anchor=north west,
      align=left},
  m/.style={matrix of nodes,
            inner sep=2pt,
            outer sep=0pt,
            column sep=0pt,
            draw=black!50},
            nodes={minimum height=2cm,
                   minimum width=3.6cm}]
  \matrix[m] (M) {%
  {} & {} \\
   {}&  {}\\
  }; 

\node[b] at (M-1-1.north west){%
   Hey, this is a node with a break\break and stuff };
\node[b] at (M-1-2.north west){%
   And another one with it. Milkshakes are yummy when the sun is shining};
\node[b] at (M-2-1.north west){%
   Let's see what happens; I'm trying to find the logic };
\node[b] at (M-2-2.north west){%
   Does it break when all these cells have different amount of text?};      

\draw[very thick,red!50] (M-1-1.north east)--(M-2-1.south east)
                         (M-1-1.south west)--(M-2-2.north east);
\draw[double,green!50!black] (M-1-1.north west) rectangle (M-2-2.south east);
\draw[decorate,decoration={brace,mirror,raise=6pt}]%
     (M-1-1.north west)--(M-2-1.south west);
\node[anchor=east,left=1em] at (M-1-1.south west){%
      I'd like for the cells to be top-aligned};
\node[anchor=west] at (M-1-2.south east) {Yes it does}; 
\endtikzpicture    
\bye

enter image description here

Moriambar
  • 11,466
Alain Matthes
  • 95,075
2

You need to make a couple of changes to the above. There is probably more than one way to do this, but the following gives me a reasonable picture. Whether or not it is the best solution for you depends on what else you are trying to do here. To understand it, you need to realise that there are several layers involved. There's the placement of the text in the node box, the placement of the node in its matrix cell, and the alignment of the matrix cells. Your styles are trying to act on all of these and causing conflicts. What I've done in the following is to simplify this by taking the size stuff out of the nodes and put it in to the matrix.

The basic problem is that you can't have full control over how text is positioned within a node. The node is meant to be just big enough to contain the text and to grow accordingly. You can override its automatic size calculations, but only by specifying absolutes. The text is always placed at the centre of the node. The only way to override that is to tell TikZ/TeX that the text is not quite what it thinks it is - this is what the text height and text depth keys are for. But if you want to tell TikZ the exact height and depth (as you don't in this example since it changes for each node), then when you specify the minimum size it grows the node in all directions so as to keep the text at the centre.

So when doing complicated positioning like this, it is best to not mess with the nodes too much and let the matrix do the alignment. Thus anchor=north puts each node's anchor at the alignment point, but that only works if the text is flushed to the top of the node, and that only works if the node is the right size for its text. Hence my suggestion (in the comments) of anchor=north didn't work because you were trying to be too clever with the node dimensions.

So we let the nodes be their natural size and pass control of the cell size to the matrix. We do this by using the row sep key, with the between origins to make it look as if each cell was the same height.

This does mess up the sizes of the nodes, but to fix that you could use my matrixcells package (available from the TeX-SX package, see the "From Answers to Packages" for more details). Disclaimer: I've no idea if it works with plain TeX. If you know the exact sizes the nodes should be then you don't need to use that package (it would be overkill). What you need to do in that case is to ensure that TikZ/TeX sees the text as a box of the right dimensions (in this case 3.5cm square) and position the text within that box how you want. In LaTeX I'd use a minipage or parbox for this, I don't know how to do it in plain TeX.

\input tikz
\usetikzlibrary{matrix}
$$\hbox{I'd like for the cells to be top-aligned}\cases{
\tikzpicture[
  a/.style={draw=green!50!black,text width=3.5cm,
    anchor=north,
    inner sep=0pt,outer sep=0pt},
  m/.style={matrix of nodes,inner sep=2pt,outer sep=0pt,nodes=a,
    ampersand replacement=\&,row sep={3.5cm,between origins},column sep=0pt,draw=black!50}
  ]
  \parindent0pt
  \matrix[m] (mx) {
    Hey, this is a node with a break\break and stuff\&
    And another one with it. Milkshakes are yummy when the sun is shining\\
    Let's see what happens; I'm trying to find the logic\&
    Does it break when all these cells have different amount of text?\\
  };
  \draw[very thick,red!50] (mx.north)--(mx.south) (mx.west)--(mx.east);
\endtikzpicture
} \hbox{Yes it does}
$$
\bye

Result:

nodes with vertical alignment

Moriambar
  • 11,466
Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
  • Thanks for the answer. Although, I need to have each node with the same height (because they will be getting a background-color, and look funky if they have different height---that's why I included the border color here). – morbusg Jun 12 '11 at 16:00
  • @morbusg: I suspected that might be the case (though it might have been that they were in to highlight the problem ...). That's why I suggested my matrixcells package. That draws a new node which is the size of the matrix cell as seen from the outside, so it can be filled or styled accordingly without needing this. However, if you know in advance that everything will be the same height you don't need to use that package ... wait a bit and I'll modify my answer. – Andrew Stacey Jun 12 '11 at 16:06
  • @morbusg: Actually, I don't think that I can modify my answer to fix this problem, but maybe I can modify it so that you can. I know how I would fix it in LaTeX but don't know anything about plain TeX. – Andrew Stacey Jun 12 '11 at 16:10
  • @morbusg: edited. I hope that's enough clues! – Andrew Stacey Jun 12 '11 at 16:16
  • "The text is always placed at the centre of the node." This was the vital piece of information I was missing. +1 Thanks! It's a weird restriction, IMO, since I'm basically asking for a \vtop to 3.5cm. – morbusg Jun 12 '11 at 16:27
  • @morbusg: It's not that weird when you think that originally nodes were meant to be "box containing text" and that a rectangle is one of the simplest nodes out there. It may be only later that idiots came along and said, "Hey, these nodes are great shapes. We could use them to draw, say, TQFT diagrams!" Anyway, it wouldn't be hard to design a rectangle shape in which you could anchor the text pretty much anywhere within the node, but it would be more complicated than the current rectangle node. – Andrew Stacey Jun 12 '11 at 16:32
2

Oh gosh, I even said it out loud myself in a comment, without even realizing it could indeed be used inside a node:

\input tikz
\usetikzlibrary{matrix}
\tikzpicture
  \parindent0pt
  \matrix[matrix of nodes, inner sep=.5cm, nodes={text width=3cm}] (mx) {
    |[fill=green!10]|\vtop to 3cm{
      Hey, this is a node with a break\hfil\break and stuff\vfil}&
    |[fill=red!10]|\vtop to 3cm{
      And another one with it. Milkshakes are yummy when the sun is shining\vfil}\\
    |[fill=blue!10]|\vtop to 3cm{
      Let's see what happens; I'm trying to find the logic\vfil}&
    |[fill=yellow!10]|\vtop to 3cm{
      Does it break when all these cells have different amount of text?\vfil}\\
  };
  \draw[very thick,red!50] (mx.north)--(mx.south) (mx.west)--(mx.east);
\endtikzpicture
\bye
Moriambar
  • 11,466
morbusg
  • 25,490
  • 4
  • 81
  • 162