27

As a follow-up to this solution on defining the default text for a node, how can it be done with the use of a fill color? Note below that specification of a fill color abolishes the node text.

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzstyle{stuff_nofill}=[rectangle,draw,font={A}]
\tikzstyle{stuff_fill}=[rectangle,draw,fill=black!20,font={A}]
\begin{document}
\begin{tikzpicture}[node distance=0.5cm,auto]
 \node at (0,1) [stuff_nofill] {};
 \node at (0,0) [stuff_fill] {};
\end{tikzpicture}
\end{document}
2
  • It should be noted that it was mentioned in the linked solution, the font={} was not designed to place text in a node. Mar 22, 2012 at 1:56
  • "but nevertheless it works" no it does not work align=right,font={$x+2$\\very bad idea } Mar 22, 2012 at 22:50

4 Answers 4

28

Yet another hack but I think a little bit more robust since it utilizes a legitimate way of putting text inside a node.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzstyle{stuff_nofill}=[rectangle,draw,font={A}]
\tikzstyle{stuff_fill}=[rectangle,draw,fill=black!20,minimum size=1.4em,label={center:A}]
\begin{document}
\begin{tikzpicture}
 \node at (0,1) [stuff_nofill] {};
 \node at (0,0) [stuff_fill] {};
\end{tikzpicture}
\end{document}

enter image description here

My assumption is that the default text would be defined once and there is no need to change it often otherwise you would just put a regular node. So, we can do a little calculation about the default text size and draw the background node accordingly. The text will then fit into the filled rectangle.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newdimen\mywidth
\newdimen\myheight
\def\mytext{\Huge A}% define the text
\pgfmathparse{width("\noexpand\noexpand\noexpand\mytext")} %the width calc
\pgfmathsetlength{\mywidth}{\pgfmathresult} % Put it into a length register
\pgfmathparse{height("\noexpand\noexpand\noexpand\mytext")}%the height calc
\pgfmathsetlength{\myheight}{\pgfmathresult} % Put it into a length register
\tikzset{stuff_fill/.style={
                    rectangle,draw,fill=black!20, 
                    minimum height=1.5\myheight, % set the min height to the value above
                    minimum width=1.5\mywidth, % set the min width to the value above
                    label={center:\mytext} 
                    },
stuff_nofill/.style={rectangle,draw,font={A}}
}
\begin{document}
\begin{tikzpicture}
 \node at (1,0) [stuff_nofill] {};
 \node at (0,0) [stuff_fill] {};
\end{tikzpicture}
\end{document}

enter image description here

If you use \def\mytext{\tiny tiny text},

enter image description here

