2

I have a parabola and 4 lines. What I need to do is fill the outer area delimited by the parabola and these lines. Here is what I currently have 1]

I would like the orange fill to be only in the rectangle delimited by the segments AH and AB.

I have tried clipping the fill but to no luck. I am using PGFplots. Here is my current relevant code

\documentclass{article}

\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.11}
\usepgfplotslibrary{fillbetween}

% axis style, ticks, etc
\pgfplotsset{every axis/.append style={
              axis x line=middle,    % put the x axis in the middle
              axis y line=middle,    % put the y axis in the middle
              axis line style={<->}, % arrows on the axis
              xlabel={$x$},          % default put x on x-axis
              ylabel={$y$},          % default put y on y-axis
              axis equal,            % 1:1 ratio
              grid=both,             % coordinate grid
              grid style={line width=.1pt, draw=gray!10},
              major grid style={line width=.2pt,draw=gray!50},
              ticks=both,            % ticks for integers
              minor tick num=5,      % number of subticks
              ticklabel style={font=\small,fill=white},
              xlabel style={at={(ticklabel* cs:1)},anchor=north west},
              ylabel style={at={(ticklabel* cs:1)},anchor=south west},
            }
}
\tikzset{>=stealth}

\begin{document}

\begin{center}
  \begin{tikzpicture}
    \begin{axis}[xmin=-1.5,ymin=-1,xmax=2.5,ymax=6]
      \coordinate (O) at (0,0);
      \node[fill=white,circle,inner sep=0pt] (O-label) at ($(O)+(-35:10pt)$) {$O$};

      \coordinate (A) at (-1.12,1.24);
      \LabelPoint[mark=*][above right]{-1.09}{1.18}{$A$}

      \coordinate (B) at (-1.4,1.96);
      \LabelPoint[mark=*][above right]{1.4}{1.96}{$B$}

      \coordinate (H) at (-0.63,-0.21);
      \LabelPoint[mark=*][below left]{-0.63}{-0.21}{$H$}

      \addplot[name path = f,red,thick,samples=500] {x^2};
      \addplot[name path = l1,thick] {1/3*x+1.5};
      \addplot[name path = l2,thick] {1/3*x};
      \addplot[name path = p1,thick,green] {-3*x-2.1};
      \addplot[name path = p2,thick,green] {-3*x+6.2};
      \addplot [
        thick,
        color=blue,
        fill=none, 
        fill opacity=0.5
      ]
      fill between[
        of=f and l1,
        split,
        every segment no 1/.style={
            fill=blue,
        },
      ];
      \clip (A) -- (B) -- (1.86,0.62) -- (H) -- cycle;
      \clip[domain=-1.5:2] plot (\x,{\x^2}) -- (2,0) -- (-1.5,0) -- cycle;
      \addplot[
        thick,
        color=orange,
        fill=orange,
        fill opacity=0.5
      ]
      fill between[
        of=f and l2,
        soft clip={domain=-1.12:1.86} 
      ];
    \end{axis}
  \end{tikzpicture}
\end{center}
\end{document}

(\LabelPoint does just a mark at the given coordinate and puts a node with some text).

Both with and without clipping, the result remains unchanged. I'm still quite new to PGF I previously had a solution with only Tikz but looked very bad and was curious to try out PGF for graphs.

Is there a general way of dealing with filling areas between more than 2 plots? Is that general case applicable here?

Thanks for any help.

2
  • Just for clarification: You want to fill the part below the parabola that is surrounded by the green and black line, correct? Jan 10 '18 at 20:12
  • Yes. Below the parabola between the lines. Basically "reduce" the orange part.
    – gjkf
    Jan 10 '18 at 20:15
6

So this is what you are searching for. For details please have a look at the comments in the code. The trick is to draw two orange fillings, i.e. one for the left part and one for the right part.

To do so I use the intersection segments feature (which is roughly the TikZ equivalent of PGFPlots fill between). Then sequence allows us to draw an arbitrary path of the both paths given to of. In short: L and R stand for "left" and "right" which correspond to the paths given to of. The numbers refer to the path elements. 1 means "from the start to the first intersection point", 2 means "from the first intersection point to the second intersection point", etc.

(I have added some commented "debugging" code at the end of the code with some descriptions. Try it once and you will quite easily find out how it works. Unfortunately sometimes there is some "magic" left, as also is in this example.)

