3

I have taken information I learned from this question to make a 3D plot using pgfplots. I can plot the normal distribution on the x- and y-axes but I cannot figure out how to plot the corresponding ellipses on the xy plane, as shown here. (Overall, the z dimension is not necessary for my purpose.) The ellipses do not need to spread the full length of the tails from the normal distributions. Probably 2-3 standard deviation units is fine (assuming that can be done). My purpose for the figure is to illustrate a concept so it does not have to be super precise.

enter image description here

I tried using contour gnuplot but I do not need contour lines. I just need a smooth ellipse for each pair of normal distributions (blue and red pairs). In addition, the contours here are boxy. The code I tried is commented in the MWE below.

enter image description here

I tried using the scope environment from the tikz 3d library but I could not get the circle to move from the lower left corner of the plot. The code I tried is commented in the MWE.

enter image description here

Although I said the third dimension is unnecessary, I would also not mind seeing the result as a surface plot instead of ellipses to see if it might better suit my purpose. I have no idea where to begin. It would need to be colored to show the overlapping region, although a blend of the curve colors could be used instead of gray, perhaps.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usepgfplotslibrary{fillbetween}
    \pgfplotsset{
        compat=1.3,
        3dbaseplot/.style={
            width=12cm,
            height=7cm,
            axis lines*=left,
            axis on top,
            enlargelimits=upper,
            xlabel={Temperature},
            ylabel={Soil pH},
            ticks=none,
            no markers,
            samples=30,
            samples y=0,
            smooth,
        },
        /pgf/declare function={
            % normal distribution where \mean = mean and \stddev = sd}
      normal(\mean,\stddev)=1/(2*\stddev*sqrt(pi))*exp(-(x-\mean)^2/(2*\stddev^2));
        },
        /pgf/declare function={%
            bivar(\meanA,\stddevA,\meanB,\stddevB)=1/(2*pi*\stddevA*\stddevB) * exp(-((x-\meanA)^2/\stddevA^2 + (y-\meanB)^2/\stddevB^2))/2;
        },
    }
    \newcommand*\myaddplotX[4]{
        \addplot3+ [name path=#1,domain=#2-4*#3:#2+4*#3, color=#4] (x,4,{normal(#2,#3)});
    }
    \newcommand*\myaddplotY[4]{
        \addplot3+ [name path=#1,domain=#2-4*#3:#2+4*#3, color=#4] (1,x,{normal(#2,#3)});
    }

% Added to try the scope environment
\usetikzlibrary{3d}

\begin{document}

    \begin{tikzpicture}
        \begin{axis}[
            3dbaseplot,
            set layers,
        ]
          \myaddplotX{A}{2}{0.25}{blue}
          \myaddplotX{B}{2.2}{0.25}{red}
          \myaddplotY{C}{2.7}{0.15}{red}
          \myaddplotY{D}{3.2}{0.15}{blue}

%% I don't think contour is really what I want.
%     \addplot3+[contour gnuplot={,labels=false}, samples y=41,domain y=1:3, z filter/.code=\def\pgfmathresult{0}] {bivar(2,0.25,3.2,0.15)};

% This may be the path to nirvana but I can't figure out how to apply it properly.            
%         \begin{scope}[canvas is xy plane at z=0]
%            \draw (2,3.2) circle (0.5cm);
%         \end{scope}
            \pgfonlayer{pre main}
               \fill[gray!20, intersection segments={of=B and A}];
               \fill[gray!20, intersection segments={of=D and C}];
            \endpgfonlayer
        \end{axis}
    \end{tikzpicture}

\end{document}

1 Answer 1

5

You were thinking quite too complicated. Just draw the ellipses with the ellipse or circle (they are equivalent) command from TikZ. The rest should then be straight forward (hopefully) ...

Again: For more details have a look at the comments in the code.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usepgfplotslibrary{fillbetween}
    \pgfplotsset{
        % change `compat level to 1.11 or higher so you don't need to
        % prefix every tikz coordinate with `axis cs:'
        compat=1.11,
        3dbaseplot/.style={
            width=12cm,
            height=7cm,
            axis lines*=left,
            axis on top,
            enlargelimits=upper,
            xlabel={Temperature},
            ylabel={Soil pH},
            ticks=none,
            no markers,
            samples=30,
            samples y=0,
            smooth,
        },
        /pgf/declare function={
            % normal distribution where \mean = mean and \stddev = sd
            normal(\mean,\stddev)=1/(2*\stddev*sqrt(pi))*exp(-(x-\mean)^2/(2*\stddev^2));
        },
    }
    \newcommand*\myaddplotX[4]{
        \addplot3+ [name path=#1,domain=#2-4*#3:#2+4*#3,color=#4]
            (x,4,{normal(#2,#3)});
    }
    \newcommand*\myaddplotY[4]{
        \addplot3+ [name path=#1,domain=#2-4*#3:#2+4*#3, color=#4]
            (1,x,{normal(#2,#3)});
    }
\begin{document}

    \begin{tikzpicture}
        \begin{axis}[
            3dbaseplot,
            set layers,
        ]
            \myaddplotX{A}{2.0}{0.25}{blue}
            \myaddplotX{B}{2.2}{0.25}{red}
            \myaddplotY{C}{2.7}{0.15}{red}
            \myaddplotY{D}{3.2}{0.15}{blue}

            \pgfonlayer{pre main}
               \fill[gray!20, intersection segments={of=B and A}];
               \fill[gray!20, intersection segments={of=D and C}];
            \endpgfonlayer

            % -----------------------------------------------------------------
                % create a variable that stores the factor of the standard
                % deviations for that the ellipses should be drawn
                \pgfmathsetmacro{\factor}{2.5}
            % draw the ellipses
            \draw [blue,x radius=\factor*0.25,y radius=\factor*0.15]
                (2.0,3.2,0) ellipse;
            \draw [red,x radius=\factor*0.25,y radius=\factor*0.15]
                (2.2,2.7,0) ellipse;

            % again, to draw the fill we use the other layer
            \pgfonlayer{pre main}
                % repeat the drawing of the ellipses, but this time as clip pathes
                \clip [x radius=\factor*0.25,y radius=\factor*0.15]
                    (2.0,3.2,0) ellipse;
                \clip [x radius=\factor*0.25,y radius=\factor*0.15]
                    (2.2,2.7,0) ellipse;
                % then you can just fill the full xy plane and it does not need
                % to be adjusted any more
                \fill [gray!20]
                    (rel axis cs:0,0,0) -- (rel axis cs:1,0,0)
                        -- (rel axis cs:1,1,0) -- (rel axis cs:0,1,0) -- cycle;
            \endpgfonlayer
            % -----------------------------------------------------------------
        \end{axis}
    \end{tikzpicture}
\end{document}

image showing the result of above code

7
  • Is there a way to rotate the clipped gray area? I tried changing the angle of the plot with view/h=50 in the 3dbaseplot style. Everything rotated just fine except for the gray of the overlapping ellipses. Nov 13, 2016 at 20:48
  • Both overthinking and underthinking are the hallmarks (and bane) of my life. Thank you once again. Nov 13, 2016 at 20:53
  • Ok, I don't know what you wanted to say with your last comment, but I think you found the solution to the comment question yourself, right? Nov 13, 2016 at 21:11
  • No, I did not find a solution to my comment question. My statement comment was in reference to a statement a the start of your answer and an expression of appreciation. Nov 13, 2016 at 21:24
  • I am not sure what you mean with "rotate the clipped gray area". Would you mind asking a new question and again sketch what you want to achieve and add the stuff to the code that you have already tried (commented is also fine) -- as you did exemplary in this question? Nov 13, 2016 at 21:31

You must log in to answer this question.

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