Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have an example to explain my problem but if the code compiles and if I get a good result, I don't understand why !

The idea is to split a circle node like in this question . I want to fill the node with two colors.

It's not possible to use the same code but perhaps I'm wrong.

1) first with insert path, I think I can't use \tikzlastnode because this macro is not defined. \pgf@node@name seems to be defined only for multipart node.

2) I try with append after command but the code is strange. I need to use a scope with the background layer. But

     \node[ circle,
     draw=blue,
     text=white,
     font=\bfseries,
     append after command={
       \pgfextra{% 
     \pgfpointdiff{\pgfpointanchor{\tikzlastnode}{center}}%
                  {\pgfpointanchor{\tikzlastnode}{east}}%            
     \pgfmathsetmacro\insiderad{\pgf@x}
     \begin{scope}[on background layer]
        \fill[orange] (\tikzlastnode.center) 
                      ([xshift=\pgflinewidth]\tikzlastnode.west)  arc
                      (180:360:\insiderad-\pgflinewidth);  
        \fill[red]    (\tikzlastnode.center) 
                      ([xshift=-\pgflinewidth]\tikzlastnode.east) arc
                      (0:180:\insiderad-\pgflinewidth);  
       \end{scope}
     }  
   },text opacity=1] (last name) {big label}; 

gives

enter image description here

and if I remove the scope environment, the same code

        \fill[orange] (\tikzlastnode.center) 
                      ([xshift=\pgflinewidth]\tikzlastnode.west)  arc
                      (180:360:\insiderad-\pgflinewidth);   
        \fill[red]  (\tikzlastnode.center) 
                    ([xshift=-\pgflinewidth]\tikzlastnode.east) arc
                    (0:180:\insiderad-\pgflinewidth); 

give a bad result too :

enter image description here

The only code correct seems to be :

 \documentclass[11pt]{scrartcl}
 \usepackage{tikz}
 \usetikzlibrary{shapes,backgrounds,calc}

  \begin{document}

  \makeatletter
  \begin{tikzpicture}[line width=3mm]
    \node[ circle,
           draw=blue,
           text=white,
           font=\bfseries,
           append after command={
             \pgfextra{% 
                \pgfpointdiff{\pgfpointanchor{\tikzlastnode}{center}}%
                             {\pgfpointanchor{\tikzlastnode}{east}}%            
                \pgfmathsetmacro\insiderad{\pgf@x}
                 \fill[orange] (\tikzlastnode.center) 
                               ([xshift=\pgflinewidth]\tikzlastnode.west)  arc
                               (180:360:\insiderad-\pgflinewidth);  
                 \begin{scope}[on background layer]   
                      \fill[red]  (\tikzlastnode.center) 
                                  ([xshift=-\pgflinewidth]\tikzlastnode.east) arc
                                  (0:180:\insiderad-\pgflinewidth);  
       \end{scope}
     }  
 },text opacity=1] (last name) {big label}; 

 \end{tikzpicture}  
 \end{document} 

and I get :

enter image description here

My question is why I need to use like this the scope. A second question is to know if there is another way to get the name of the last node than \pgf@node@name and \tikzlastnode.

Perhaps someone knows another method to get the same result.

Remark :

In the link (multipart node given above) I realized at the end that I could remove the environment scopebut it was a surprise for me. It seems that the text is placed at the end of the construction of the shape.

share|improve this question
add comment

2 Answers

up vote 6 down vote accepted

What's causing the strange behaviour here is the fact that you are nesting path constructions. As I'm sure you know, when TikZ constructs a path then it handles nodes in a slightly special way. They are processed as they are encountered (since information about them is needed later) but they aren't placed until after the path has been constructed. To do this, TikZ stores the nodes in a box, \tikz@figbox, until it is time to place them.

The append after command key sticks a bit extra in the current path after the node command has been processed. The important thing to note is that this is before the actual node has been placed. This is what you want since you want the two half circles to be placed behind the node. However, what TikZ is expecting from the append after command is an extension of the current path, not a whole new path construction! So it doesn't do anything special to protect the current path from whatever you do in the append after command code. In this case, what you do is create a whole new path! In fact, you create two of them.

It's the two of them that is causing the immediate problem, but I can imagine situations where even one would be problematic. The problem is that the node box, \tikz@figbox, is being used inside the first path: TikZ thinks that the nodes from the parent path are actually nodes on the first child path. They get used there, then the box is cleared, and the second child path is drawn therefore on top of the node.

