tikz: position label halfway along arrow shaft

The following code draws an arrow from a to b with a label g. The label looks like it is too far to the right, and not centered.

$\begin{tikzpicture} \node (a) at (0,0) {a}; \node (b) at (1.2,0) {b}; \draw[-open triangle 90] (a) to node {g} (b); \end{tikzpicture}$

The way to correct this in xymatrix is to add a dash before the label:

$\xymatrix{a \ar[r]^-g & b}$

Is there a similar fix in tikz, or what is the best way to accomplish this?

• Did you try tikz-cd? – egreg Dec 30 '12 at 0:43

Notes:

• The nodes in TikZ have a bigger inner seperator so that the arrow is slightly shorter than in the xymatrix.
• The g in the xymatrix is set in \scriptstyle. This does not apply automatically in TikZ, but can be achieved by settings the node’s content to $g$.
• The difference between the g and the -g version in your xymatrix example is quite small:  For the placement of the node, there are many keys that help, mostly:

• above places the nodes content above the line-
• pos takes a value between 0.0 and 1.0 and means the relatively position between the start and the target.
• auto places the node automatically on one side and in the middle.

The automatically assigned midway (= pos=.5) is calculated for the whole arrow, not only the part that is not the arrow head. This is the reason it looks okay in xymatrix (the arrow head is quite small), but not so good if you use a big arrow like open triangle 90 on such a short line.

Solution for straight lines (--/line to) and fixed arrow

From the code for the open triange 90 arrow one can see that its length is 6 (.5pt + .25\pgflinewidth). This length is subtracted from the placement of the node.

The trickery with the name path keys was necessary because ($(\tikztotarget)!6*(.5pt+.25\pgflinewidth)!(\tikztostart)$) would have calculated from the centers not from the node’s border.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{
arrows,
calc,
positioning,
intersections,
}
\newcount\qrrArrowLineCounter
\newdimen\qrrArrowLength
\tikzset{
name/.append style={
/tikz/name path=qrr-node-#1
},
arrow length/.code={
\pgfmathsetlength\qrrArrowLength{#1}
},
m/.style={
arrow length=6*(.5pt+.25\pgflinewidth),
to path={
\pgfextra{
\path[name path=qrr-\the\qrrArrowLineCounter-path] (\tikztostart) -- (\tikztotarget);
\path[name intersections={of=qrr-\the\qrrArrowLineCounter-path and qrr-node-\tikztostart}] (intersection-1) coordinate (qrr-\the\qrrArrowLineCounter-start);
\path[name intersections={of=qrr-\the\qrrArrowLineCounter-path and qrr-node-\tikztotarget}] (intersection-1) coordinate (qrr-\the\qrrArrowLineCounter-target);
\path (\tikztostart) -- ($(qrr-\the\qrrArrowLineCounter-target)!\the\qrrArrowLength!(qrr-\the\qrrArrowLineCounter-start)$) \tikztonodes;
}
(\tikztostart) -- (\tikztotarget)
}
},
}
\begin{document}
\begin{tikzpicture}
\node (a) at (0,0) {$a$}; \node (b) at (1.2,0) {$b$};
\draw[-open triangle 90] (a) -- node[above] {$g$} (b);
\end{tikzpicture}

\begin{tikzpicture}
\node (a) at (0,0) {$a$}; \node (b) at (1.2,0) {$b$};
\draw[-open triangle 90] (a) -- node[above left=0cm and 1.2pt,anchor=south] {$g$} (b);
\end{tikzpicture}

\begin{tikzpicture}
\node[name=a] at (0,0) {$a$}; \node (b) at (1.2,0) {$b$};
\draw[-open triangle 90] (a) to[m] node[above] {$g$} (b);
\end{tikzpicture}
\end{document}

Output

Order:

• without any placement correction
• manual placement to the left (works only for horizontal left-to-right lines)
• automatically placement for nodes on straight lines Maybe tikz-cd

Although it does not solve the actual problem on hand, the package tikz-cd works similar to xymatrix but uses TikZ.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows,calc}
\usepackage{xypic}
\usepackage{tikz-cd}
\begin{document}
\begin{center}
\begin{tikzpicture}
\node (a) at (0,0) {$a$};
\node (b) at (1.2,0) {$b$};
\draw[-open triangle 90] (a) -- node[auto] {$g$} (b);
\end{tikzpicture}
\end{center}

\begin{center}
\begin{tikzcd}
a \arrow{r}{g} & b \\
\end{tikzcd}
\end{center}

\end{document}

Output • IMHO xymatrix is fancier. See the font size. – Sigur Dec 30 '12 at 0:15
• $g$ – egreg Dec 30 '12 at 0:21
• @Sigur Although that was not the question, egreg pointed out how to achieve the same output as in xymatrix. – Qrrbrbirlbel Dec 30 '12 at 0:24
• Thanks for your suggestion. I actually tried this, but it looked the same afterwards. I admit my toy example isn't very good; my real problem is a little more complicated. I don't really understand what's going on, but in xymatrix this kind of problem is very easy to resolve! I think it has something to do with the fact that the label is placed half way between the nodes, whereas the eye expects to see it half way along the shaft. – Alex Dec 30 '12 at 0:26
• @Alex I have updated my answer with a solution for straight lines and this specific arrow. For bent lines I can’t offer any placement corrections (tried similar things with the markings library). – Qrrbrbirlbel Dec 30 '12 at 6:43

maybe is this what you looking for:

\begin{tikzpicture}
\node (a) at (0,0) {$a$};
\node (b) at (1.2,0) {$b$};
\draw[-open triangle 90] (a) to node[pos=0.45] {$g$} (b);
\end{tikzpicture}