7

I am loading two curves from a file and plot them with \addplot table [...] {the table.txt}; I have managed to fill the area under a single curve, but I want the minimum of the two curves filled. What is the preferred way to accomplish this using tikz and pgfplots? The image shows an example of the desired result.

Thanks for any help.

enter image description here

0

3 Answers 3

10

This can be done by the fillbetween library which is shipped with pgfplots version 1.10:

enter image description here

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.9}

% \usetikzlibrary{}
\usepgfplotslibrary{fillbetween}


\begin{document}

\begin{tikzpicture}
    \begin{axis}[axis on top,set layers]
    \addplot[blue,name path=A,domain=0:2.3] {sin(deg(2*x))};    

    \addplot[red,name path=B,domain=0:2.3] {cos(deg(2*x))};

    \pgfonlayer{pre main}
    \fill[blue!20!white,intersection segments={of=A and B,sequence={A0 -- B1 -- A2}}]
        -- (axis cs:2.3,\pgfkeysvalueof{/pgfplots/ymin})
        -- (axis cs:0,\pgfkeysvalueof{/pgfplots/ymin})
        -- cycle
    ;
    \endpgfonlayer
    \end{axis}
\end{tikzpicture}
\end{document}

The idea is to use the new intersection segments path instructions provided by fillbetween. It accepts to labelled paths on input and a sequence of intersection segments. Currently, the "minimum" needs to be provided manually. In your case, you need to use the first (0th) segment of the first (A) curve (A0), then the second (1st) of the second curve (B) which is B1, followed by the third (2rd) segment of the first curve which is A2. The other statements specify the bottom line of the filled region. The layering instructions set layers and \pgfonlayer make sure that the stuff appears behind the labelled input paths.

Note that version 1.10 is very young at the time of this writing - you might need a software upgrade.

6
  • Ok, so you have to manually add to sequence={A0 -- B1 -- A2} if there are more intersections, B3 -- A4 -- B5 etcetera? As my data comes from a table, would you say it is just better to have an extra column with the minimum of my two functions?
    – Godisemo
    Mar 14, 2014 at 9:32
  • Well, if you have the two functions sampled at the same points, you could easily let pgfplots compute the minimum and draw a separate plot with the minimum and \closedcycle. My solution is better if the curves do not have the same sample points. Mar 14, 2014 at 9:36
  • In my case they are sampled at the same points. What is the function I would use for computing the minimum inside pgfplots, rather than adding an extra column to my input file? Thanks for the help and for an awesome package!
    – Godisemo
    Mar 14, 2014 at 9:42
  • Just for future reference, I managed to do what I wanted using the y expr key and section 4.3.4 "Mathematical Expressions And File Data" in the pgfplots 1.10 manual. I'll mark this anser as accepted.
    – Godisemo
    Mar 14, 2014 at 9:59
  • 1
    @Godisemo could you add your own answer as well? While I am excited about the new fillbetween stuff, your example might actually be a simpler and more automatic solution. It will help visitors to see the different solutions. Mar 14, 2014 at 14:18
3

Another alternative is use of the clip twice, without fillbetween library. First, fill the area below sine curve and then clean the area above cosine curve.

enter image description here

Code:

\documentclass{article}
\usepackage[papersize={11cm,10cm}]{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\thispagestyle{empty}

\begin{document}

\begin{tikzpicture} 
\begin{axis}[enlargelimits=0.1]
\begin{scope}
\clip(axis cs:0,-1.19) -- (axis cs:2.3,-1.19) -- (axis cs:2.3,1)-- (axis cs:0,1)--  cycle;
\addplot[draw=white,fill=blue!20!white,domain=0:2.3] {sin(deg(2*x))}--(axis cs:2.3,-1.5) --(axis cs:0,-1.5);    
\end{scope}

\begin{scope}
\clip (axis cs:2.3,-1) -- (axis cs:2.3,1) -- (axis cs:0,1)-- (axis cs:0,-1)--cycle;
\addplot[draw=white,fill=white,domain=0:2.3] {cos(deg(2*x))}--(axis cs:2.3,1)--(axis cs:0,1);
\end{scope}
\addplot[red,domain=0:2.3] {cos(deg(2*x))};
\addplot[blue,domain=0:2.3] {sin(deg(2*x))};
\end{axis}
\end{tikzpicture}  
\end{document}
0

Just for finalizing the question with PSTricks.

Postfix representation

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-plot,pst-eucl}

\def\f{x RadtoDeg sin 2 mul 3 add}
\def\g{x RadtoDeg cos 2 mul 3 add}

\begin{document}
\begin{pspicture}[saveNodeCoors,PointName=none,PointSymbol=none](-1,-1)(7,6)
    \pstInterFF{\f}{\g}{1}{A}
    \pstInterFF{\f}{\g}{4}{B}
    \pscustom[linestyle=none,fillstyle=solid,fillcolor=lightgray]
    {
        \psplot{.5}{N-A.x}{\f}
        \psplot{N-A.x}{N-B.x}{\g}
        \psplot{N-B.x}{6}{\f}
        \psline(6,0)(.5,0)
        \closepath
    }
    \psaxes[ticks=none,labels=none]{->}(0,0)(-1,-1)(6.5,5.5)[$x$,0][$y$,90]
    \psplot[linecolor=blue]{0}{TwoPi}{\f}
    \psplot[linecolor=red]{0}{TwoPi}{\g}
\end{pspicture}
\end{document}

enter image description here

Infix representation

If you prefer to work in infix, use the following.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-plot,pst-eucl}

\def\f{(2*sin(x)+3)}
\def\g{(2*cos(x)+3)}

\pstVerb{/I2P {AlgParser cvx exec} def}

\begin{document}
\begin{pspicture}[algebraic,saveNodeCoors,PointName=none,PointSymbol=none](-1,-1)(7,6)
    \pstInterFF{\f I2P}{\g I2P}{1}{A}
    \pstInterFF{\f I2P}{\g I2P}{4}{B}
    \pscustom[linestyle=none,fillstyle=solid,fillcolor=lightgray]
    {
        \psplot{.5}{N-A.x}{\f}
        \psplot{N-A.x}{N-B.x}{\g}
        \psplot{N-B.x}{6}{\f}
        \psline(6,0)(.5,0)
        \closepath
    }
    \psaxes[ticks=none,labels=none]{->}(0,0)(-1,-1)(6.5,5.5)[$x$,0][$y$,90]
    \psplot[linecolor=blue]{0}{TwoPi}{\f}
    \psplot[linecolor=red]{0}{TwoPi}{\g}
\end{pspicture}
\end{document}

You must log in to answer this question.

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