8

Possible Duplicate:
A line of length \textwidth in TikZ

I'm trying to learn tikz. In this MWE all I'm trying to do it to draw a line the width of \linewidth. I'm able to do this with a rule; I'm able to do this in pstricks. But when I try this with tikz the line comes out too short; moreover, it seems to depend on what's happening in my paragraph in a way I'm not expecting (particularly considering where I'm defining my nodes in both cases).

\documentclass{article}
\usepackage{tikz}
\usepackage{pst-node}
\pagestyle{empty}
\begin{document}

\noindent%
\raisebox{0ex}[0pt][0pt]{\makebox[0pt][r]{\color{red}\rule[-4in]{0.4pt}{4.5in}}}%
\hspace*{\fill}{\color{red}\Huge $\leftarrow$ Struts to show the end line $\rightarrow$}\hspace*{\fill}%
\raisebox{0ex}[0pt][0pt]{\makebox[0pt][l]{\color{red}\rule[-4in]{0.4pt}{4.5in}}}%
\vspace{1cm}

Creating a rule:\newline
\noindent\rule{\linewidth}{0.4pt}%
\vspace{1cm}

Using \texttt{pstricks}:\newline
\noindent\rput(0,0){\rnode{ps:left}{}}\hspace*{\fill}\rput(0,0){\rnode{ps:right}{}}%

\psline(ps:left)(ps:right)
\vspace{1cm}

Using \texttt{tikz} \textbf{(round I)}:\newline
\tikz \node (tkzlefta) at (0,0) {};
\tikz \node (tkzrighta) at (\linewidth,0) {};%
\noindent\tikz \draw (tkzlefta) -- (tkzrighta);

Using \texttt{tikz} \textbf{(round II)}:\newline
\tikz \node (tkzleftb) at (0,0) {};%
\tikz \node (tkzrightb) at (\linewidth,0) {};%

\noindent\tikz \draw (tkzleftb) -- (tkzrightb);

Using \texttt{tikz} \textbf{(round III)}:\newline
\tikz \coordinate (tkzleftc) at (0,0);%
\tikz \coordinate (tkzrightc) at (\linewidth,0);%

\noindent\tikz \draw (tkzleftc) -- (tkzrightc);


Using \texttt{tikz} \textbf{(round IV)}:\newline
\tikz \node[inner sep=0pt] (tkzleftd) at (0,0) {};%
\tikz \node[inner sep=0pt] (tkzrightd) at (\linewidth,0) {};%

\noindent\tikz \draw (tkzleftd) -- (tkzrightd);

\end{document}

enter image description here

I've incorporated HarishKumar's suggestion. Seems to work when I use coordinate (round III). But not working with inner sep=0pt applied to the nodes (round IV). Also, what's going on with the indentation in round I that's not occurring in round II? I would assume that the paragraph break should not be changing the placement of the nodes; but that's exactly what seems to be happening.

10
  • @HarishKumar, I've followed your advice. It works with coordinates but now I'd like to know what happening in the other places where things are still not as I would like. What's making the difference between round I and round II? Why is round IV still not quite right?
    – A.Ellett
    Commented Dec 27, 2012 at 23:13
  • I suggest that each line should be one 'tikzpicture', by putting the two nodes/coordinates and the \draw command into a \begin{tikzpicture}...\end{tikzpicture} environment, or using the \tikz{...} form (with braces) containing all three directives. Perhaps consult the manual to see how to do this. Commented Dec 27, 2012 at 23:22
  • @Qrrbrbirlbel. Tried that. I see nodes now, but don't know how that helps me (other than it shows nodes that seem to have no connection to the end points of the line); they're not even draw close to the position I would expect to find them.
    – A.Ellett
    Commented Dec 27, 2012 at 23:25
  • @HarishKumar, the end of line character only partially explains what's happening in round 1, but I don't see where there's an end of line error in round IV.
    – A.Ellett
    Commented Dec 27, 2012 at 23:25
  • 1
    @A.Ellett Maybe you should add what your final goal is? Simply a horizontal rule? \noindent\tikz\draw (0,0) -- (\linewidth-\pgflinewidth,0); Commented Dec 27, 2012 at 23:31

2 Answers 2

13

Node or coordinate does not matter at the point when you use three \tikz macros.

NB: If I say “TikZ picture” I mean either a solely \tikz macro or the tikzpicture environment.

Further reference on remember picture and overlay can be found in the PGF manual in section 16.13 “Referencing Nodes Outside the Current Pictures”, pp. 199f.)


As I already suggested in the comments, draw the nodes and you will find that those at (0,0) and at (\linewidth,0) are just sitting together. (Depending on the line-ending %s with a little space between them.)

Take a look at the following example:

Code I

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\tikzset{every node/.style={
    draw,
%   inner sep=0pt,
    }
}
\begin{document}
\noindent
\tikz \node (tkzlefta) at (0,0) {};% where am I?
\tikz \node (tkzrighta) at (\linewidth,0) {};% where am I?
\tikz \node[green] (bignumber) at (40cm,-1cm) {};% not on paper you say?

