I would like to print the probability density function two truncated normal distributions. The functions look like this (image source):
My try
\documentclass[varwidth=true, border=2pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\def\cdf(#1){0.5*(1+(erf((#1)/(sqrt(2)))))}%
\def\phi(#1){(1/sqrt(2*pi))*exp(-0.5*#1^2)}%
% trunkated gauss(x, mu, sigma, a, b)
\def\tgauss(#1)(#2)(#3)(#4)(#5){((1/#3)*phi((#1-#2)/#3))/(cdf((#5-#2)/#3) - cdf((#4-#2)/#3))}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
legend pos=north west,
axis x line=middle,
axis y line=middle,
grid = major,
width=8cm,
height=6cm,
grid style={dashed, gray!30},
xmin= 0.0, % start the diagram at this x-coordinate
xmax= 1.0, % end the diagram at this x-coordinate
ymin= 0, % start the diagram at this y-coordinate
%ymax= 1.6, % end the diagram at this y-coordinate
x label style={at={(axis description cs:0.5,0)},anchor=north},
y label style={at={(axis description cs:0,.5)},rotate=90,anchor=south},
xlabel=$q$,
ylabel=$p$,
tick align=outside,
enlargelimits=false]
\addplot[domain=0:5.2,smooth,red!70!black,very thick,samples=400] {\tgauss(x)(0.5)(0.3)(1)(1)};
\end{axis}
\end{tikzpicture}
\end{document}
gives
! Package PGF Math Error: Unknown function `phi' (in '((1/0.3)*phi((x-0.5)/0.3)
)/(cdf((1-0.5)/0.3) - cdf((1-0.5)/0.3))').
See the PGF Math package documentation for explanation.
Type H <return> for immediate help.
...
l.34 ...samples=400] {\tgauss(x)(0.5)(0.3)(1)(1)};
I could, of course, simply inline it. However, I'm pretty sure there is a better option. (I don't care how exactly it is plotted)
Another try
\documentclass[varwidth=true, border=2pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\makeatletter
\pgfmathdeclarefunction{erf}{1}{%
\begingroup
\pgfmathparse{#1 > 0 ? 1 : -1}%
\edef\sign{\pgfmathresult}%
\pgfmathparse{abs(#1)}%
\edef\x{\pgfmathresult}%
\pgfmathparse{1/(1+0.3275911*\x)}%
\edef\t{\pgfmathresult}%
\pgfmathparse{%
1 - (((((1.061405429*\t -1.453152027)*\t) + 1.421413741)*\t
-0.284496736)*\t + 0.254829592)*\t*exp(-(\x*\x))}%
\edef\y{\pgfmathresult}%
\pgfmathparse{(\sign)*\y}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup
}
\makeatother
\pgfmathdeclarefunction{cdf}{1}{%
\pgfmathparse{0.5*(1+(erf((#1)/(sqrt(2)))))}%
}
\pgfmathdeclarefunction{phi}{1}{%
\pgfmathparse{(1/sqrt(2*pi))*exp(-0.5*#1^2)}%
}
% trunkated gauss(x, mu, sigma, a, b)
\pgfmathdeclarefunction{tgauss}{5}{%
\pgfmathparse{((1/#3)*phi((#1-#2)/#3))/(cdf((#5-#2)/#3) - cdf((#4-#2)/#3))}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
legend pos=north west,
axis x line=middle,
axis y line=middle,
grid = major,
width=8cm,
height=6cm,
grid style={dashed, gray!30},
xmin= 0.0, % start the diagram at this x-coordinate
xmax= 1.0, % end the diagram at this x-coordinate
ymin= 0, % start the diagram at this y-coordinate
%ymax= 1.6, % end the diagram at this y-coordinate
x label style={at={(axis description cs:0.5,0)},anchor=north},
y label style={at={(axis description cs:0,.5)},rotate=90,anchor=south},
xlabel=$q$,
ylabel=$p$,
tick align=outside,
enlargelimits=false]
\addplot[domain=0:1,smooth,red!70!black,very thick,samples=400] {tgauss(x, 0.5,0.3,1,1)};
\end{axis}
\end{tikzpicture}
\end{document}
based on this answer. However, it gives
NOTE: coordinate (1Y1.00001369e0],4Y0.0e0]) has been dropped
because it is unbounded (in y). (see also unbounded coords=jump).
I have no idea what that means and how to fix it.
Best Answer
Because
gnuplot
knows the error function (erf
), you can use theraw gnuplot
function of PGFPlots to do what you want. Because I don't know the truncated normal distribution function, I am not 100% sure the implementation is right, but at least it seems I can reproduce the given figure from the Wiki article you posted in the question (see below).For more details on how the solution works, have a look at the comments in the code.
Edit: Thoughts about how the
tpdfn
really should be definedThinking again about the discussion (in the comments below the question) where the
tpdfn
function is defined and if it must be the same aspdfn
I came to the conclusion that forpdfn
the area under the curve is 1. Assuming that is the case also fortpdfn
then my previous solution would be wrong in general.Then it is a "combination" of restricting the calculation to the domain [a, b] and using the
tpdfn
function. To support this view I have added two more plots which can be created from the one given source below successively.For the left image I (just) shifted the "black" curve to
mu = 0
(which then is the gray dashed curve). If I am right then it now must be, the blue shaded area must be of the same size as the red shaded area, because that is exactly the part we "truncated" on the left side of the correspondingpdfn
function.Having a look at the areas that could be true.
For the right image I in addition to the left image I truncated also "the right side" of the
pdfn
function. Here also I think, that (the sum of) the blue areas could be of the same size as the red area.Here again: For more details on how it works, have a look at the comments in the code.