Plotting a function with very small values in TikZ

I want to plot a function in TikZ, G4 of this paper (p5). I tried with and without pgfplots, and also by gnuplot call. MWE are below.

With pgfplots, compilation throws the error ! Dimension too large. <recently read> \pgf@yy l.54 \end{axis} whereas the TikZ-only attempt plots instead f(x) = 0.

The function should look like this

This function involves the exponential of a small number multiplied by other small numbers. I suspect that raising the precision of the calculation is enough to fix this. I've seen some examples with precision=<number> but I don't know how to do that for a plotted function and not a number to be printed.

This answer shows a gnuplot call for a plot with a very small y-scale, but I'd like to not depend on external programs. Plus I don't know if my macro-reliant definition of the function is compatible with gnuplot. For now I tried changing the macros for explicit numbers, but got an error again, ! Dimension too large. <recently read> \pgf@yy l.43 \end{axis}

Is there a solution for this? I'm out of my depth.

MWE (TikZ only):

\documentclass[tikz]{standalone}

\usepackage{siunitx}

\begin{document}

\colorlet{colorline1}{red}

\def\xmax{360}
\def\ymax{0.02}

\tikzset{every picture/.style={x = 0.025cm,y = 60cm}}

\begin{tikzpicture}
\draw[->] (0,0) -- (0,\ymax) node [left] {\small $G_i^{4,5}$};
\draw[->] (0,0) -- (\xmax,0) node [below] {\small $\theta_{ijk}$/\si{\degree}};

\node[left] at (0,0) {\small $0$};

\def\coefValT{0.8}

% Cutoff function fc of Rij and Rik, with both distances fixed at 0.8*Rc
\pgfmathsetmacro{\fcOfijNikValT}{0.5*cos( \coefValT * pi r) + 0.5}

\def\lambdaVal{1}
\def\etaVal{0.2}
\def\zetaVal{1}

\def\Rc{10}
\pgfmathsetmacro{\RijNikValT}{\coefValT*\Rc}

% Function to plot begins here
\begin{scope}[thick,colorline1]
\def\fcOfijNik{\fcOfijNikValT}
\draw[domain=0:\xmax,variable=\x,samples=100,smooth] plot (\x,{2^(1-\zetaVal)*(1 + \lambdaVal*cos(\x))^\zetaVal*exp( -\etaVal*( 2*(\RijNikValT)^2 +
% Calculation for Rjk^2:
2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x)
))* % these two parenthesis close the one opened by \etaVal*, and by exp(
\fcOfijNik^2*(
% Calculation for fc(Rjk)
0.5*(cos( pi*
% Calculation for Rjk:
(%opens quotient multiplied by pi
sqrt( 2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x) )
/\Rc)%ends quotient multiplied by pi
)% closes parenth opened by cos
)% closes parenth opened to the left of cos
+0.5)%closes parenth opened before of 0.5*(cos
});
\end{scope}
\end{tikzpicture}
\end{document}


MWE (TikZ+pgfplots):

\documentclass[tikz]{standalone}

\usepackage{pgfplots}

\usepackage{siunitx}

\begin{document}

\colorlet{colorline1}{red}

\def\xmax{360}
\def\ymax{0.02}

\tikzset{every picture/.style={x = 0.025cm,y = 60cm}}

\begin{tikzpicture}
\draw[->] (0,0) -- (0,\ymax) node [left] {\small $G_i^{4,5}$};
\draw[->] (0,0) -- (\xmax,0) node [below] {\small $\theta_{ijk}$/\si{\degree}};

\node[left] at (0,0) {\small $0$};

\def\coefValT{0.8}

% Cutoff function fc of Rij and Rik, with both distances fixed at 0.8*Rc
\pgfmathsetmacro{\fcOfijNikValT}{0.5*cos( \coefValT * pi r) + 0.5}

\def\lambdaVal{1}
\def\etaVal{0.2}
\def\zetaVal{1}

\def\Rc{10}
\pgfmathsetmacro{\RijNikValT}{\coefValT*\Rc}

%\begin{axis}[range=0:360,restrict y to domain=0:0.02]
\begin{axis}[xmin=0, xmax = 360,ymin = 0, ymax = 0.02]
% Function to plot begins here
\begin{scope}[thick,colorline1]
\def\fcOfijNik{\fcOfijNikValT}
\addplot {2^(1-\zetaVal)*(1 + \lambdaVal*cos(\x))^\zetaVal*exp( -\etaVal*( 2*(\RijNikValT)^2 +
% Calculation for Rjk^2:
2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x)
))* % these two parenthesis close the one opened by \etaVal*, and by exp(
\fcOfijNik^2*(
% Calculation for fc(Rjk)
0.5*(cos( pi*(
% Calculation for Rjk:
sqrt( 2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x) )
/\Rc)%ends quotient multiplied by pi
)% closes parenth opened by cos
)% closes parenth opened to the left of cos
+0.5)%closes parenth opened before of 0.5*(cos
};
\end{scope}
\end{axis}

\end{tikzpicture}
\end{document}


MWE (TikZ+pgfplots+gnuplot):

\documentclass[tikz]{standalone}

\usepackage{pgfplots}

\usepackage{siunitx}

\begin{document}

\colorlet{colorline1}{red}

\def\xmax{360}
\def\ymax{0.02}

\tikzset{every picture/.style={x = 0.025cm,y = 60cm}}

\begin{tikzpicture}
\draw[->] (0,0) -- (0,\ymax) node [left] {\small $G_i^{4,5}$};
\draw[->] (0,0) -- (\xmax,0) node [below] {\small $\theta_{ijk}$/\si{\degree}};

