5

I need to draw some plots with vertical lines from the x axis to the function. For example, I defined the gauss(x) function for the normal distribution and I drew this plot, with a vertical line from (1.96, 0) to (1,96, gauss(1.96)) and the corresponding simmetric line:

\documentclass{book}
  \usepackage{tikz}
  \usepackage{pgfplots} \pgfplotsset{compat=1.16}
  \pgfmathdeclarefunction{gauss}{3}{%
    \pgfmathparse{1/(#3*sqrt(2*pi))*exp(-((#1-#2)^2)/(2*#3^2))}
  }
  \usetikzlibrary{positioning}
  \usetikzlibrary{shapes}
  \usetikzlibrary{arrows}
  \usetikzlibrary{arrows.meta}
  \usetikzlibrary{decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[%
      domain=-4:4, samples=61, smooth,
      clip=false,
      enlargelimits=upper
    ]
    % normal distribution PDF
    \addplot [thick] {gauss(x,0,1)};
    % right vertical line
    \pgfmathparse{gauss(+1.96,0,1)};
    \pgfmathsetmacro\pgftempa\pgfmathresult;
    \node[coordinate] (a) at (axis cs:+1.96,\pgftempa) {};
    \draw (axis cs:+1.96,0) -- (a);
    % left vertial line
    \pgfmathparse{gauss(-1.96,0,1)};
    \pgfmathsetmacro\pgftempb\pgfmathresult;
    \node[coordinate] (b) at (axis cs:-1.96,\pgftempb) {};
    \draw (axis cs:-1.96,0) -- (b);
  \end{axis}
\end{tikzpicture}
\end{document}

(code above may contain some math errors as it's a MWE from a longer code, just ignore them)

I know, after searching on this forum, that I can't use gauss(x)directly after axis cs, but when I have to draw many lines the code becomes huge, and unreadable. Also, I'd like to avoid using many variables \pgftemp*.

Is there an easier way to evaluate a function which does not require three lines of code? For example, would it be possible to define a new command \evaluatefunction(x) and write axis cs: 1.96,\evaluatefunction(1.96) or \evaluatefunction{gauss(1.96,0,1)}? I already tried this but it does not work:

\newcommand{\evaluatefunction}[1]{%
  \pgfmathparse{#1};
  \pgfmathsetmacro\pgftempa\pgfmathresult;
}
\node[coordinate] (a) at (axis cs:+1.96,\evaluatefunction{gauss(1.96,0,1)}) {};

Compilation of this code does not end, and I have to stop it, so I can't even get an error log.

Thank you!

  • 2
    Welcome to TeX.SX! Can you please expand the code snippet that you have posted to a full minimal working example. A MWE should start with a \documentclass command, include any necessary packages and be as small as possible to demonstrate your problem. It is much easier to help you if we can start with some compilable code that illustrates your problem - at the moment we have to guess what packages etc you are using... – Andrew Jun 13 '18 at 15:14
  • Done, I also forgot to enclose the tikz code in axis environment – Taekwondavide Jun 13 '18 at 15:31
  • 1
    Why the extra parenthesis in \pgfmathparse{#1)};? Should be \pgfmathparse{#1};? – Bordaigorl Jun 13 '18 at 15:50
  • 1
    @Zarko Sorry, did you try what happens when you draw the vertical lines in the OP's MWE with the usual syntax, i.e. with \draw (+1.96,0) -- (1.96,{gauss(+1.96,0,1)}); ? Your code does not help in this regard, I am afraid. If you want so see benefits, just look at my code below, where one can just put \draw (1.96,0) -- (1.96,{gauss(1.96,0,1)}); and no mysterious shifts happen. – user121799 Jun 13 '18 at 17:25
  • 1
    @Zarko Maybe you want to have a look here. Ironically, it was never really clarified why \pgfmathdeclarefunction is "bad" but it (sort of) was agreed on that the syntax I was familiar with id "better". I guess it has to do with the fpu library. – user121799 Jun 13 '18 at 17:38
4

I am not so much familiar with the way you declare a function. However, if I use the way I am familiar with, there is no problem.

  \documentclass{book}
  \usepackage{tikz}
  \usepackage{pgfplots} 
  \pgfplotsset{compat=1.16}
  \tikzset{declare function={gauss(\x,\y,\z)=
  1/(\z*sqrt(2*pi))*exp(-((\x-\y)^2)/(2*\z^2));}}
  \usetikzlibrary{positioning}
  \usetikzlibrary{shapes}
  \usetikzlibrary{arrows}
  \usetikzlibrary{arrows.meta}
  \usetikzlibrary{decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[%
      domain=-4:4, samples=61, smooth,
      clip=false,
      enlargelimits=upper
    ]
    % normal distribution PDF
    \addplot [thick] {gauss(x,0,1)};
    \draw (1.96,0) -- (1.96,{gauss(1.96,0,1)});
    \draw (-1.96,0) -- (-1.96,{gauss(1.96,0,1)});
  \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

The same result can be obtained with an even more pgfplots like notation:

  \documentclass{book}
  \usepackage{tikz}
  \usepackage{pgfplots} 
  \pgfplotsset{compat=1.16}
  \usetikzlibrary{positioning}
  \usetikzlibrary{shapes}
  \usetikzlibrary{arrows}
  \usetikzlibrary{arrows.meta}
  \usetikzlibrary{decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[declare function={gauss(\x,\y,\z)=
  1/(\z*sqrt(2*pi))*exp(-((\x-\y)^2)/(2*\z^2));},%
      domain=-4:4, samples=61, smooth,
      clip=false,
      enlargelimits=upper
    ]
    % normal distribution PDF
    \addplot [thick] {gauss(x,0,1)};
    \draw (1.96,0) -- (1.96,{gauss(1.96,0,1)});
    \draw (-1.96,0) -- (-1.96,{gauss(1.96,0,1)});
  \end{axis}
\end{tikzpicture}
\end{document}

On the other hand, \pgfmathdeclarefunction cannot be found in the pgfplots manual. However, on p. 544 the manual warns us that it automatically switches on fpu. This might be where be big overall and the small relative shifts come from, but I am not sure.

  • Thank you! This should be good for me, I'm trying to understand the difference between the two ways of declaring functions before accepting the answer – Taekwondavide Jun 13 '18 at 17:26
  • @Taekwondavide The difference is that declare function can be found in the pgfplots manual, meaning that it is fully supported, whereas \pgfmathdeclarefunction can't be found there. See page 544 of the pgfplots manual. – user121799 Jun 13 '18 at 17:29
  • 1
    @Taekwondavide See here for an earlier discussion of the same issues... I guess one may now delve into the codes of TikZ and pgfplots or just accept as an empirical fact that the declare function syntax is better... – user121799 Jun 13 '18 at 17:40
  • 1
    I take a better look to TikZ manual, looks like \pgfmathparse loads the mathematical engine of PGF in TikZ, while your solution is native PGF. I guess that I would have had to use \pgfmathparse only if I hadn't used pgfplot package too. – Taekwondavide Jun 13 '18 at 17:51
  • 1
    @Taekwondavide \tikzset{declare function={gauss(\x,\y,\z)= 1/(\z*sqrt(2*pi))*exp(-((\x-\y)^2)/(2*\z^2));}} works for both TikZ and pgfplots without problems (for me) so far. – user121799 Jun 13 '18 at 17:56
2

If you want to draw vertical lines from y = 0 to the function value there is an even simpler way to achieve this using ycomb. Then, starting with marmot's answer this reduces to following.

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \pgfplotsset{
        /pgf/declare function={
            gauss(\x,\y,\z) = 1/(\z*sqrt(2*pi))*exp(-((\x-\y)^2)/(2*\z^2));
            mygauss = gauss(\x,0,1);
        }
    }
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        domain=-4:4,
        samples=61,
        smooth,
        enlargelimits=upper,
    ]
        \addplot [thick] {mygauss};
        % ----------------------------------
        % added/new stuff
        \addplot [
            ycomb,
            samples at={-1.96,1.96},
        ] {mygauss};
        % ----------------------------------
    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code

  • Thank you! In many cases I still need to create a \node[coordinate] for other purposes, as in marmot's solution, but in all other cases I'll use this one – Taekwondavide Jun 15 '18 at 14:51
  • Neither can I find a node/coordinate in marmot's answer, nor do I see a problem to add them to my answer ... – Stefan Pinnow Jun 15 '18 at 18:52
  • Yes, sorry, I misspoke. I mean that this is a great solution, which let me avoid to create many unnecessary nodes as in my original code, however In some situations I did not explained here I still need to create the node and use \draw, otherwise I'll definitely use ycomb – Taekwondavide Jun 18 '18 at 0:47

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.