10

I'm using Tikz and have two polar curves r=1.5+cos(t) and r=1.5. I would like to fill (shade) the area between curves (shown by an arrow on the picture). How can I do this? Maybe using \clip or something?

enter image description here

I tried \tikzfillbetween but it behaves weirdly in polar coordinates.

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{arrows, intersections, fillbetween}
\begin{document}
\begin{tikzpicture}
\begin{axis}[grid = both]
    % Outer curve
    \addplot [data cs=polar, domain=0:360, samples=180, black,
        line width=1pt, smooth](x, {1.5+cos(x)});
    % Inner curve
    \addplot [data cs=polar, domain=0:360, samples=180, green,
        line width=1pt, smooth](x, 1.5);
\end{axis}
\end{tikzpicture} 
\end{document}
  • Welcome to TeX.SX! You can help us to help you by providing the code for a small compilable document that shows your problem called MWE. Just edit your question and add missing code. – Bobyandbob Dec 10 '17 at 14:02
  • @Bobyandbob Thanks for the advise I've edited my question. – user35603 Dec 10 '17 at 14:16
  • See: Graphics: Area between curves. I think its a duplicat... have a look... – Bobyandbob Dec 10 '17 at 14:23
  • 1
    In the question that you linked the curves are not polar. And it does not work here. I would like an approach suitable for polar curves. – user35603 Dec 10 '17 at 14:25
  • Since you have some responses below that seem to answer your question, please consider marking one of them as ‘Accepted’ by clicking on the tickmark below their vote count (see How do you accept an answer?). This shows which answer helped you most, and it assigns reputation points to the author of the answer (and to you!). It's part of this site's idea to identify good questions and answers through upvotes and acceptance of answers. – user36296 Jan 7 '18 at 14:52
12

You could use intersection segments:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}% <- added!!
\usepgfplotslibrary{fillbetween}% <- changed
\begin{document}
\begin{tikzpicture}
\begin{axis}[grid = both,
    set layers% <- added
]
    % Outer curve
    \addplot [data cs=polar, domain=0:360, samples=180, black,
        line width=1pt, smooth,
        name path=outer
        ](x, {1.5+cos(x)});
    % Inner curve
    \addplot [data cs=polar, domain=0:360, samples=180, green,
        line width=1pt, smooth,
        name path=inner
        ](x, 1.5);
    % Filling
    \begin{pgfonlayer}{axis background}
      \fill [orange!30,
          intersection segments={
            of=inner and outer,
            sequence={L0--L1--R1[reverse]--R0[reverse]}
          }];
    \end{pgfonlayer}
\end{axis}
\end{tikzpicture} 
\end{document}

Result:

enter image description here


Example showing the segments:

enter image description here

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}% <- added!!
\usepgfplotslibrary{fillbetween}% <- changed
\begin{document}
\begin{tikzpicture}
\begin{axis}[grid = both,
    set layers% <- added
]
    % Outer curve
    \addplot [data cs=polar, domain=0:360, samples=180, black,
        line width=1pt, smooth,
        name path=outer
        ](x, {1.5+cos(x)});
    % Inner curve
    \addplot [data cs=polar, domain=0:360, samples=180, green,
        line width=1pt, smooth,
        name path=inner
        ](x, 1.5);
    % Filling
    \begin{pgfonlayer}{axis background}
        \fill [orange!30,
            intersection segments={
              of=inner and outer,
              sequence={L0--L1--R1[reverse]--R0[reverse]}
            }];
    \end{pgfonlayer}
\end{axis}
% Showing the segments
\begin{scope}[line width=2pt,->,font=\bfseries]
    \foreach[count=\i from 0] \c in {green,orange,purple}{
        \edef\temp{\noexpand\draw [\c,
            intersection segments={of=inner and outer,sequence={L\i}}]node[left]{L\i};}
        \temp}
     \foreach[count=\i from 0] \c in {blue,gray,yellow}{
         \edef\temp{\noexpand\draw [\c,
            intersection segments={of=inner and outer,sequence={R\i}}]node[right]{R\i};}
         \temp}
 \end{scope}