\node[left] at (0,0) {\small $0$};

%\begin{axis}[range=0:360,restrict y to domain=0:0.02]
\begin{axis}[xmin=0, xmax = 360,ymin = 0, ymax = 0.02]
% Function to plot begins here
\begin{scope}[thick,colorline1]
\def\fcOfijNik{\fcOfijNikValT}

\addplot[no marks,blue,line width=1pt] gnuplot [domain=0:360,samples=200] {2^(1-1)*(1 + 1*cos(x))^1.1*exp( -0.2*( 2*(8)^2 +
% Calculation for Rjk^2:
2*(8)^2 - 2*(8)^2*cos(x)
))* % these two parenthesis close the one opened by \etaVal*, and by exp(
8^2*(
% Calculation for fc(Rjk)
0.5*(cos( pi*(
% Calculation for Rjk:
sqrt( 2*(8)^2 - 2*(8)^2*cos(x) )
/10)%ends quotient multiplied by pi
)% closes parenth opened by cos
)% closes parenth opened to the left of cos
+0.5)%closes parenth opened before of 0.5*(cos
};
\end{scope}
\end{axis}

\end{tikzpicture}
\end{document}

• You do not need to know any PGFplots to use it. PGFplots is on top of TikZ. Do youself a favour and look at an example. Slap your plot in between \begin{axis} and \end{axis} - that is it. Now different googleable options will let you get everything you desire - women, money, ... Commented Jan 1, 2021 at 23:59
• @hpekristiansen Thanks. I've revised the question with the two approaches. Neither work. Commented Jan 2, 2021 at 0:20

Just to confirm hpekristiansen's comment: pgfplots does work. However, first of all you need to do away with

\tikzset{every picture/.style={x = 0.025cm,y = 60cm}}


and also with

\draw[->] (0,0) -- (0,\ymax) node [left] {\small $G_i^{4,5}$};
\draw[->] (0,0) -- (\xmax,0) node [below] {\small $\theta_{ijk}$/\si{\degree}};


which become the ylabel and xlabel, respectively. After this, your code works.

\documentclass[tikz]{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\usepackage{siunitx}

\begin{document}

\colorlet{colorline1}{red}

\def\xmax{360}
\def\ymax{0.02}

%\tikzset{every picture/.style={x = 0.025cm,y = 60cm}}

\begin{tikzpicture}
% \draw[->] (0,0) -- (0,\ymax) node [left] {\small $G_i^{4,5}$};
% \draw[->] (0,0) -- (\xmax,0) node [below] {\small $\theta_{ijk}$/\si{\degree}};
%
% \node[left] at (0,0) {\small $0$};

\def\coefValT{0.8}

% Cutoff function fc of Rij and Rik, with both distances fixed at 0.8*Rc
\pgfmathsetmacro{\fcOfijNikValT}{0.5*cos( \coefValT * pi r) + 0.5}

\def\lambdaVal{1}
\def\etaVal{0.2}
\def\zetaVal{1}

\def\Rc{10}
\pgfmathsetmacro{\RijNikValT}{\coefValT*\Rc}

%\begin{axis}[range=0:360,restrict y to domain=0:0.02]
\begin{axis}[xmin=0, xmax = 360,ymin = 0,
ylabel={\small $G_i^{4,5}$},xlabel={\small $\theta_{ijk}$/\si{\degree}}]
% Function to plot begins here
\begin{scope}[thick,colorline1]
\def\fcOfijNik{\fcOfijNikValT}
{2^(1-\zetaVal)*(1 + \lambdaVal*cos(\x))^\zetaVal*exp( -\etaVal*( 2*(\RijNikValT)^2 +
% Calculation for Rjk^2:
2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x)
))* % these two parenthesis close the one opened by \etaVal*, and by exp(
\fcOfijNik^2*(
% Calculation for fc(Rjk)
0.5*(cos( pi*(
% Calculation for Rjk:
sqrt( 2*(\RijNikValT)^2 - 2*(\RijNikValT)^2*cos(\x) )
/\Rc)%ends quotient multiplied by pi
)% closes parenth opened by cos
)% closes parenth opened to the left of cos
+0.5)%closes parenth opened before of 0.5*(cos
};
\end{scope}
\end{axis}

\end{tikzpicture}
\end{document}


This is still a very rusty code, and the normalization is different from what you expect, but this is just to substantiate that it works in principle.

If you want a cleaner code then you probably first want to rephrase the question such that others have a better feeling for what's going on.

• It works! My only question left is whether the code could be made clearer. For example, in the myriad of parenthesis. \pgfmathdeclarefunction could be used to define the function elsewhere, but that still leaves the myriad of parenthesis. My best idea was to comment the purpose of each. Adding [or { caused errors. Commented Jan 2, 2021 at 1:16
• @Imp54 You can use the declare function key, e.g. declare function={f(\x,\y)=\x*\x*cos(\y);a0=7;}, i.e. it works for functions and also for constants like a0. You have to be a bit careful to declare functions only locally, e.g. in a tikzpicture, because redeclaring them is more efforts.
– user232027
Commented Jan 2, 2021 at 1:19
• So is breaking down the function into smaller functions whenever possible is the best that can be done for this? Commented Jan 2, 2021 at 1:21
• @Imp54 For readability, probably yes. For speed: not sure. What I want to say is that if you define constants with declare function={a0=7;} this is arguably much more readable but it may take slightly longer to compile. Yet in 2D plots this should hardly matter.
– user232027
Commented Jan 2, 2021 at 1:30