7
  • Excellent, that works perfectly percusse. Thank you. How, by the way, does one control the font size of the label within the tikzstyle definition? The minimum size option appears to regulate the size of the box itself. I can preface the text with a font size modifier such as \Large, but I didn't know if there was also an option that one could set to accomplish the same thing.
    – user001
    Mar 22, 2012 at 2:16
  • @user001 Wait, I think I don't get the question. Do you want to change the font size or you want to change the size of the box according to the label content?
    – percusse
    Mar 22, 2012 at 2:19
  • I wanted to change the font size (which I realize can be done by label={center: \Large A}, but I didn't know if there was a tikzstyle option that would do the same (\font=Large) does not have an effect. If the size of the box could scale in accordance with the label content, that would be a bonus.
    – user001
    Mar 22, 2012 at 2:25
  • @percusse: This answer should also be added to the linked question, as it is less hackish. Mar 22, 2012 at 2:36
  • 1
    @user001 See my edit to the answer.
    – percusse
    Mar 22, 2012 at 11:42
17

Although I clearly saw Alan's original answer, I have no memory of it and so when seeing this immediately starting thinking about how I would get some text automatically into a node.

There are several "hooks" in the construction of a node which can be used. Although these hooks are intended for certain purposes, they can be subverted for others, and some aren't really intended for anything but are just "general hooks".

The key macro in the TikZ code is \tikz@do@fig (reminds me of the card game Go Fish!). Looking through this macro, we find the following hooks, together with some other important stuff:

  1. The first thing that happens in that a box is started, called \pgfnodeparttextbox. This is what will be put inside the node as its "text" (and used for size computations).
  2. The first "hook" is: \tikzset{every text node part/.try}. So anything stored in that key gets evaluated. This can include arbitrary code. However, adding text at this point does nothing as we are still in "picture mode".
  3. The next important thing is that we get out of "picture mode". Now things can start to have an effect.
  4. At this point, \tikz@textfont is executed. This contains whatever was saved by the font key. Literally. This is the secret to Alan's method.
  5. Now it tests to see if the text was given a width, and if so starts a minipage (and a group).
  6. Next hook is \tikz@atbegin@node. This is a general purpose hook that can contain anything. As we're out of the picture mode, any text here is visible so this can be used to insert text. This is used to great effect in keys like matrix of math nodes to insert the magic $ at the start of the node. However ...
  7. Now we set the colour. This means that all the previous hooks were enacted before the colour was set.
  8. At this point, \tikz@do@fig is almost done. The last bits are to set up some stuff for after the node text is processed.
  9. The node text is now read.
  10. After the node text is read, control passes over to \tikz@fig@collectresetcolor. This does something with resetting colours, but only if explicitly asked. I'm not at all clear as to the effect that this has.
  11. Control now passes to \tikz@fig@boxdone.
  12. The first thing that happens here is \tikz@atend@node is executed (this is used by matrix of math nodes to insert the final $).
  13. Next, we tear down all of the stuff that \tikz@do@fig set up with no obvious hooks (one could play with \aftergroup and similar hacks, but only with Great Care).

So, we have three hooks provided by the keys font, execute at begin node, and execute at end node. Each has a drawback in that each is separated from the real text by one or more actions:

  • font occurs before any text width is taken into account, and before the text=colour is enacted.
  • execute at begin node is before text=colour is enacted.
  • execute at end node is after whatever the \reset@color is doing.

One other fact is important to note before putting all of this theory into practice. That is the question as to what colour is in effect at the start of all these shenanigans. This is the fill colour. This is quite important to note because it explains why Alan's code is seeming to fail in your example. It isn't. The text is there. It's just that it is rendered with the same colour as the fill. This suggests a simple addition to Alan's solution: set the colour explicitly.

Now, in fact, I'd recommend using execute at begin node instead of font. This is because font=X sets the hook to X, overriding anything already set. Whereas execute at begin node=X appends X to the list of things to be "executed". This makes it easier to manipulate in stages.

Here's some experimental code:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/48918/86}
\usepackage{tikz}
\makeatletter
\def\usetextcolour{%
  \ifx\tikz@textcolor\pgfutil@empty%
  \else%
  \pgfutil@colorlet{.}{\tikz@textcolor}%
  \fi%
  \pgfsetcolor{.}%
}
\makeatother

\tikzset{
  every node/.style={
    draw=orange,
    fill=blue,
    text=red
  },
  auto text colour/.style={
    execute at begin node=\usetextcolour
  },
  method 1/.style={
    every text node part/.style={add text}
  },
  add text/.code={first method},
  method 2/.style={
    font={\usetextcolour second method}
  },
  method 3/.style={
    auto text colour,
    execute at begin node={second method}
  },
  method 4/.style={
    execute at end node={third method}
  },
}

\begin{document}
\begin{tikzpicture}
\foreach \k in {1,...,4} {
  \node[method \k] at (0,-\k) {lorem};
}
\end{tikzpicture}
\end{document}

The "first method" tries to use the every text node part/.try hook but fails as that's too early. The other methods are the other hooks. An interesting experiment to try (to verify what I said about colours) is to set fill opacity=0,text opacity=1 and to remove the references to \usetextcolour. This shows that the text added by the second and third methods is in the fill colour, as claimed.

Here's the results with the above code:

automatic text in nodes

I think that of these methods, I'd go for the execute at end node hook. Whilst that \reset@color stuff worries me a bit, it doesn't worry me all that much so it seems the cleanest hook to get stuff into the node contents automatically.

0
7

With TiKZ 3.0 and node contents option it's possible to define node contents in options and fill the node without problems:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzstyle{stuff_nofill}=[rectangle,draw,node contents={A}]
\tikzstyle{stuff_fill}=[rectangle,draw,fill=black!20,node contents={A}]
\begin{document}
\begin{tikzpicture}[node distance=0.5cm,auto]
 \node at (0,1) [stuff_nofill];
 \node at (0,0) [stuff_fill];
\end{tikzpicture}
\end{document}

enter image description here

3

There is a command in TiKz for doing this : preaction.
To fill a node in place of [fill=black!20] you can use [preaction={fill=black!20}].

The complete code in your case is :

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzstyle{stuff_nofill}=[rectangle,draw,font={A}]
\tikzstyle{stuff_fill}=[rectangle,draw,preaction={fill=black!20},font={A}]
\begin{document}
\begin{tikzpicture}[node distance=0.5cm,auto]
 \node at (0,1) [stuff_nofill] {};
 \node at (0,0) [stuff_fill] {};
\end{tikzpicture}
\end{document}

enter image description here

Note 1 : the library calc and the style [node distance=0.5cm,auto] are usless in your example.

Note 2 : (do not repeat yourself) you can define stuff_fill as follows \tikzstyle{stuff_fill}=[preaction={fill=black!20}, stuff_nofill].

You must log in to answer this question.

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