6

I'm using pgfplots. The graph is clipped where it shouldn't, how can I fix it?

\documentclass{article}

\usepackage{tikz}
\usepackage{siunitx}
\usepackage{pgfplots}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}[
        ymin=0,ymax=0.33,
        xmin=0,xmax=260,
        ticks=none,axis x line=bottom,axis y line=left,xlabel={Voltage (\si{\volt})}, ylabel={Current (\si{\ampere})},
    ]
    \addplot[
        domain=0:249.999,
        samples=1000,
    ]
        {0.0257019* ln(1000 *(250 - x))};
    \end{axis}
    \end{tikzpicture}
\end{document}

The graph of the function is clipped, but it should reach the x axis

Because of the steepness of the graph near 250, I want to add a point at (250,0), so pgfplots can draw a vertical line, I've been trying to do this without success. This is the real example:

\documentclass{article}

\usepackage{tikz}
\usepackage{siunitx}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}[
    declare function={
        func(\x)= (\x<250) * 0.02570194444* ln(1.470588235e10 -5.882352941e7* \x)) +
            (\x==250)*(0);
    }
]
    \begin{axis}[
        clip=false,
        ymin=0,ymax=0.625,
        xmin=0,xmax=260,
        every axis y label/.style={
            at={(ticklabel* cs:0.5)},
            anchor=near ticklabel,
            rotate=90,
        },
        every axis x label/.style={
            at={(ticklabel* cs:0.5)},
            anchor=near ticklabel,
        },
        ticks=none,
        xlabel={Voltage (\si{\volt})}, ylabel={Current (\si{\ampere})},
        ]

        \addplot[domain=0:250,samples=3000,thick]{func(x)};
    \end{axis}
\end{tikzpicture}
\end{document}

Real graph

How can I do that?

  • That's your end point sample sensitivity. Try with 151 samples. The log is blowing down faster than the sensitivity of the math engine of rusty TeX. – percusse Jun 5 '14 at 18:35
7

This problem is very similar to tikz does not plot correctly (which is about the TikZ plotting functionality): Due to numerical inaccuracies, sometimes the domain isn't sampled right up to the specified upper limit.

To fix this, PGFPlots has to be taught to always use the specified upper limit (given using domain=<lower>:<uppper>), and not the calculated one (determined using <lower> + <samples> * <step size>. In PGFPlots, this can be achieved by patching an internal macro used in \pgfplotforeachungrouped, which is a variant of the \foreach function:

\documentclass{article}

\usepackage{pgfplots}

\makeatletter
\long\def\pgfplotsforeachungroupeduniform@#1#2,#3,...,#4\relax#5{%
    % Compute mesh width!
    \pgfmathparse{#2}%
    \let\pgfplots@foreach@loc@TMPa=\pgfmathresult
    \pgfmathparse{#3}%
    \let\pgfplots@foreach@loc@TMPb=\pgfmathresult
    \pgfmathsubtract@{\pgfplots@foreach@loc@TMPb}{\pgfplots@foreach@loc@TMPa}%
    % Use \pgfmath engine for the loop:
    % mesh width:
    \let\pgfplots@foreach@loc@meshwidth=\pgfmathresult
    \pgfmathparse{0}% invoke the parser - in case the fpu is active.
    \pgfmathlessthan@{\pgfplots@foreach@loc@meshwidth}{\pgfmathresult}%
    % the loop will run while ( NOT \pgfplots@foreach@loc@cmp{<cur>}{<last>} )
    \ifdim\pgfmathresult pt=1pt
        \def\pgfplots@foreach@loc@cmp{\pgfmathlessthan@}%
    \else
        \def\pgfplots@foreach@loc@cmp{\pgfmathgreaterthan@}%
    \fi
    %
    \pgfmathparse{#4 - 0.5*\pgfplots@foreach@loc@meshwidth}% Do the iteration only up to the penultimate value
    \let\pgfplots@foreach@loc@TMPb=\pgfmathresult
    %
    \t@pgfplots@toka={#5}%
    % to allow nesting without additional TeX groups of
    % \pgfplotsforeachungroupeduniform, I introduce this loop
    % structure here which does not need ANY state macro:
    \edef\pgfplots@foreach@loc@TMPc{%
        \noexpand\pgfplotsforeachungroupeduniform@loop@mathengine
            {\expandafter\noexpand\pgfplots@foreach@loc@cmp}% #1= comparison fct
            {\pgfplots@foreach@loc@TMPa}% #2 =lower limit (ITERATES)
            {\pgfplots@foreach@loc@TMPb}% #3 = upper limit
            {\noexpand#1}% #4 = the loop macro name
            {\pgfplots@foreach@loc@meshwidth}% #5 =  h
            {\the\t@pgfplots@toka}% #6 = the code to invoke
    }%
    \pgfplots@foreach@loc@TMPc
    % After the iteration is done, invoke the code one last time with the value of the given upper limit
    \def#1{#4}%
    #5
}%
\makeatother



\begin{document}
    \begin{tikzpicture}
    \begin{axis}[
        ymin=0,ymax=0.33,
        xmin=0,xmax=260,
        ticks=none,axis x line=bottom,axis y line=left,xlabel={Voltage (\si{\volt})}, ylabel={Current (\si{\ampere})},
    ]
    \addplot[
        domain=0:249.9999,
        samples=100,
    ]
        {0.0257019* ln(1000 *(250 - x))};
    \addplot [domain=-1:1, samples=50] {sqrt(4*(1-(\x)^2))};
    \end{axis}
    \end{tikzpicture}
\end{document}
4

enter image description here

\documentclass{article}

%\usepackage{tikz}
\usepackage{siunitx}
\usepackage{pgfplots}
 \pgfplotsset{compat=1.9}
\begin{document}
    \begin{tikzpicture}
    \begin{axis}[
        ymin=0,ymax=0.33,
        xmin=0,xmax=260,
        ticks=none,axis x line=bottom,axis y line=left,xlabel={Voltage (\si{\volt})}, ylabel={Current (\si{\ampere})},
    ]
    \addplot[
        domain=0:250,
        samples=1000,
    ]
    { (0.0257019* ln(1000 *(250 - x)))*(x<249.9)+0};
    \end{axis}
    \end{tikzpicture}
\end{document}
  • Hehe, nice idea! Borderline cheating =) – Jake Jun 6 '14 at 21:12
  • I play by the rules, but you rewrite them using a lot of m@gic commands ;-) – Tarass Jun 7 '14 at 7:24
2

The problem appears to be due to the limited number of points that pgfplots uses as the function changes very quickly, and because the domain you specified is not quite wide enough. By splitting the plot into two, you can better control the number of points that pgfplots applies to each section. I also had to increase the domain of the second plot to 249.9999 instead of 249.999. This is a pretty brute-force approach though, I expect there is a better way... anyways, the following worked for me with pdflatex and lualatex.

% arara: pdflatex
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\begin{document}
    \begin{tikzpicture}
    \begin{axis}[
        ymin=0,ymax=0.33,
        xmin=0,xmax=260,
        ticks=none,axis x line=bottom,axis y line=left,
    ]
    \addplot[
        domain=0:240,
        samples=1000,
    ]
        {0.0257019* ln(1000 *(250 - x))};
    \addplot[
        domain=240:249.9999,
        samples=1000,
    ]
        {0.0257019* ln(1000 *(250 - x))};
    \end{axis}
    \end{tikzpicture}
\end{document}

graph image

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.