31

I want to add a label to a node, but "inside" the node. Something like this:

desired output

The manual seems to indicate it might be possible, although no actual key is named.

The ... anchor point for the label node ... is determined in such a way that the label node will “face away” from the border of the main node. The anchor that is chosen depends on the position of the border point that is chosen and its position relative to the center of the main node and on whether the transform shape option is set. In general, the choice should be what you would expect, but you may have to set the anchor yourself in difficult situations. (emph. added)

But when I try an example like this:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\tikz \node [circle,draw,label={[red,anchor=north]above:X}] {my circle};
\end{document}

I don't get any change in the position of the label node. It's still "outside."

actual output

Any ideas?

2
  • See also tex.stackexchange.com/a/43946/86 Apr 4, 2013 at 14:48
  • @Andrew: Good link. My use cases don't involve rotated nodes so I think I'm in the clear. But it's good to keep in mind that labels and pins are designed to "snap to" certain places. Apr 4, 2013 at 15:20

3 Answers 3

29

The problem here is that TikZ applies some automatication (namely the \tikz@auto@anchor macro) that will overwrite your set anchor.

We can either hijack a .code key that is applied very last in the node that is used internally for the label (yes, even after our own settings red, anchor=north) and which calls \tikz@auto@anchor:

\tikzset{label anchor/.style={tikz@label@post/.append style={anchor=#1}}}

or we let the macro that does the calculations relax a little bit (no additional key needed):

\tikzset{anchor/.append code=\let\tikz@auto@anchor\relax}

If the new and improved anchor key is now used more globally (say \tikz[anchor=<dir>]) it will also affects the nodes (and there is currently now way to get it back).

I also provide a key inside (you can even use it twice to reverse the effect).

Code

\documentclass[tikz]{standalone}
\usepackage{etoolbox}
\makeatletter
\tikzset{anchor/.append code=\let\tikz@auto@anchor\relax}
\tikzset{inside/.code=\preto\tikz@auto@anchor{\pgf@x-\pgf@x\pgf@y-\pgf@y}}
\makeatother
\begin{document}
\tikz\node [anchor=west, circle,draw,label={[red, anchor=north]above:X}] {my circle};
\tikz\node [anchor=west, circle,draw,label={[red, inside]below:X}] {my circle};
\end{document}

Output

enter image description here

enter image description here

4
  • For having the same effect on labels of coordinates one must add \let\tikz@compute@direction\pgfutil@gobble to the (improved) anchor key. May 22, 2013 at 19:51
  • I put both tikzset commands from above into my preamble, but I still get : File ended while scanning use of \@argdef. :( Jul 8, 2013 at 19:18
  • 1
    @DaveBallakauser750378 Are you sure? Have you included the other three lines as well? The inside key uses etoolbox\preto and both use @ in macro names so @ needs to be a letter, thus the \makeatletter-\makeatother sequence. Jul 8, 2013 at 19:23
  • oh, ok. I'm using the version without inside and etoolbox now, and it works fine :) Thanks again. Jul 8, 2013 at 19:27
16

Here is another approach exploiting the append after command option. The point is that, by referring to the anchor \tikzlastnode.center one might add, relatively to that position, labels.

The new style able to accomplish this task is my label:

\tikzset{my label/.style args={#1:#2}{
  append after command={
    (\tikzlastnode.center) node [#1] {#2}
    }
  }
}

A mwe:

\documentclass[tikz,png,border=10pt]{standalone}
\usepackage{tikz}
\tikzset{my label/.style args={#1:#2}{
    append after command={
       (\tikzlastnode.center) node [#1] {#2}
    }
  }
}
\begin{document}
\tikz \node [circle,draw,my label={red,above=0.15cm:X}] {my circle};
\tikz \node [circle,draw,my label={red,below=0.15cm:X}] {my circle};
\end{document}

which gives as results:

enter image description here

enter image description here

The style accepts at first argument any TikZ option, so it is easy to customize colors and position: indeed, it is better to adjust a bit the offset to not overlap the text.

If, instead, one knows that the label always has to be placed below the "north border", well, the best thing to do is to change the my label style into:

\tikzset{my label/.style args={#1:#2}{
    append after command={
       (\tikzlastnode.north) node [#1] {#2}
    }
  }
}

In such a way, just setting:

\tikz\node [circle,draw,my label={red,below:X}] {my circle};

allows to achieve the target.

A mwe:

\documentclass[tikz,png,border=10pt]{standalone}
\usepackage{tikz}
\tikzset{my label/.style args={#1:#2}{
    append after command={
       (\tikzlastnode.north) node [#1] {#2}
    }
  }
}
\begin{document}
\begin{tikzpicture}
\node [circle,draw,my label={red,below:X}] {my circle};
\node [circle,draw,my label={red,below=0.15cm:X},xshift=2cm] {my circle};
\end{tikzpicture}
\end{document}

The result:

enter image description here

Revision

The previous method suffer, as said in the comments, if more than one label should be introduced. But this is perfectly doable if rather than introducing nodes, we introduce coordinates with labels.

The code:

\documentclass[tikz,png,border=10pt]{standalone}
\usepackage{tikz}
\tikzset{my label/.style args={[#1]#2:#3}{
    append after command={
       (\tikzlastnode.center) coordinate[label={[label distance=0.1cm,#1]#2:#3}]
    }
  },
}
\begin{document}
\begin{tikzpicture}
\node [circle,
  draw,
  my label={[red]above:X},
  my label={[green!70!blue]below:Y},
  my label={[blue,yshift=0.3cm]above:Z}] {my circle};
\node [circle,
  draw,
  my label={[blue,yshift=-0.15cm]below:X},
  my label={[green!70!blue]70:Z},
  my label={[orange!80!red]130:Y},
  xshift=2cm] {my circle};
\end{tikzpicture}
\end{document}

The result:

enter image description here

Notice: by using the label distance within the option definition, allows to not have the label text overlapped when one just says:

\tikz\node [circle,draw,my label={[red]below:X}] {my circle};
2
  • 1
    I've tried this method before, too. I found it did not work well with multiple labels. Because once you place the first label node, \tikzlastnode is that label node rather than the main node. Apr 4, 2013 at 15:16
  • Actually, you're right, but I think we can supply this problem by not introducing nodes. I'm going to edit my answer. Apr 4, 2013 at 17:58
12

You can also shift the label:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\tikz \node [circle,draw,label={[red,yshift=-0.5cm]above:X}] {my circle};

\tikz \node [circle,draw,label={[red,label distance=-0.5cm]above:X}] {my circle};
\end{document}
1
  • Funny, I tried a negative label distance before I posted the question and couldn't get it to work. Maybe I was doing it wrong. Apr 4, 2013 at 12:15

You must log in to answer this question.

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