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.

To highlight part of a graph for a presentation that I'm writing, I would like to "circle" an area and make semitransparent everything outside that area. Anything inside that area should remain opaque. Is there a way to accomplish this inside TikZ?

As an example, in the following picture, I would like to make nodes a and c semitransparent, as well as the fraction of the edge from a to b that lies outside the circle.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[vertex/.style={draw, fill={#1}}]
  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};

  \draw (a) edge (b);

  \draw [red] (b) circle [radius=0.75];
\end{tikzpicture}
\end{document}

Of course, I could always accomplish this by manually making the desired pieces transparent, but for a complex picture it would be better to use some kind of clipping. I've read through the manual and vaguely understand clipping and transparency, but I don't see how to put those keys together to get what I want.

share|improve this question

4 Answers 4

up vote 5 down vote accepted

Two attempts here, the first is not ideal, but "fakes" transparency by overlaying a semi-transparent white rectangle and uses the spy library:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{positioning,spy}
\tikzset{%
  white out/.style={
    preaction={%
      even odd rule, 
      fill=white, 
      fill opacity=0.75,
      insert path={
        % This covers the current picture.
        (current bounding box.south west) 
        rectangle
        (current bounding box.north east) 
      }
    }
  }
}

\begin{document}
\begin{tikzpicture}[vertex/.style={draw, fill={#1}}, spy using outlines={circle, magnification=1}]

  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};

  \draw (a) edge (b);

  \spy [size=0.75cm] on (b) in node [thin, red, white out] at (b);

\end{tikzpicture}
\end{document}

enter image description here

The second manages the semi-transparency but must capture the original picture inside a scope:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{positioning}

\newbox\tikzcapturebox
\tikzset{capture scope/.style={
   execute at begin scope={\global\setbox\tikzcapturebox=\hbox\bgroup}, 
   execute at end scope={\egroup\copy\tikzcapturebox}
},
captured scope as path picture/.style={
  preaction={path picture={\pgfextra{\copy\tikzcapturebox}}}
}}


\begin{document}
\begin{tikzpicture}[vertex/.style={draw, fill={#1}}]

\node [text=gray!50, font=\footnotesize] at (1.25,0) {some text behind the figure};

\begin{scope}[transparency group, opacity=0.5, capture scope]
  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};
  \draw (a) edge (b);
\end{scope}

\draw [red, captured scope as path picture] (a) circle [radius=0.5];
\draw [blue, captured scope as path picture] ([xshift=-0.25cm]c) circle [radius=0.25];

\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
I would've never thought of this idea! I agree that it's not quite ideal, but it seems to work great for my purpose. I'll wait to accept this answer, in case someone comes up with something else, but otherwise I'll try to remember to accept your answer in a day or so. Thanks so much for your help! –  Henry DeYoung May 29 at 21:24

A layman's solution (whose doesn't like spies ;)):

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[vertex/.style={draw, fill={#1}}]
  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};

  \draw (a) edge (b);

  \draw [red] (b) circle [radius=0.75];
  \fill[white,fill opacity=0.75](current bounding box.south west) rectangle 
                                (current bounding box.north east);
  \begin{scope}
    \clip (b) circle [radius=0.75];
    \node [vertex=blue, right=of a] {};
    \draw (a) edge (b);
    \draw [red] (b) circle [radius=0.75];
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
circle[radius=0.75cm+.5\pgflinewidth] gives a better clip region. –  Paul Gaborit May 30 at 13:57
    
This is a good idea too, but I'd rather not have to explicitly recreate the parts inside the red circle. I am greedy that way. :) –  Henry DeYoung May 30 at 20:30

Here is a very simple solution (trick: a white background).

enter image description here

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[vertex/.style={draw, fill={#1}}]
  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};
  \draw (a) edge (b);
  \draw [red] (b) circle [radius=0.75];

  \fill[white,fill opacity=.75]
  (current bounding box.south west) rectangle (current bounding box.north east)
  (b) circle[radius=0.75cm+.5\pgflinewidth];
\end{tikzpicture}
\end{document}
share|improve this answer
    
I like this answer for its simplicity without manually repeating the nodes a, b, and c, etc. One question: if I comment out the red circle (and use a different fill color for the rectangle-circle path, say, gray, just to see what is going on), I get a strange result in which only some of the area surrounding the circle is filled transparent gray. Using even odd rule doesn't seem to help. Do you know why? –  Henry DeYoung May 30 at 20:19
    
@HenryDeYoung If you comment out the red circle, the current bouding box changes... Instead of comment out the red circle, try to change its \draw to \path and remove +.5\pgflinewidth. –  Paul Gaborit May 31 at 8:42

This looks like the same problem with inverse clipping and plus filling with some color with opacity less than 1. I stole Paul's nice solution from How can I invert a 'clip' selection within TikZ?. And to make it do more than clipping you need to reuse the path and hence the preaction.

EDIT: I confused myself. No clipping is necessary obviously (thanks Henry). Just filling is enough. Renamed it to invselect. Result stays the same.

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

\tikzset{
    vertex/.style={draw, fill={#1}},
    invselect/.style={insert path={{[reset cm]
      (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)
    }}
  },
  hilite/.style={fill=#1,opacity=0.9,overlay,invselect}
}

\begin{document}
\begin{frame}

\begin{tikzpicture}
  \fill[yellow] (-3,-2) rectangle (3,2);
  \node (a) [vertex=blue] {};
  \node (b) [vertex=blue, right=of a] {};
  \node (c) [vertex=green, right=of b] {};

  \draw (a) edge (b);

  \draw [red] (b) circle [radius=0.75];

  \path<2>[hilite=white] (b) circle (0.75) ;
  \path<3>[hilite=brown] (a) circle (1);
\end{tikzpicture}

\end{frame}
\end{document}

enter image description here

share|improve this answer
    
Thanks for your help! One quick question: When I remove the preaction=clip, there is no change to the results (as far as I can tell). Why is that option there? Also (ok, two questions, I guess), based on the answer that you linked to, I would have expected preaction={clip, insert path=...}, but that doesn't have the correct result. So, could you explain why moving the insert path=... outside the preaction is the right thing to do? Sorry to ask so many questions; I just want to understand so I can better solve future problems that I run into. –  Henry DeYoung May 30 at 21:22
    
@HenryDeYoung Too few coffees. Of course you are right. There is no need for clipping. I'm probably getting tired from work. I'll fix it. –  percusse May 30 at 21:33

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.