3

I have to connect three plots. These are a normal and two log-normal distributions (pdfs). For simplicity, here I am showing only two.

The code is:

\documentclass{article}
\usepackage[british]{babel}
\usepackage{pgfplots,tikz}

\usepgfplotslibrary{fillbetween}

\begin{document}

\newcommand\normal[2]{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))} % Normal function, parameters mu and sigma
\newcommand\lognormal[2]{1/(x*#2*sqrt(2*pi))*exp(-((ln(x)-#1)^2)/(2*#2^2))} % Log-normal function, parameters mu and sigma

\begin{tikzpicture}
\begin{axis}[
samples=200,
smooth,
ytick=\empty,
xtick=\empty,
xmin=0,
xmax=15,
axis lines=none,
]
% Plot 1
\addplot[name path=A,thick,domain=0:10] {\normal{5}{1.4}};
\addplot+[name path=B,domain=0:15,samples=2,draw=none,mark=none] {0};
\addplot[blue] fill between[of=B and A,soft clip={domain=0:4}];
% Plot 2
\addplot[name path=C,thick,domain=0.5:15] {\lognormal{2}{0.3}};         
\addplot[red] fill between[of=C and B,soft clip={domain=5:15}];
% Nodes
\fill (40,220) node[left]{A} circle[radius=2pt];
\fill (50,115) node[left]{B} circle[radius=2pt];
\fill (1,0) node[above]{0} circle[radius=2pt];
\end{axis}
\end{tikzpicture}   

\end{document}

The result so far:

enter image description here

I want to connect the graphs so that points A and B coincide, while keeping point 0 as pivot. Additionally, the fill between must also be scaled, in order to make the whole scaling coherent.

Doing this by hand is extremely painful, requiring me to move many variables at the same time. I am thinking of doing this by scaling the graphs vertically and horizontally. Something like:

\addplot[xscale=0.8,yscale=1.3,...] ...

But I'm not sure this is possible. If not, any other way to do this in a simple way?

  • Should the asymptotes of the graphs all be the same/fixed in value? – Dai Bowen Sep 23 '16 at 15:48
  • Updated question. – luchonacho Sep 23 '16 at 16:13
  • So you don't care if the x\to\infty limits are different – Dai Bowen Sep 23 '16 at 16:20
  • I think they cannot be the same if you fix x=0. – luchonacho Sep 23 '16 at 16:26
  • You can calculate your xscale and yscale factor from the coordinates of your A and B node. So for \addplot[xscale=0.8,yscale=220/115,...] points A and B would overlap. Or do you mean something else? – Roald Sep 23 '16 at 16:31
6
+50

Unfortunately you didn't specify

  • if point A should be "moved" to point B or the other way round or
  • where the coordinates A and B are coming from,

so I think just scaling one or both of the plots is a non-optimal solution. This impression is hardened, because you have specified the coordinates A and B "by hand", which I think also took you quite some time to "hit the plots".


Here I present a code which "automatically" finds the intersection of the two plots. With that coordinate it is then easy to fill the corresponding parts of the curves. Of course this can also quite easily be extended to a third curve.

With that you should easily be able by changing the parameters \mu and/or \sigma of one or both plots to move the intersection point where you want it to be.

For details how it works, please have a look at the comments in the code.

% used PGFPlots v1.14
\documentclass[border=2pt]{standalone}
\usepackage{pgfplots}
    \usepgfplotslibrary{fillbetween}
    \pgfplotsset{
        % use compat level so that coordinates are interpreted as `axis cs'
        % if no other coordinate system is given
        compat=1.11,
        %
        % declare functions in tikz rather than as command
        % (using `compat=1.12' or higher would allow to calculate the
        %  function using lua, which should be much faster.
        %  Of course then `lualatex' has to be used.)
        /pgf/declare function={
            % Normal function with parameters mu and sigma
            normal(\x,\mu,\sigma)
                = 1/(\sigma*sqrt(2*pi))*exp(-((\x-\mu)^2)/(2*\sigma^2));
            % Log-normal function with parameters mu and sigma
            lognormal(\x,\mu,\sigma)
                = 1/(x*\sigma*sqrt(2*pi))*exp(-((ln(x)-\mu)^2)/(2*\sigma^2));
        },
    }
\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
            xmin=0,
            xmax=15,
            domain=0:15,
            samples=200,
            smooth,
            ytick=\empty,
            xtick=\empty,
            axis lines=none,
            % avoid clipping so the "0" label is (fully) shown
            clip=false,
        ]

        % (draw) plots and name them
            % base line
            \addplot [
                samples=2,
                draw=none,
                name path=base line,
                    ] {0};
            % normal plot
            \addplot [
                thick,
                name path=normal plot ,
                    ] {normal(x,5,1.4)};
            % lognormal plot
            \addplot [
                thick,
                name path=lognormal plot,
                    ] {lognormal(x,2,0.3)};

        % find intersection of the two plots and name it "A"
            \path [
                name intersections={
                    of=normal plot and lognormal plot,
                    by=A,
                },
            ];

%           % draw a vertical line at the intersection point
%            \draw [green,name path=vertical line]
%                (A |- 0,\pgfkeysvalueof{/pgfplots/ymin})
%                -- (A |- 0,\pgfkeysvalueof{/pgfplots/ymax});

        % draw the fill between plots
            \addplot [blue!50] fill between [
                of=base line and normal plot,
                soft clip={
                    (\pgfkeysvalueof{/pgfplots/xmin},\pgfkeysvalueof{/pgfplots/ymin})
                        rectangle
                     (A |- 0,\pgfkeysvalueof{/pgfplots/ymax})
                },
            ];
            \addplot [red!50]  fill between [
                of=base line and lognormal plot,
                soft clip={
                     (A |- 0,\pgfkeysvalueof{/pgfplots/ymin})
                        rectangle
                    (\pgfkeysvalueof{/pgfplots/xmax},\pgfkeysvalueof{/pgfplots/ymax})
                },
            ];

        % nodes
            \fill (0,0) circle (2pt) node [above] {0};
            \fill (A)   circle (2pt) node [above] {A};
        \end{axis}
    \end{tikzpicture}
\end{document}

image showing the result of above code

3

I guess this was your old result?:

Triangular fill

I could not really figure out what was wrong. But you can do a simple work around by not clipping the path and redraw the first graph over it again.

MWE

\documentclass{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}

\newcommand\normal[2]{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))} % Normal function, parameters mu and sigma
\newcommand\lognormal[2]{1/(x*#2*sqrt(2*pi))*exp(-((ln(x)-#1)^2)/(2*#2^2))} % Log-normal function, parameters mu and sigma

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
            samples=200,
            smooth,
            ytick=\empty,
            xtick=\empty,
            xmin=0,
            xmax=15,
            axis lines=none,
            clip=false,
            ]
        % Nodes
        \fill (40,220) node[left]{A} circle[radius=2pt];
        \fill (1,0) node[above]{0} circle[radius=2pt];

        % Plot 1
        \addplot [name path=A,thick,domain=0:10] {\normal{5}{1.4}};
        \addplot+[name path=B,domain=0:15,samples=2,draw=none,mark=none] {0};
        \addplot[blue] fill between[of=B and A, soft clip={domain=0:4}];

        % Plot 2
        \addplot[name path=C,xscale=0.8,yscale=220/115,thick, domain=0:15]  {\lognormal{2}{0.3}};       
        \addplot[red] fill between[of=C and B];

        % Plot 1
        \addplot[thick,domain=0:10] {\normal{5}{1.4}};
        \addplot[blue] fill between[of=B and A,soft clip={domain=0:4}];
        \end{axis}
    \end{tikzpicture}   
\end{document}

Result

enter image description here


Edit: 6 October 2016, 23:17

I incorporated the changes suggested by Stefan.

MWE

\documentclass{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}

\newcommand\normal[2]{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))} % Normal function, parameters mu and sigma
\newcommand\lognormal[2]{1/(x*#2*sqrt(2*pi))*exp(-((ln(x)-#1)^2)/(2*#2^2))} % Log-normal function, parameters mu and sigma

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
            samples=200,
            smooth,
            ytick=\empty,
            xtick=\empty,
            xmin=0,
            xmax=15,
            ymax=0.4,
            axis lines=none,
            clip=false,
            ]
        % Nodes
        \fill (axis cs: 4,0.22) node[left]{A} circle[radius=2pt];
        \fill (axis cs: 0,0) node[above]{0} circle[radius=2pt];

        % Plot 1
        \addplot [name path=A,thick,domain=0:10] {\normal{5}{1.4}};
        \addplot+[name path=B,domain=0:15,samples=2,draw=none,mark=none] {0};
        \addplot[blue] fill between[of=B and A, soft clip={domain=0:4}];

        % Plot 2
        \addplot[name path=C,xscale=0.8,yscale=220/115,thick, domain=0:15]  {\lognormal{2}{0.3}};       
        \addplot[red] fill between[of=C and B, soft clip={domain=4:15}];
        \end{axis}
    \end{tikzpicture}   
\end{document}

Result

Stefan's suggestions

  • 1
    The "strange" result of the first pictures results from the plot going beyond the ymax limit, which isn't also scaling (you can make this visible by commenting the line axis lines=none). By adding e.g. ymax=0.4 you get the desired result when you reorder the "blue" fill between after the "red" fill between. (The "red" fill between hasn't given any domain so it fills the complete curve.) – Stefan Pinnow Oct 6 '16 at 18:50

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.