% used PGFPlots v1.15
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{
        calc,
        pgfplots.fillbetween,
    }
    \tikzset{>=stealth}
    \pgfplotsset{
        compat=1.11,
        every axis/.append style={
            axis x line=middle,
            axis y line=middle,
            axis line style={<->},
            xlabel={$x$},
            ylabel={$y$},
            axis equal,
            grid=both,
            grid style={line width=.1pt, draw=gray!10},
            major grid style={line width=.2pt,draw=gray!50},
            ticks=both,
            minor tick num=5,
            ticklabel style={font=\small,fill=white},
            xlabel style={at={(ticklabel* cs:1)},anchor=north west},
            ylabel style={at={(ticklabel* cs:1)},anchor=south west},
        },
    }
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        xmin=-1.5,
        ymin=-1,
        xmax=2.5,
        ymax=6,
        % to be able to draw the orange filling on another layer
        set layers,
    ]

        % draw the function and the "intersection lines"
            % (please note that I have changed the number of samples and added
            %  the option `smooth' to avoid some numerical instabilities for `f')
        \addplot [name path=f,red,thick,samples=49,smooth] {x^2};
        \addplot [name path=l1,thick] {1/3*x+1.5};
        \addplot [name path=l2,thick] {1/3*x};
        \addplot [name path=p1,thick,green] {-3*x-2.1};
        \addplot [name path=p2,thick,green] {-3*x+6.2};

        % find the intersection points of the black and green lines
        \path [
            name intersections={
                of=l1 and p1,
                by={A},
            },
        ];
        \path [
            name intersections={
                of=l1 and p2,
                by={B},
            },
        ];
        \path [
            name intersections={
                of=l2 and p2,
                by={C},
            },
        ];
        \path [
            name intersections={
                of=l2 and p1,
                by={H},
            },
        ];

        % create coordinate at origin
        \coordinate (O) at (0,0);

        % create invisible clip paths which are needed for the orange filling
        \path [name path=clippath1] (A) -- (H) -- (C) -- cycle;
        \path [name path=clippath2] (O) -- (C) -- (B) -- cycle;

        % draw the intersection points
            \pgfmathsetlengthmacro{\Radius}{2pt}
        \fill
            (A) circle (\Radius)
            (B) circle (\Radius)
            (C) circle (\Radius)
            (H) circle (\Radius)
        ;

        % label the intersection points
        \node [coordinate,label=below right:$O$] at (O) {};
        \node [coordinate,label=above right:$A$] at (A) {};
        \node [coordinate,label=above right:$B$] at (B) {};
        \node [coordinate,label=below right:$C$] at (C) {};
        \node [coordinate,label=below left:$H$] at (H) {};

        % fill the area between the intersection points on a lower layer
        % so the red function line doesn't have to be plotted twice
        \begin{pgfonlayer}{axis ticks}
            % left half
            \fill [
                orange,
                fill opacity=0.5,
                % (this is the TikZ equivalent to PGFPlots `fill between')
                intersection segments={
                    of=f and clippath1,
                    % (here we can draw -- in general -- an arbitrary path
                    %  between the path elements of intersection points.
                    %  Of course here we want to find the path that surrounds
                    %  the area that we want to fill.)
                    sequence={R1[reverse] -- L2},
                },
            ];
            % right half
            \fill [
                orange,
                fill opacity=0.5,
                intersection segments={
                    of=f and clippath2,
                    sequence={R{-2} -- L{-2}[reverse]},
                },
            ];
        \end{pgfonlayer}

        % draw the blue filling
        \addplot [
            fill=none,
        ] fill between [
            of=f and l1,
            split,
            every segment no 1/.style={
                fill=blue,
                fill opacity=0.5,
            },
        ];

%        % ---------------------------------------------------------------------
%        % for debugging purpose only
%        % ---------------------------------------------------------------------
%        % To find the right `sequence' you can play with the elements.
%        % Just start with one single element like `R1' to see what happens and
%        % then replace them until you found the right ones and connect them in
%        % the right order.
%        \draw [
%            blue,
%            very thin,
%            |->,
%            intersection segments={
%                of=f and clippath1,
%                sequence={
%                    % Because we know that the "green/black" line is needed
%                    % from the start to the first intersection point, for sure
%                    % we need `R1'.
%                    % And we also know that we need for the "red" line the part
%                    % from the first (not real) intersection point above (left)
%                    % of point A (crossing of the green and red line) to the
%                    % second intersection point (at point O)
%                    % (There is still some magic left why there is this "not
%                    %  real" intersection point ...)
%                    R1[reverse] -- L2
%%                    % so the reverse path is also fine, which can be done by
%%                    % reversing the "pathes" ...
%%                    R1 -- L2[reverse]
%%                    % ... or the elements of the pathes which offers another
%%                    % two possibilities to do this
%%                    L2 -- R1[reverse]
%%                    L2[reverse] -- R1
%%                    % Another possibility to avoid the `[reverse] you could
%%                    % simply reverse the path directly `clippath1' from
%%                    %     (A) -- (H) -- (C) -- cycle
%%                    % to
%%                    %     (C) -- (H) -- (A) -- cycle
%%                    % in the (above) definition of that path.
%%                    % Can you imagine how the right elements and sequence is then?
%%                    % (One tip: It is not as simple as `L2 -- R1')
%                },
%            },
%        ];
%        \draw [
%            blue,
%            very thin,
%            |->,
%            intersection segments={
%                of=f and clippath2,
%                sequence={
%%                    % try to find the right elements and orders here yourself
%                    R{-1}
%                },
%            },
%        ];
%        % ---------------------------------------------------------------------

    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code

3
  • Thanks a bunch! That's exactly what I needed! May I ask for a clarification? What does sequence do inside the intersection segments? In what way is it used in this example? Thanks a bunch again!
    – gjkf
    Jan 11 '18 at 13:23
  • 1
    I added some more explanatory text as well as some more code at the end of the code which might be a good start. Hopefully this helps. Jan 11 '18 at 17:51
  • Thanks a lot! That explains it perfectly! Once again thanks for your time!
    – gjkf
    Jan 12 '18 at 18:05

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.