The remedy is to protect the node box from the child paths. Looking at the TikZ code, there are other places where this has to be done: preactions and postactions. There, the code is:

\def\tikz@extra@preaction#1{%
  {%
    \pgfsys@beginscope%
      \setbox\tikz@figbox=\box\pgfutil@voidb@x%
      \path[#1];% do extra path
      \pgfsyssoftpath@setcurrentpath\tikz@actions@path% restore
      \tikz@restorepathsize%
    \pgfsys@endscope%
  }%
}

As you're doing a node, not a path, you probably don't need to worry about the actual path or any details of the scope (though it may be safest to put them in for a more complicated example). All you actually need is the grouping and the \tikz@figbox declaration. Hence the following works:

\documentclass[11pt]{scrartcl}
 \usepackage{tikz}
\usepackage{trace-pgfkeys}
 \usetikzlibrary{shapes,backgrounds,calc}

  \begin{document}
  \makeatletter
  \begin{tikzpicture}[line width=3mm]
    \node[ circle,
           draw=blue,
           text=white,
           font=\bfseries,
           append after command={
             \pgfextra{%
                \pgfpointdiff{\pgfpointanchor{\tikzlastnode}{center}}%
                             {\pgfpointanchor{\tikzlastnode}{east}}%            
                \pgfmathsetmacro\insiderad{\pgf@x}
{
                             \setbox\tikz@figbox=\box\pgfutil@voidb@x
                 \fill[orange] (\tikzlastnode.center) 
                               ([xshift=\pgflinewidth]\tikzlastnode.west)  arc
                               (180:360:\insiderad-\pgflinewidth);  
                      \fill[red]  (\tikzlastnode.center) 
                                  ([xshift=-\pgflinewidth]\tikzlastnode.east) arc
                                  (0:180:\insiderad-\pgflinewidth);  
}
}
 },text opacity=1] {big label}; 
 \end{tikzpicture}  
 \end{document} 

with result:

split circle

share|improve this answer
    
\setbox\tikz@figbox=\box\pgfutil@voidb@x great idea. Intuitively I thought that you expressed very well in your answer but I was not able to organize my ideas. Now it's more clearer and clever. Thanks for this great answer and thanks for \tikz@figbox !! –  Alain Matthes May 14 '12 at 11:47
    
Yet another great explanation! –  percusse May 14 '12 at 13:05
add comment

One peculiar detail about the append after command usage is that it has to sit inside a path construction command. In other words, the node must be interrupting a path construction so that whenever it is declared the path construction can continue. But you are using it inside a node command hence things get weird.

You can place your node inside a path command while calculation of the radius can be done via a let operation. I have filled the background with a light blue color and placed the half filled node on top of it. It is still puzzling for me how we can fill the other half with a different color. This is difficult since the color is dictated by the \path[fill=red] and I don't know how to change inside a path command. Another option would be going to the lower level and using \pgfpositionnodelater type of commands to set up the whole node creation process.

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes,backgrounds,calc}
\begin{document}
\begin{tikzpicture}
\begin{scope}
\clip (0,0) circle (2.65cm);
\fill[blue!25] (-5cm,-5cm) rectangle (5cm,5cm);
\path[fill=red] node[circle,
           line width=3mm,
           minimum height=5cm,
           draw=blue,
           text=white,
           font=\bfseries,
           append after command={ 
               let \p1=(a.east),\p2=(a.center),\n1={veclen(\x1-\x2,0)}  
                   in (a.east) arc (0:180:\n1) -- cycle
          }
          ] at (0,0) (a) {\huge big label};
\end{scope}
\end{tikzpicture}
\end{document}

enter image description here

It's not quite portable as it is but via defining a new style this can probably float.

share|improve this answer
    
Or you can directly create a new shape by inheriting from circle and adding a \behindbackgroundpath{} code –  percusse May 14 '12 at 2:32
    
It's not exactly what I want. My style works. I want to find an explanation about the need of \begin{scope}[on background layer] inside the ` append after command`. It's not satisfactory to have a code and do not understand. –  Alain Matthes May 14 '12 at 6:56
    
I added the results when I move the scopes. I would like to understand these three codes. –  Alain Matthes May 14 '12 at 7:03
    
@Altermundus If you put your node over a colored surface it would lose the top color. –  percusse May 14 '12 at 10:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.