\noindent\tikz\draw (tkzlefta) -- (tkzrighta) -- (bignumber);
\end{document}

Output I

enter image description here

What happens here?

The whole TikZ picture will be cropped (“bounding box”) and put in one (TeX) box. The coordinates (x,y) are not related to the physical paper.

Also take a close look at the line end. The horizontal line and the line to bignumber are not connected, because the node is there.

If you add remember picture to the \tikz and without % at the end of line (to have at least a little space between those nodes).

Code II

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\tikzset{every node/.style={
    draw,
%   inner sep=0pt,
    }
}
\begin{document}
\noindent
\tikz[remember picture] \node (tkzlefta) at (0,0) {};
\tikz[remember picture] \node (tkzrighta) at (\linewidth,0) {};
\tikz[remember picture] \node[green] (bignumber) at (40cm,-1cm) {};

\noindent\tikz\draw[blue] (tkzlefta) -- (tkzrighta) -- (bignumber);%
\tikz[overlay, remember picture]\draw[green] (tkzlefta) -- (tkzrighta) -- (bignumber);
\end{document}

Output 2

enter image description here

This looks better as it uses the actual boxes (that TikZ remembers) to connect.

What have we learned?

  1. TikZ outputs boxes, nothing else. The actual placement is up to TeX. (There is a special node current page, though.)
  2. Without remember picture TikZ only remembers the coordinates but not the picture (picture is either \tikz or the tikzpicture environment).
  3. With remember picture TikZ remembers the actual (comparatively) placement on TeX paper but still, the box is just typeset by TeX.
  4. With remember picture and overlay TikZ finally connects the actual boxes!
  5. Do not use nodes.

But that is not what you are after anyway?

There are a few ways to get what you want.

The first solution uses only one TikZ picture. This is typeset by TeX.
So you will need an otherwise empty paragraph and \noindent.

Here you can see that TikZ’s way to set the correct bounding box is not optimal as it apparently pads the line additional by .5\pgflinewidth on both ends.

The yellow line solves this with \hspace trickery but as \pgflinewidth is only known inside a TikZ picture we need to use -.2pt manually. (The standard line width (thin) in TikZ is .4pt.)

The green line uses TikZ \clip path that is in fact a rectangular (the line has a width!).

The second solution actually places coordinates at the start and the end of the line (hfill); this is also known as (Google Search); see the third solution. These solutions need to be compiled at least twice!


The TikZmark macro I provide is a very rudimentary one. There is a TikZ library that can deal with marks on different page, provides an extra coordinate system for “remembered” coordinates and and and …

Solution 1 (one TikZ picture)

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\begin{document}

\noindent\hrulefill

\noindent\tikz\draw[red] (0,0) -- (\linewidth,0);% gives Overfull \hbox (0.4pt too wide)

\noindent\hspace{-.2pt}\tikz\draw[yellow] (0,0) -- (\linewidth-.5\pgflinewidth,0);%

\noindent\tikz{% do a line width change in the \tikz macro: \tikz[line width=1pt]
    \clip (0,-.5\pgflinewidth) rectangle ++(\linewidth,\pgflinewidth);
    \draw[green] (0,0) -- (\linewidth,0);
}
\end{document}

Output (solution 1)

enter image description here

Solution 2 (“TikZmark” but without the actual macro)

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\begin{document}

\noindent\hrulefill

\noindent\tikz[remember picture]\coordinate (tikzleft);%
\hfill%
\tikz[remember picture]\coordinate (tikzright);%
\tikz[remember picture, overlay]\draw (tikzleft)--(tikzright);

% The following is not pictured in the image below.
\noindent\tikz[remember picture]\coordinate (tikzleft2);%
\hfill%
\tikz[remember picture]{
    \coordinate (tikzright2);
    \draw[overlay] (tikzleft2) -- (tikzright2);
}%
\end{document}

