I had plotted using \usepackage{pgfplots} the Lorentzian's function

f(x,\epsilon)=\frac{1}{\pi} \frac{\epsilon}{(x-x_0)^{2}+\epsilon^2}}

when $\epsilon=0.5$ and $x_0=0$ i.e. $f(x,0.5) = \frac1{\pi} \cdot \frac{0.5}{(x - 0)^2 + 0.25}$.

In this case I have the curvature of the graph $f$ at the top of the $x_0=0$ is evident. See red big arrow.

enter image description here

But when I plot the function $g(x,0.5) = \frac1{\pi} \cdot \frac{0.5}{(x - 0)^2 + 0.25}$, the curvature at the top of the point $x_0=0$ is not visible. Infact I have a truncated function as shown in the figure below

enter image description here

Why is there this problem?

Here my MWE:

\documentclass{article}
    \usepackage{tikz,amsmath,xcolor}
    \usetikzlibrary{patterns}
    \usepackage{pgfplots}
    \usetikzlibrary{spy}
    \begin{document}
    \begin{tikzpicture}[spy using outlines={circle=.5cm, magnification=3, size=.5cm, connect spies}]
    \tikzset{
        hatch distance/.store in=\hatchdistance,
        hatch distance=10pt,
        hatch thickness/.store in=\hatchthickness,
        hatch thickness=2pt
    }

    \makeatletter
    \pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{flexible hatch}
    {\pgfqpoint{0pt}{0pt}}
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
    \makeatother

    \begin{axis}[
        xmin=-4,xmax=4,
        xlabel={},
        ymin=0,ymax=3,
        axis on top,
        legend style={legend cell align=right,legend plot pos=right}] 
       %\begin{scope}
    %\spy[green!70!black,size=2cm] on (2.5,1) in node [fill=white] at (8,2);
       %\end{scope}
    \addplot[color=gray,domain=-4:4,samples=100] {(1/pi)*(0.1/((x)^2+0.01)};

       \addplot+[color=gray,mark=none,
        domain=-4:4,
        samples=100,
        pattern=flexible hatch,
        area legend,
        pattern color=orange]{(1/pi)*(0.1/((x)^2+0.01)} \closedcycle;


    \end{axis}
\end{tikzpicture}
\end{document}

With samples=101 the result is with a tip and not with a curvature:

enter image description here

  • 3
    Use an odd number of sample points, such as samples=101? – Ruixi Zhang Aug 19 at 19:54
  • I tried with samples=101 but the result is with a tip and not with a curvature. – Sebastiano Aug 19 at 20:11
  • 1
    What is the reason of my downvote? – Sebastiano Aug 19 at 20:18
up vote 11 down vote accepted

As samcarter has already shown in her answer the key is to increase samples. But instead of increasing it to 10000 I suggest to increase it only to 1001 and also use the smooth key, which gives almost the same result and also works for PDFLaTeX (and not only with LuaLaTeX. Otherwise one has to increase TeX's "memory").

Using only smooth with 101 samples still shows a spike, as now can be seen in Ruixi Zhang's answer.

Ruixi and I use an uneven number of samples, because this ensures that there is also a sample point "in the middle" of the domain, i.e. in this case with a domain of -4 to 4 at 0, where we find the maximum value of the given function.

(Please note that I also heavily simplified your code. For example you need only one \addplot command to achieve what you want.)

Edit

An even better approach is to reformulate the function using non-linear spacing as Max has shown in his answer. Here I edited his code so that it also works for \xz <> 0 and also allows to have unsymmetrical lower and upper bounds of the domain (lb and ub instead of just b).

The non-linear spacing approach is always a good idea if you otherwise need to increase the samples to a "high" value because there is a rather quick change in the slope/steepness of the function (as in your case -- or the other cases that link to each other that are stated in comments of my codes).

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{
        patterns,
        spy,
    }
    \tikzset{
        hatch distance/.store in=\hatchdistance,
        hatch distance=10pt,
        hatch thickness/.store in=\hatchthickness,
        hatch thickness=2pt,
    }

    \makeatletter
    \pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{flexible hatch}
    {\pgfqpoint{0pt}{0pt}}
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}
    {\pgfpoint{\hatchdistance-2pt}{\hatchdistance-2pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
    \makeatother
\begin{document}
\begin{tikzpicture}[
    % -------------------------------------------------------------------------
    % declare functions
    declare function={
        % Lorentzian function
        L(\x,\xz,\ep) = (1/pi) * (\ep/((\x-\xz)^2 + (\ep)^2));
        % state lower and upper boundaries
        lb = -4;
        ub = 4;
        % -----------------------------------------------------------------
        %%% non-linear spacing:
        %%% adapted from <https://tex.stackexchange.com/a/443731/95441>
        % "non-linearity factor"
        a = 1;
        % function to use for the nonlinear spacing
        Y(\x,\a) = exp(\a*\x);
        % rescale to former limits (domain=lb:ub) taking into account `\xz',
        % where sample points should be densest
        X(\x,\a,\xz) =
            + (\x >= \xz) * ( (Y(\x,\a)  - Y(\xz,\a))/(Y(ub,\a)   - Y(\xz,\a)) * (ub - \xz) + \xz )
            + (\x < \xz)  * ( (Y(\x,-\a) - Y(lb,-\a))/(Y(\xz,-\a) - Y(lb,-\a)) * (\xz - lb) + lb )
        ;
        % -----------------------------------------------------------------
        % create simplified functions when `xz' and `ep' are known/fix
        xz = 0;
        ep = 0.1;
        myL(\x) = L(\x,xz,ep);
        myX(\x) = X(\x,a,xz);
    },
    % -------------------------------------------------------------------------
    % (only needed for the spy stuff)
    spy using outlines={
        circle,
        magnification=10,
        size=20mm,
        connect spies,
    },
    % -------------------------------------------------------------------------
]
    \begin{axis}[
        xmin=lb,
        xmax=ub,
        ymin=0,
        ymax=3.5,       % <-- (adapted)
        axis on top,
        % (moved common options here)
        domain=lb:ub,
        % -----------------------------
        % using non-linear spacing `samples' can drastically be reduced
        samples=51,
        % added `smooth'
        smooth,
        % -----------------------------
    ]

%        % old solution using linear spacing
%        \addplot [
%            color=gray,
%            pattern=flexible hatch,
%            pattern color=orange,
%            % -----------------------------
%            % increased `samples'
%            samples=1001,
%            % -----------------------------
%        % (simplified and corrected unbalanced braces)
%        ] {(1/pi) * 0.1/(x^2+0.01)};

        % new solution using non-linear spacing
        \addplot [
            color=gray,
            pattern=flexible hatch,
            pattern color=orange,
        ] ({myX(x)},{myL(myX(x))});

        % -----------------------------------------------------------------
        % (for debugging purposes only
        %  it shows the points where the main function is evaluated)
        \addplot [
            only marks,
            mark size=0.5pt,
            blue,
        ] ({myX(x)},3.25);
        % ---------------------------------------------------------------------
        % (only needed for the spy stuff)
            \coordinate (spy) at (axis cs:-2.25,2.5);
            \coordinate (A)   at (axis cs:0,3.15);
        \spy on (A) in node at (spy);
        % ---------------------------------------------------------------------

    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code

  • I added an answer which uses your code from this answer, and some of your answer here. If you would want to include it in your answer here, please let me know and I will be happy to delete my answer. – Max Aug 20 at 9:46
  • @Max, yesterday and today in the morning I just had no time to implement the non-linear spacing solution. But with your preliminary work it was quite easy. Please don't delete your answer, because it was the basis for my edited answer. Many thanks for that. (+1) – Stefan Pinnow Aug 20 at 20:49
  • What are the blue dots Stefan? All users are very excellent. Upvote all and again thank you "mille grazie". – Sebastiano Aug 20 at 20:49
  • 1
    I just added a comment in the code what it is good for. It is just to show the x values where the function is evaluated when you use the non-linear spacing approach. (With this it is much easier to see as in Max's answer, at least for me.) – Stefan Pinnow Aug 20 at 20:54
  • @StefanPinnow I didn't understand anything but it's okay. I would have liked to give the green check to everyone and I am sorry hoping that no one will be offended. All were very good. – Sebastiano Aug 20 at 20:57

You need a higher sampling rate:

\documentclass{article}
    \usepackage{tikz,amsmath,xcolor}
    \usetikzlibrary{patterns}
    \usepackage{pgfplots}
    \usetikzlibrary{spy}
    \begin{document}
    \begin{tikzpicture}[spy using outlines={circle=.5cm, magnification=3, size=.5cm, connect spies}]
    \tikzset{
        hatch distance/.store in=\hatchdistance,
        hatch distance=10pt,
        hatch thickness/.store in=\hatchthickness,
        hatch thickness=2pt
    }

    \makeatletter
    \pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{flexible hatch}
    {\pgfqpoint{0pt}{0pt}}
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
    \makeatother

    \begin{axis}[
        xmin=-4,xmax=4,
        xlabel={},
%        ymin=0,ymax=3,
        axis on top,
        legend style={legend cell align=right,legend plot pos=right}] 
       %\begin{scope}
    %\spy[green!70!black,size=2cm] on (2.5,1) in node [fill=white] at (8,2);
       %\end{scope}
    \addplot[color=gray,domain=-4:4,samples=100] {(1/pi)*(0.1/((x)^2+0.01)};

       \addplot+[color=gray,mark=none,
        domain=-4:4,
        samples=100,
        pattern=flexible hatch,
        area legend,
        samples=10000,
        pattern color=orange]{(1/pi)*(0.1/((x)^2+0.01)} \closedcycle;


    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • This afternoon I inserted samples=1000 and I had the same problem. For this reason, I have not increased this value. +1 – Sebastiano Aug 19 at 19:57
  • When I compile your code I have this error: Package pgfplots Warning: running in backwards compatibility mode (unsuitable t ick labels; missing features). Consider writing \pgfplotsset{compat=1.16} into your preamble. on input line 6. Runaway definition? ->\pgfpl@@ {{\pgfkeyssetvalue {/pgfplots/execute at begin plot visual\ETC. ! TeX capacity exceeded, sorry [main memory size=3000000]. \pgfplotslistpushbackglobal ...e \t@pgfplots@toka } l.46 ...e]{(1/pi)*(0.1/((x)^2+0.01)} \closedcycle; – Sebastiano Aug 19 at 20:03
  • @Sebastiano Works fine for me. – samcarter Aug 19 at 20:08
  • Why not for me? – Sebastiano Aug 19 at 20:09
  • 2
    @Sebastiano I think you have to try to compile this with lualatex. With pdflatex and xelatex I also get the TeX capacity exceeded-error. – Max Aug 20 at 6:56

The idea is to use an odd number of sample points and use smooth. Note: Too many sample points tends to exhaust computer memory, so I used samples=101 for the curve and samples=101 for the orange shading.

\documentclass{article}
    \usepackage{tikz,amsmath,xcolor}
    \usetikzlibrary{patterns}
    \usepackage{pgfplots}
    \usetikzlibrary{spy}
    \begin{document}
    \begin{tikzpicture}[spy using outlines={circle=.5cm, magnification=3, size=.5cm, connect spies}]
    \tikzset{
        hatch distance/.store in=\hatchdistance,
        hatch distance=10pt,
        hatch thickness/.store in=\hatchthickness,
        hatch thickness=2pt
    }

    \makeatletter
    \pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{flexible hatch}
    {\pgfqpoint{0pt}{0pt}}
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
    \makeatother

    \begin{axis}[
        xmin=-4,xmax=4,
        xlabel={},
%        ymin=0,ymax=3,
        axis on top,
        legend style={legend cell align=right,legend plot pos=right}] 
       %\begin{scope}
    %\spy[green!70!black,size=2cm] on (2.5,1) in node [fill=white] at (8,2);
       %\end{scope}
    \addplot[color=gray,domain=-4:4,samples=101,smooth] {(1/pi)*(0.1/((x)^2+0.01)};

       \addplot+[color=gray,mark=none,
        domain=-4:4,
        samples=101,
        pattern=flexible hatch,
        area legend,
        pattern color=orange]{(1/pi)*(0.1/((x)^2+0.01)} \closedcycle;


    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Due to the shape of the plot, it seems as if you simply want more samples around x=0. Stefan Pinnow came up with a very clever way of manipulating the sample distance in his answer here (which could use some more upvotes). To use this method for a plot that has a pattern fill, it must be adjusted such that you can use it with one \addplot command.

The following variables are used in Tikz's declare function key:

  • b is used as lower and upper bound (haven't figured out yet how to make this unsymmetrical around the y-axis, i.e. with different lower and upper bounds);
  • Y(x) is used to give nonlinear spacing of the samples, this should be a function that grows exponentially (e.g. exp(x) or x^2);
  • X(x) provides samples, non-linearly spaced in domain=-b:b with a higher density around x=0;
  • I also added a function for your Lorentzian's function: L(x,xz,ep), to make it a bit more reusable.

The following code declares the functions (MWE will be provided below):

declare function={
    % outer bound
    b=4;
    % function to use for the nonlinear spacing
    Y(\x) = exp(\x);
    % Y(\x) = (\x)^2; % alternative nonlinear spacing function
    % rescale samples to domain=-b:b
    X(\x) = (\x >= 0) * (b*(Y(\x) - Y(0))/(Y(b) - Y(0)))
            - (\x < 0) * (b*(Y(-\x) - Y(0))/(Y(b) - Y(0)));
    % Lorentzian function 
    L(\x,\xz,\ep) = (1/pi) * (\ep/((\x-\xz)^2 + (\ep)^2));
},

And the \addplot command can be used as follows:

\addplot [
    color=gray,
    pattern=flexible hatch,
    pattern color=orange,
% (simplified and corrected unbalanced braces)
] ({X(x)},{L(X(x),0,0.1)});

Note that the x coordinate of every point is given by {X(x)}, and the y coordinate by {L(X(x),0,0.1)}.

I used the excellent code from Stefan Pinnow's answer to work with. In the following, the blue line with the (smaller) green markers was plotted with the default (linear) sample spacing, and the grey line with the orange markers was plotted with the custom spacing (both with only 51 samples). Notice how few green markers are drawn on the pulse shape.

enter image description here

Without the markers and the blue plot, it looks like this (very similar to the results of Stefan Pinnow and samcarter, but with a lot less samples):

enter image description here

MWE:

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{
        patterns,
        spy,
    }
    \tikzset{
        hatch distance/.store in=\hatchdistance,
        hatch distance=10pt,
        hatch thickness/.store in=\hatchthickness,
        hatch thickness=2pt,
    }

    \makeatletter
    \pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{flexible hatch}
    {\pgfqpoint{0pt}{0pt}}
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}
    {\pgfpoint{\hatchdistance-2pt}{\hatchdistance-2pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
    \makeatother
\begin{document}
\begin{tikzpicture}[
    % -------------------------------------------------------------------------
    % declare functions for nonlinear spacing, and for the Lorentzian
    declare function={
        % outer bound
        b=4;
        % function to use for the nonlinear spacing
        Y(\x) = exp(\x);
        % Y(\x) = (\x)^2; % alternative nonlinear spacing function
        % rescale samples to domain=-b:b
        X(\x) = (\x >= 0) * (b*(Y(\x) - Y(0))/(Y(b) - Y(0)))
                - (\x < 0) * (b*(Y(-\x) - Y(0))/(Y(b) - Y(0)));
        % Lorentzian function 
        L(\x,\xz,\ep) = (1/pi) * (\ep/((\x-\xz)^2 + (\ep)^2));
    },
    % -------------------------------------------------------------------------
    % (only needed for the spy stuff)
    spy using outlines={
        circle,
        magnification=10,
        size=20mm,
        connect spies,
    },
    % -------------------------------------------------------------------------
]
    \begin{axis}[
        xmin=-4,
        xmax=4,
        ymin=0,
        ymax=3.5,       % <-- (adapted)
        axis on top,
        % (moved common options here)
        domain=-b:b,
        % -----------------------------
        % increased `samples' ...
        samples=51,
        % ... and added `smooth'
        smooth,
    ]

        \addplot [
            color=gray,
            pattern=flexible hatch,
            pattern color=orange,
        % (simplified and corrected unbalanced braces)
        ] ({X(x)},{L(X(x),0,0.1)});

        % ---------------------------------------------------------------------
        % (only needed for the spy stuff)
            \coordinate (spy) at (axis cs:-2.25,2.5);
            \coordinate (A)   at (axis cs:0,3.15);
        \spy on (A) in node at (spy);
         ---------------------------------------------------------------------

    \end{axis}

\end{tikzpicture}
\end{document}
  • I thank you infinitely for the time you have dedicated for me. I understood your comment and the solution very well. This was the first time this has happened to me. Thank you again and, of course, I am voting in favour. – Sebastiano Aug 20 at 9:11
  • @marmot What comment you must remove? :-o – Sebastiano Aug 20 at 20:54
  • @Sebastiano I made a false statement, namely that Max is not using smooth, and made the not particularly helpful suggestion to use samples at to make the number of points denser around 0. This works as well, but there is no obvious advantage compared to Max's beautiful answer. (Note that percusse keeps stressing that smooth distorts the graph. I confirmed this by playing with that example, but Max chooses a sufficiently high number of sample points in the critical region such that this makes no difference.) For me this is the best answer here. – marmot Aug 20 at 20:59

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.