22

This is perhaps a simple question, but after reading manual several times, I still don't have the answer.

My common situation is that I draw boxes and I want label above/below the box. If I use node[above] or node[anchor=south], the label is just above center of the box. Situation gets even more absurd if rectangle is slanted. Is there any simple way to achieve my goal?

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\draw (0,0) rectangle node[above] {$m$} +(2,1);
\draw (0,2) rectangle node[anchor=south] {$m$} +(2,1);

\begin{scope}[xshift=4cm,rotate=-30]
  \draw (0,0) rectangle node[above] {$m$} +(2,1);
  \draw (0,2) rectangle node[anchor=south] {$m$} +(2,1);
\end{scope}
\end{tikzpicture}

\end{document}
Troy
  • 13,741
Pygmalion
  • 6,387
  • 4
  • 34
  • 68

2 Answers2

26

I would suggest you use nodes to draw the rectangles, instead of just paths (which you get if you use \draw). With nodes, you have the ability to add labels, and they are in general more pleasant to work with: If you want to connect the upper left corners of two rectangles, for example, you can use the north east anchors provided by the nodes, and don't have to figure out the coordinates yourself.

labels are by default positioned above the node, but you can influence the placement using statements like node=left:<text>.

If you want the rectangles to be rotated, you will have to issue the rotate statement in the node definition itself, not in the scope, because by default nodes are not affected by rotation or scaling. This makes sure that text is always horizontal and line widths do not change. In the second example below, only the rectangle node is rotated, but the label remains horizontal.

You can make the nodes (and labels) scale and rotate according to the scope definition by adding the key transform shape to the node (and label).

Another option to get rotated labels is to use a scope with a transform canvas statement, which affects nodes as well as simple paths.

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\node [draw,rectangle,minimum width=2cm,minimum height=1cm,label=$m$] {};

\begin{scope}[xshift=3cm]
\node [rotate=-30,draw,rectangle,minimum width=2cm,minimum height=1cm,label=$m$] {};
\end{scope}

\begin{scope}[xshift=6cm,rotate=-30]
\node [transform shape,draw,rectangle,minimum width=2cm,minimum height=1cm,label={[transform shape]$m$}] {};
\end{scope}

\begin{scope}[xshift=1cm,yshift=-3cm,rotate=-30,scale=2]
\node [transform shape,draw,rectangle,minimum width=2cm,minimum height=1cm,label=$m$] {};
\end{scope}

\begin{scope}[transform canvas={xshift=6cm,yshift=-3cm,rotate=-30}]
\node [draw,rectangle,minimum width=2cm,minimum height=1cm,label=$m$] {};
\end{scope}

\end{tikzpicture}

\end{document}

rectangle nodes


Here's an example how this could be used:

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}[every node/.style={draw}]

\begin{scope}[rotate=-30]
\node at (3,0) [draw,name=A,rectangle, minimum width=2cm,minimum height=1cm,anchor=south,label=$m_1$,transform shape] {};
\node at (6,0) [name=B,rectangle, minimum width=1cm,minimum height=0.75cm,anchor=south,label=$m_2$,transform shape] {};
\node at (0,0) [name=C,circle,minimum size=.8cm,transform shape] {};

\draw (C.north) -- ($(A.south west)!(C.north)!(A.north west)$);
\draw ($(A.south east)!(C.north)!(A.north east)$) -- ($(B.south west)!(C.north)!(B.north west)$);
\draw(1,0) -- (8,0);
\end{scope}


\node at (-0.4,-5) [draw,name=D,rectangle, minimum width=1cm,minimum height=2cm,anchor=south,label=right:$m_3$] {};
\draw ($(D.north west)!(C.210)!(D.north east)$) -- (C.210)  arc [start angle=180,end angle=60,radius=0.4cm];
\end{tikzpicture}
\end{document}

blocks on a slope


Here's a suggestion for how to do the drawing you showed in your answer using nodes. The clear advantage of nodes here is that you can change dimensions, like the width and height of the big box, and everything else will be moved automatically without you having to do manual recalculations of coordinates:

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{calc,patterns}

\begin{document}

