# How to modify nodes in TikZ to automatically add a line on their top?

In TikZ there is the very flexible node system. As a beginner I am still stumbling over a few details. How can I modify a node or create my own nodes easily? As an example I need a node with a thick line on top. At the moment I solved this as follows:

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}

\node[bottom color=white,top color=black!20] (node) at (0,0) {node};

% line on top but not well aligned
\draw [very thick] (node.north west) -- (node.north east);

\end{tikzpicture}

\end{document}


Is it possible to define a new node that has the line automatically in it or is this not the right approach? Additionally the line seems a bit longer than the node itself but I do not know the cause (the black line is slightly wider than the box):

-
 have a look at zeroth's excellent answer to global-variables-for-all-tikz-drawings-in-a-document/ – cmhughes Oct 12 '12 at 16:40

This is a possible implementation:

\tikzset{mynode/.style={
bottom color=white,top color=black!20,
append after command={
[very thick,shorten >=0.2bp, shorten <=0.2bp]
(\tikzlastnode.north west)edge(\tikzlastnode.north east)
}
}
}


The complete example:

\documentclass{standalone}
\usepackage{tikz}

\tikzset{mynode/.style={
bottom color=white,top color=black!20,
append after command={
[very thick,shorten >=0.2bp, shorten <=0.2bp]
(\tikzlastnode.north west)edge(\tikzlastnode.north east)
}
}
}

\begin{document}
\begin{tikzpicture}
\node[mynode] at (0,0){texta};
\end{tikzpicture}

\end{document}


The result:

Some explanation

Inside a tikzset you can define the style of your node, thus you can select the colors bottom color=white,top color=black!20,. It is also possible to automatically draw the thick line on the upper border just appending the path when the node has been drawn: that's the purpose of:

append after command={
[very thick,shorten >=0.2bp, shorten <=0.2bp]
(\tikzlastnode.north west)edge(\tikzlastnode.north east)
}


Notice that, in order to correctly set the line with, it has been reduced a bit by means of shorten >=0.2bp, shorten <=0.2bp.

After percusse's comment I investigated a bit on it and actually I found a way to solve the problem.

Assume indeed to substitute \node[mynode] at (0,0){texta}; with \draw[red,dotted] node[mynode]at (0,0){texta};. You'll get:

But the following MWE demonstrates that this could be avoided (part of the credit should go to percusse's comment):

\documentclass[border=1bp]{standalone}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}

\tikzset{
my safe node/.style={
bottom color=white,top color=black!20,text=black,% <= that's for the text
line width=0pt, %<= now it's absolutely needed to not have problems while scaling the picture
append after command={% <= for the line
\pgfextra{%
\begin{pgfinterruptpath}
\begin{pgfonlayer}{foreground}
\draw[very thick,shorten >=0.05bp, shorten <=0.05bp] % <= this actually  is to remove a residual tiny exceeding border
(\tikzlastnode.north west)--(\tikzlastnode.north east);
\end{pgfonlayer}
\end{pgfinterruptpath}
}
}
}
}

\begin{document}
\scalebox{6}{
\begin{tikzpicture}
\draw[draw=red,dashed,ultra thick] (0,0) -- (1,1) node[my safe node]{texta} -- (2,2)
node[my safe node] {textb} --(3,3);
\end{tikzpicture}
}
\end{document}


The result is:

-
 This might cause some headache if used like \draw[red,dotted] node[mynode] {texta}; because append after command is meant to be used originally inside a path. Also outer sep is getting in the way hence the shorten requirements. – percusse Oct 12 '12 at 16:48 Oh.. that's right!! Just for curiosity I've tried if it is possible to override the definitions inside the mynode, but didn't succeed. Perhaps some postaction would help? – Claudio Fiandrino Oct 13 '12 at 13:52 I can't have a look at it right now but this still has a problem to which I don't know a fix yet (well an elegant one that is). The problem can be seen with \draw[red,dotted] (0,0) -- (1,1) node[my safe node]at (0,0){texta} -- (3,3);. It eats up the drawing options of a path. Same problem applies to tex.stackexchange.com/questions/71487/… too – percusse Oct 13 '12 at 14:54 Thank you, this works nicely and also thank you for taking the time to investigate the correct insertion into a draw command. – Alexander Oct 13 '12 at 18:36 @percusse: working a bit on it, I discover that the the scope environment is responsible to that. Some workaround is here, but still far to be an acceptable solution. – Claudio Fiandrino Oct 14 '12 at 10:25

The reason for the overhang is the line width on the original node (we've had a question about this but a quick search didn't find it). The anchors on a node are so that they touch the outside of the line. They therefore extend the actual node by half the line width of the stroke. This happens even if the node is not stroked (drawn). So when you use the anchor node.north east, you are actually (.5\pgflinewidth,.5\pgflinewidth) above the actual north east corner of the filled rectangle.

As your original node is not filled, the simplest fix for this is to set the line width to 0pt when it is created. The following code does this, and also folds the two commands into one using append after command (though percusse's commend to Claudio's answer is pertinent here), and creates a single style alias to invoke the lot.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/76459/86}
\usepackage{tikz}

\tikzset{
top down style/.style={
bottom color=white,
top color=black!20,
line width=0pt,
append after command={
(\tikzlastnode.north west) edge [very thick]
(\tikzlastnode.north east)
}
}
}

\begin{document}
\begin{tikzpicture}

\node[top down style] (node) at (0,0) {node};

\end{tikzpicture}

\end{document}


Here's the result:

(The apparent underhang is due to the conversion to PNG. In the PDF the alignment is exact.)

-
 Thank you, I would never guessed this but it makes a lot of sense. – Alexander Oct 13 '12 at 18:39