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}
user35603
  • 307

4 Answers4

13

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}
esdd
  • 85,675
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}
user35603
  • 307
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

Franck Pastor
  • 18,756
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

Display Name
  • 46,933