\end{tikzpicture} 
\end{document}
5

I found a solution, maybe not the optimal one, but it allows to generalize. In (axis cs: {(1.5)*cos(\x)}, {(1.5)*sin(\x)}) in the frame inside scope one can substitude any polar equation in the form r(\x) instead of (both) 1.5.

enter image description here

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{arrows, intersections, fillbetween}
\begin{document}
\begin{tikzpicture}
\begin{axis}[grid = both]
    % Outer curve
    \addplot [data cs=polar, domain=0:360, samples=180, black,
        line width=1pt, smooth](x, {1.5+cos(x)});
    % Inner curve
    \addplot [data cs=polar, domain=0:360, samples=180, green,
        line width=1pt, smooth](x, 1.5);
    % Shading        
    \begin{scope}
        % Frame (inversed)
        \path[clip] plot[domain=0:360, samples=180] 
            (axis cs: {(1.5)*cos(\x)}, {(1.5)*sin(\x)}) 
            -- (current page.north east) -- (current page.south east) 
            -- (current page.south west) -- (current page.north west) 
            -- (current page.north east);
        % framed plot
        \addplot [data cs=polar, domain=0:360, samples=180, draw=none,
            fill = yellow!40!white, fill opacity = 0.5,
            line width=1pt, smooth](x, {1.5+cos(x)});
    \end{scope}
\end{axis}
\end{tikzpicture} 
\end{document}
3

A way of doing it with MetaPost, for whom it may interest.

Edit My first attempt made use of the otherwise very handy buildcycle macro, but I've just realized that filling the cardioid and then unfilling the circle is much simpler in this particular case.

\documentclass[border=3mm]{standalone}
\usepackage{luatex85, luamplib}
    \mplibsetformat{metafun}
\begin{document}
\begin{mplibcode}
vardef plrfcn(expr tmin, tmax, tstep)(text r_t) =
    save t; t := tmin;
    (r_t)*dir t forever: hide(t := t + tstep) exitunless t <= tmax; 
        .. (r_t)*dir t 
    endfor
    if t-tstep < tmax: hide(t := tmax) .. (r_t)*dir t fi    
enddef;
u = cm; xmin = -2; xmax = 3; ymax = -ymin = 2;
beginfig(1);
    % grid
    for x = xmin upto xmax:
        draw u*(x, ymin) -- u*(x, ymax) withcolor .8white;
        if x>xmin: label.bot(TEX("$" & decimal x & "$"), u*(x, ymin)) fi;
    endfor;
    for y = ymin upto ymax:
        draw u*(xmin, y) -- u*(xmax, y) withcolor .8white;
        label.lft(TEX("$" & decimal y & "$"), u*(xmin, y));
    endfor; 
    % polar curves and filled area
    path cardio, circle; 
    circle = (plrfcn(0, 359, 1)(1.5) .. cycle) scaled u;
    cardio = (plrfcn(0, 359, 1)(1.5 + cosd t) .. cycle) scaled u;
    fill cardio withcolor .25[white, yellow]; unfill circle;
    draw cardio; draw circle withcolor green;
endfig;
\end{mplibcode}
\end{document}

enter image description here

3

An emergency-purpose-only solution with PSTricks.

\documentclass[pstricks,border=1cm]{standalone}
\usepackage{pst-plot}

\begin{document}
\begin{pspicture}[algebraic,polarplot,plotpoints=100](-3,-3)(3,3)
    \psaxes[axesstyle=polar,tickcolor=gray!25,ylabelFactor=^\circ](3,0)
    \pscustom[fillstyle=solid,fillcolor=yellow!25]
    {
        \psplot{PiDiv2}{PiDiv2 neg}{1.5}
        \psplot{PiDiv2 neg}{PiDiv2}{1.5+cos(x)}     
    }   
    \psplot[linecolor=blue]{0}{TwoPi}{1.5}
    \psplot[linecolor=red]{0}{TwoPi}{1.5+cos(x)}        
\end{pspicture}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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