\begin{tikzpicture}[every node/.style={draw,outer sep=0pt,thick}]
\node (M3) [minimum width=3.5cm,minimum height=2.5cm] {$m_3$};
\node (M1) at (M3.north) [minimum width=1cm,minimum height=0.6cm,label=$m_2$,anchor=south] {};
\node (M2) at (M3.east) [minimum width=0.6cm,minimum height=1cm,label=right:$m_1$,anchor=west] {};
\node (C) at (M3.north east) [circle, minimum size=0.6cm] {};
\draw (M1.east) -- (C.north) (C.east) -- (M2.north);
\node (ground) at (M3.south) [fill,pattern=north east lines,minimum width=5cm,minimum height=.3cm,anchor=north,draw=none] {};
\draw (ground.north west) -- (ground.north east);
\end{tikzpicture}

\end{document}

third block picture

Jake
  • 232,450
  • 2
    @Jake I think that nodes should be used to place some texts. When using nodes for figures you get some problems. First now it's not possible to use \begin{tikzpicture}[scale=2] you have a problem with the last scope and generally the figures can be scaled. If you want a scale in the last rectangle : [transform canvas={xshift=6cm,rotate=-30,scale=2}] now it is incorrect for the label. And finally, It's not easy to place, for example, two rectangles with the same vertices. I think this method is only correct in some cases but not if you want drawing geometry pictures. – Alain Matthes Mar 14 '11 at 16:20
  • @Altermundus: Excellent point, it really depends on what you're trying to do. I've added the transform shape option to my answer, which takes care of the scaling and rotation defined in scopes. – Jake Mar 14 '11 at 16:42
  • @Jake I am really into geometry pictures. Like for example, a block on the slope and similar, connected to another block with a string... So is this node method appropriate? – Pygmalion Mar 14 '11 at 17:38
  • @Marko: I would say this method is appropriate, but it is probably also a question of personal preference. I like the "object oriented"-ness of the node approach provides, but there are probably many situations where going with a \draw approach might be a more straighforward solution. – Jake Mar 14 '11 at 18:19
  • @Altermundus: Maybe you could provide a solution to draw rotated, scalable rectangles with text labels that does not use nodes? – Jake Mar 14 '11 at 18:21
  • @Jake: I understand your approach and I admit that you examples are fine but my problem is to scale the picture. I need geometry pictures and I need to adapt the size and to rotate the pictures. Now I'm not sure that "sloped" label is a fine idea ( see some Tufte's documents). – Alain Matthes Mar 14 '11 at 22:29
  • @Altermundus What do you thing to be better and more conventional: that labels are sloped together with the object or remain horizontal? Is there any rule of thumb? – Pygmalion Mar 14 '11 at 22:41
  • I think sloped labels are bad. I used this possibility in some examples but now I think it's better to avoid the sloped labels. It's more easy for the users to read informations when the texts are horizontal. – Alain Matthes Mar 14 '11 at 22:48
  • @Altermundus I asked you that because your sample has sloped labels. I also avoided sloped labels in my document mentioned below. I guess you recommend not using nodes in any case? – Pygmalion Mar 14 '11 at 22:55
  • @Marko http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001V7 I don't how to put a link inside a comment. The document is about the problem How to place information in a picture. I like the approach of Till Tantau about graphics and information. – Alain Matthes Mar 14 '11 at 22:56
  • @Altermundus This Trufte stuff is amazing. I am here struggling for basic working conditions and acceptance of changes to improve teaching and learning, there you are already making science out of workbook design. We're light years behind. sigh – Pygmalion Mar 15 '11 at 06:41
11

Two solutions

\documentclass{article}
\usepackage{tikz}

\begin{document}

\tikzset{rect style/.style={rotate=#1,scale=2,every node/.style={rotate=#1}}}
\begin{tikzpicture}[rect style=-30]
\pgfmathsetmacro\x{2}     
\pgfmathsetmacro\y{1}
\draw (0,0) rectangle  +(\x,\y); 
\node[above] at (.5*\x,\y){$m$};
\end{tikzpicture}

\begin{tikzpicture}[rect style=30]
\pgfmathsetmacro\x{2}     
\pgfmathsetmacro\y{1} 
\draw (0,0) rectangle  +(\x,\y); 
\path (0,\y) --  (\x,\y) node[midway,above] {$m$};
\end{tikzpicture}  

\end{document}

enter image description here

Troy
  • 13,741
Alain Matthes
  • 95,075