pgf-tikz / pgfplots

pgfplots - A TeX package to draw normal and/or logarithmic plots directly in TeX in two and three dimensions with a user-friendly interface and pgfplotstable - a TeX package to round and format numerical tables. Examples in manuals and/or on web site.
http://pgfplots.sourceforge.net/
196 stars 35 forks source link

Spurious spaces in function get typeset #370

Closed hmenke closed 3 years ago

hmenke commented 4 years ago

Brief outline of the bug

When there are spurious spaces in the definition of a \pgfmathdeclarefunction, these spaces end up in the document, shifting the plot on the page. Some people think that this is an issue in PGF (https://github.com/pgf-tikz/pgf/issues/508, https://github.com/pgf-tikz/pgf/issues/915) because it can be worked around by ignoring spaces in the definition of the function, but I believe this is a pgfplots problem. The reason is that a similar MWE with a regular \draw plot does not exhibit the shifting. This is potentially due to the fact that TikZ switches to nullfont inside the picture whereas pgfplots switches to a text font and fails to switch back to nullfont for the plot (just a hypothesis).

Minimal working example (MWE)

Here is the pgfplots example which exhibits the shift:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\begin{document}
\pgfmathdeclarefunction{test}{1}{%
    \pgfmathparse{sin(#1)} % <--- spurious space here
}
\begin{tikzpicture}
    \begin{axis}[domain=0:360, samples=100]
        \addplot {test(x)};
    \end{axis}
\end{tikzpicture}
\end{document}

This “equivalent” TikZ example does not exhibit a shift:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\pgfmathdeclarefunction{test}{1}{%
    \pgfmathparse{sin(#1)} % <--- spurious space here
}
\begin{tikzpicture}[x=.5pt]
    \draw plot[domain=0:360,samples=100] (\x,{test(\x)});
\end{tikzpicture}
\end{document}
marmotghost commented 3 years ago

It is a known thingy, coming from fpu.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fpu}
\begin{document}
\pgfmathdeclarefunction{test}{1}{%
    \pgfmathparse{sin(#1)} % <--- spurious space here
}
\begin{tikzpicture}[x=.5pt]
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
    \draw plot[domain=0:360,samples=20] (\x,{test(\x)});
\end{tikzpicture}
\end{document}
marmotghost commented 3 years ago

If this was a bug, it would be a bug of pgf, not pgfplots. However, IMHO it is not a bug. Things are written clearly in section 96 of the pgfmanual v3.1.6. You only need to set ignore spaces to true.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\begin{document}
\pgfkeys{/pgf/declare function/ignore spaces=true}
\pgfmathdeclarefunction{test}{1}{%
    \pgfmathparse{sin(#1)} % <--- spurious space here
}
\begin{tikzpicture}
    \begin{axis}[domain=0:360, samples=100]
        \addplot {test(x)};
    \end{axis}
\end{tikzpicture}
\end{document}
hmenke commented 3 years ago

Very good observation! I think I've found it:

diff --git a/tex/generic/pgf/libraries/pgflibraryfpu.code.tex b/tex/generic/pgf/libraries/pgflibraryfpu.code.tex
index c3bb9582..556e2fec 100644
--- a/tex/generic/pgf/libraries/pgflibraryfpu.code.tex
+++ b/tex/generic/pgf/libraries/pgflibraryfpu.code.tex
@@ -132,6 +132,7 @@
     \else
         \pgfmathfloatparse@output
     \fi
+    \ignorespaces
 }%

 \def\pgfmathfloat@char@asterisk{*}%
marmotghost commented 3 years ago

I agree. The ignore spaces key has some worrisome side effects, so your fix is better. One of the side effects is that you cannot use pgf keys that have spaces in the function. Your proposal does not suffer from this problem.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fpu}
\makeatletter
\def\pgfmathfloatparse@#1{%
    \edef\pgfmathfloat@expression{#1}%
    \expandafter\pgfmathfloatparse@@\pgfmathfloat@expression\pgfmathfloat@
    \ifpgfmathfloat@scaleactive
        \expandafter\pgfmathfloatmultiply@\expandafter{\pgfmathresult}{\pgfmathfloatscale}%
        \pgfmathfloattofixed{\pgfmathresult}%
    \else
        \pgfmathfloatparse@output
    \fi
    \ignorespaces %<- works
}%
\makeatother
\begin{document}
\tikzset{myfun/.cd,a 1/.initial=1}
% \pgfkeys{/pgf/declare function/ignore spaces=true} %<- does not work
\pgfmathdeclarefunction{test}{1}{%
    \pgfmathparse{sin(\pgfkeysvalueof{/tikz/myfun/a 1}*#1)} % <--- spurious space here
}
\begin{tikzpicture}[x=.5pt,]
    \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}%
    \draw plot[domain=0:360,samples=35] (\x,{test(\x)});
\end{tikzpicture}
\end{document}
hmenke commented 3 years ago

Not a pgfplots problem, therefore invalid. Fixed in https://github.com/pgf-tikz/pgf/commit/0c2237bd3bbcc140dbb53e2f467850e126d6436c