Solution 3 (\tikzmark)

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\newcommand*{\tikzmark}[2][]{%
    \tikz[remember picture, #1]\coordinate (#2);%
}
\begin{document}

\noindent\hrulefill

\noindent\tikzmark{tikzleft}\hfill\tikzmark{tikzright}%
\tikz[remember picture, overlay]\draw (tikzleft)--(tikzright);
\end{document}

Output (solution 2 and 3)

enter image description here

2
  • So this is where some of my confusion is coming in. The line seems to be drawn (close to) correctly. But, the nodes are not shown in the positions at the end of the line. Why? How can the line be drawn as it is when the nodes are adjacent to each other?
    – A.Ellett
    Commented Dec 27, 2012 at 23:50
  • OMG, this is fantastic. You've given me a lot food for thought. I've got to play with this a bit to see what I understand. But thank you for the extensive explanation.
    – A.Ellett
    Commented Dec 28, 2012 at 0:38
9

A node will not produce a geometric point even if the text is empty and the inner sep is set to zero. To produce a point, one should use \coordinate. Also the end of line character should be taken care of by adding the % at the end. Also, it may be noted that you are defining a node here by means of horizontal dimensions, not vertical dimensions that are fixed with the page. Hence the node position will/can vary vertically.

\documentclass{article}
\usepackage{tikz}
\usepackage{pst-node}
\pagestyle{empty}
\tikzset{every node/.style=draw}
\begin{document}

\noindent%
\raisebox{0ex}[0pt][0pt]{\makebox[0pt][r]{\color{red}\rule[-5in]{0.4pt}{5.5in}}}%
\hspace*{\fill}{\color{red}\Huge $\leftarrow$ Struts to show the end line $\rightarrow$}\hspace*{\fill}%
\raisebox{0ex}[0pt][0pt]{\makebox[0pt][l]{\color{red}\rule[-5in]{0.4pt}{5.5in}}}%
\vspace{1cm}

Creating a rule:\newline
\noindent\rule{\linewidth}{0.4pt}%
\vspace{1cm}

Using \texttt{pstricks}:\newline
\noindent\rput(0,0){\rnode{ps:left}{}}\hspace*{\fill}\rput(0,0){\rnode{ps:right}{}}%

\psline(ps:left)(ps:right)
\vspace{1cm}

Using \texttt{tikz} \textbf{(round I)}:\newline
\tikz \node (tkzlefta) at (0,0) {};
\tikz \node (tkzrighta) at (\linewidth,0) {};%
\noindent\tikz \draw (tkzlefta) -- (tkzrighta);%

Using \texttt{tikz} \textbf{(round II)}:\newline
\tikz \node (tkzleftb) at (0,0) {};%
\tikz \node (tkzrightb) at (\linewidth,0) {};%
\noindent\tikz \draw (tkzleftb) -- (tkzrightb);%

Using \texttt{tikz} \textbf{(round III)}: Using coordinates and \% at the end\newline
\tikz \coordinate (tkzleftc) at (0,0);%
\tikz \coordinate (tkzrightc) at (\linewidth,0);% % < put % here
\noindent\tikz \draw (tkzleftc) -- (tkzrightc);


Using \texttt{tikz} \textbf{(round IV)}: \verb|inner sep = 0pt|\\%
\tikz \node[inner sep=0pt] (tkzleftd) at (0,0) {};%
\tikz \node[inner sep=0pt] (tkzrightd) at (\linewidth,0) {};%
\noindent\tikz \draw (tkzleftd.center) -- (tkzrightd.center);%

Using \texttt{tikz} \textbf{(round V)}: You can see the nodes drawn at left and right:\\%
{\tikz \node[inner sep=0pt] (tkzleftd) at (0,0) {};%
\hfill
\tikz \node[inner sep=0pt] (tkzrightd) at (\linewidth,0) {};%

\noindent\tikz \draw (tkzleftd) -- (tkzrightd);}%

Using \texttt{tikz} \textbf{(round VI)}: You should draw it from centers of nodes:\\%
{\tikz \node[inner sep=0pt] (tkzleftd) at (0,0) {};%
\hfill
\tikz \node[inner sep=0pt] (tkzrightd) at (\linewidth,0) {};%

\noindent\tikz \draw (tkzleftd.center) -- (tkzrightd.center);}%

Conclusion: Don't use nodes but coordinates. or

\noindent\tikz\draw (0,0) -- (\linewidth,0);

\end{document}

enter image description here

Conclusion:

DON'T use nodes when you want a point but coordinate.

Just to answer why the nodes are put together despite their defined position: When you use \tikz the picture is just treated like a text so no separate bounding box from tikz is provided unlike the tikzpicture environment Hence the two nodes are put in a way like two letters by tex.

Using Qrrbrbirlbel's code we just demonstrate this:

\documentclass{article}
\usepackage{tikz}
\pagestyle{empty}
\usepackage[pass,showframe]{geometry}
\tikzset{every node/.style={
    draw,
%   inner sep=0pt,
    }
}
\begin{document}

Using \verb|\tikz|:

\noindent
\tikz \node (tkzlefta) at (0,0) {};% where am I?
\tikz \node (tkzrighta) at (\linewidth,0) {};% where am I?
%\tikz \node[green] (bignumber) at (40cm,-1cm) {};% not on paper you say?
%
%\noindent\tikz\draw (tkzlefta) -- (tkzrighta) -- (bignumber);

Using \verb|tikzpicture| environment:

\noindent
\begin{tikzpicture}
 \node (tkzlefta) at (0,0) {};% where am I?
 \node (tkzrighta) at (\linewidth,0) {};% where am I?
% \node[green] (bignumber) at (40cm,-1cm) {};% not on paper you say?
%
%\draw (tkzlefta) -- (tkzrighta) -- (bignumber);
\end{tikzpicture}
\end{document}

enter image description here

1
  • This does solve the particular problem I asked. Unfortunately, I now have many more questions as I play around with this and get all sorts of effects I'm not expecting: for example, instead of using ".center" using ".east" or ".west" and getting things shifted around. Oh how I hate learning new things when you already have another approach you understand (pstricks). But I do want to learn tikz; so, I dive in. You answer is very helpful. I am sure I'll be back soon with more questions.
    – A.Ellett
    Commented Dec 28, 2012 at 0:30

Not the answer you're looking for? Browse other questions tagged .