Is there a workaround against loss of precision in pgfplots axis?

This answer should address question 1.

The precision could be set as axis option by means of /pgf/number format/.cd,fixed,precision=<some value>.

Here are some examples:

\documentclass[]{article}
\usepackage{pgfplots}
\begin{document}
\centering
\foreach \precision in {4,5,6,7}
{
\begin{tikzpicture}
\begin{axis}[/pgf/number format/.cd,fixed,precision=\precision,
title={Precision=\precision}
]
\addplot coordinates {
 ( 10, -14136746 )
 ( 72.421875, -14136749 )
 ( 166.054688, -14136829 )
 ( 228.476562, -14137018 )
 ( 290.898438, -14137366 )
};
\end{axis}
\end{tikzpicture}
}
\end{document}

Result:

enter image description here


I might have a solution, although the current code is very ugly, because I'm not very familiar with macro's, calculating and storing values.

The code works as follows. It looks at the amount of digits in the largest y value of the data set (\nmax). Then it calculates the amount of digits of: \ymax - \ymin (ndiff). Then the amount of significant digits is given by: \nmax - \ndiff.

Code

\documentclass[]{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage[nomessages]{fp}
\usepackage{xparse}

% From https://tex.stackexchange.com/questions/197844/rounding-a-number-to-its-hundred
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\ceil}{m}
{
    \fp_eval:n { ceil ( #1 ) }
}
\ExplSyntaxOff

\newcommand{\logten}[1]
{
    \FPeval\res{ ln( abs(#1) ) / ln( 10 ) }
}

% From Jake: https://tex.stackexchange.com/questions/24910/find-a-extremal-value-in-external-data-file-with-pgfplot
\newcommand{\findmax}[1]{
    \pgfplotsforeachungrouped \table in {#1} {%
        \pgfplotstablevertcat{\concatenated}{\table}%
    }%
    \pgfplotstablesort[sort key={1},sort cmp={float >}]{\sorted}{\concatenated}%
    \pgfplotstablegetelem{0}{1}\of{\sorted}%
    \let\ymax=\pgfplotsretval%
}
\newcommand{\findmin}[1]{
    \pgfplotsforeachungrouped \table in {#1} {%
        \pgfplotstablevertcat{\concatenated}{\table}%
    }%
    \pgfplotstablesort[sort key={1},sort cmp={float <}]{\sorted}{\concatenated}%
    \pgfplotstablegetelem{0}{1}\of{\sorted}%
    \let\ymin=\pgfplotsretval%
}

\begin{filecontents}{dataA.dat}
    10          -14135746
    72.421875   -14136100
    166.054688  -14136829
    228.476562  -14137018
    290.898438  -14137701
\end{filecontents}

\begin{filecontents}{dataB.dat}
    10          -14136846
    72.421875   -14136949
    166.054688  -14136829
    228.476562  -14136718
    290.898438  -14136866
\end{filecontents}

\begin{document}

\findmax{dataA.dat}
\findmin{dataA.dat}

% number of digits in \ymax
\logten{\ymax}
\def\nmax{\ceil{\res}}
\FPeval{\nmax}{(nmax) + 1}

% Number of digits in the difference
\FPeval{\diff}{(\ymax) - (\ymin)}%   
\logten{\diff}
\def\ndiff{\ceil{\res}}

% Calculate the precision
\FPeval\precision{clip(nmax - ndiff)}

\begin{tikzpicture}
    \begin{axis}[
        y tick label style={
            /pgf/number format/.cd,
            fixed,
            zerofill,
            precision=\precision,
            /tikz/.cd,},
        title={dataA.dat, Precision=\precision}]

        \addplot table[] {dataA.dat};
    \end{axis}
\end{tikzpicture}
\end{document}

Result for both data sets

dataA dataB

Bugs

The code works for one data set, but if I run the function \findmin or \findmax on a second data set in the same document, it sometimes returns an old \ymin or \ymax.


This is just a cleaned version of Roald's version (expl3-side). I have made up one command that calculates the precision for the file (to be used before the file is included).

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage{xparse}

\ExplSyntaxOn
\fp_new:N \l__roald_ymax_fp
\fp_new:N \l__roald_ymin_fp
\fp_new:N \l__roald_diff_fp
\fp_new:N \l__roald_nmax_fp
\fp_new:N \l__roald_precision_fp

\cs_generate_variant:Nn \fp_set:Nn { NV }

% From Jake (adapted): https://tex.stackexchange.com/questions/24910/find-a-extremal-value-in-external-data-file-with-pgfplot
\DeclareDocumentCommand { \precisionforfile } { m }
  {
    % max
    \pgfplotsforeachungrouped \table in {#1} {
        \pgfplotstablevertcat{\concatenated}{\table}
    }
    \pgfplotstablesort[sort~key={1},sort~cmp={float~>}]{\sorted}{\concatenated}
    \pgfplotstablegetelem{0}{1}\of{\sorted}
    \fp_set:NV \l__roald_ymax_fp \pgfplotsretval
    % min
    \pgfplotsforeachungrouped \table in {#1} {
        \pgfplotstablevertcat{\concatenated}{\table}
    }
    \pgfplotstablesort[sort~key={1},sort~cmp={float~<}]{\sorted}{\concatenated}
    \pgfplotstablegetelem{0}{1}\of{\sorted}
    \fp_set:NV \l__roald_ymin_fp \pgfplotsretval
    % calc
    \fp_set:Nn \l__roald_nmax_fp { ceil ( ln ( abs( \l__roald_ymax_fp ) ) / ln ( 10 ) ) + 1 }
    % Number of digits in the difference
    \fp_set:Nn \l__roald_diff_fp { ceil ( ln ( abs( \l__roald_ymax_fp - \l__roald_ymin_fp ) ) / ln ( 10 ) ) }
    % Calculate the precision
    \fp_set:Nn \l__roald_precision_fp { \l__roald_nmax_fp - \l__roald_diff_fp }
    \def\precision{\fp_to_int:N \l__roald_precision_fp}
  }
\ExplSyntaxOff

\begin{filecontents}{dataA.dat}
    10          -14135746
    72.421875   -14136100
    166.054688  -14136829
    228.476562  -14137018
    290.898438  -14137701
\end{filecontents}

\begin{filecontents}{dataB.dat}
    10          -14136846
    72.421875   -14136949
    166.054688  -14136829
    228.476562  -14136718
    290.898438  -14136866
\end{filecontents}

\begin{document}

\precisionforfile{dataA.dat}

\begin{tikzpicture}
    \begin{axis}[
        y tick label style={
            /pgf/number format/.cd,
            fixed,
            zerofill,
            precision=\precision,
            /tikz/.cd,},
        title={dataA.dat, Precision=\precision}]

        \addplot table[] {dataA.dat};
    \end{axis}
\end{tikzpicture}
\end{document}

Update: The new version works with coordinate input.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage{xparse}

\ExplSyntaxOn
\fp_new:N \l__roald_ymax_fp
\fp_new:N \l__roald_ymin_fp
\fp_new:N \l__roald_nmax_fp

\fp_new:N \l_roald_precision_fp

\cs_generate_variant:Nn \regex_split:nnN { nxN }
\cs_generate_variant:Nn \fp_set:Nn { Nx }

\DeclareDocumentCommand { \precisionforcoord } { m }
  {
    \fp_zero:N \l__roald_ymin_fp
    \fp_zero:N \l__roald_ymax_fp
    \regex_split:nxN { \( } { #1 } \l_tmpa_seq
    \seq_remove_all:Nn \l_tmpa_seq { ~ }
    \seq_map_inline:Nn \l_tmpa_seq
      {
        \tl_set:Nn \l_tmpa_tl { ##1 }
        \tl_replace_all:Nnn \l_tmpa_tl { ) } { }
        \regex_split:nxN { \, } { \l_tmpa_tl } \l_tmpb_seq
        \fp_set:Nx \l_tmpa_fp { \seq_item:Nn \l_tmpb_seq { 2 } }
        \fp_compare:nT { \l__roald_ymin_fp = 0 } { \fp_gset_eq:NN \l__roald_ymin_fp \l_tmpa_fp }
        \fp_compare:nT { \l__roald_ymax_fp = 0 } { \fp_gset_eq:NN \l__roald_ymax_fp \l_tmpa_fp }
        \fp_compare:nT { \l_tmpa_fp > \l__roald_ymax_fp } { \fp_gset_eq:NN \l__roald_ymax_fp \l_tmpa_fp }
        \fp_compare:nT { \l_tmpa_fp < \l__roald_ymin_fp } { \fp_gset_eq:NN \l__roald_ymin_fp \l_tmpa_fp }
      }
    \fp_set:Nn \l__roald_nmax_fp { ceil ( ln ( abs( \l__roald_ymax_fp ) ) / ln ( 10 ) ) + 1 }
    \fp_set:Nn \l_roald_precision_fp { \l__roald_nmax_fp - ( ceil ( ln ( abs( \l__roald_ymax_fp - \l__roald_ymin_fp ) ) / ln ( 10 ) ) ) }
    \def\precision{\fp_to_int:N \l_roald_precision_fp}
  }
\ExplSyntaxOff

\def\coordinatesa{
    (10,          -14135746)
    (72.421875,   -14136100)
    (166.054688,  -14136829)
    (228.476562,  -14137018)
    (290.898438,  -14137701)
}

\def\coordinatesb{
    (10,          -14136846)
    (72.421875,   -14136949)
    (166.054688,  -14136829)
    (228.476562,  -14136718)
    (290.898438,  -14136866)
}

\begin{document}
\precisionforcoord{\coordinatesa}
\begin{tikzpicture}
    \begin{axis}[
        y tick label style={
            /pgf/number format/.cd,
            fixed,
            zerofill,
            precision=\precision,
            /tikz/.cd,},
        title={A, Precision=\precision}]
        \addplot coordinates \coordinatesa;
    \end{axis}
\end{tikzpicture}
\vskip2em
\precisionforcoord{\coordinatesb}
\begin{tikzpicture}
    \begin{axis}[
        y tick label style={
            /pgf/number format/.cd,
            fixed,
            zerofill,
            precision=\precision,
            /tikz/.cd,},
        title={B, Precision=\precision}]
        \addplot coordinates \coordinatesb;
    \end{axis}
\end{tikzpicture}
\end{document}

For the new version you will need an up-to-date expl3 installation (TL17). If you're on an older distro (e.g. TL16) updated to the frozen state you can change \pgfplotsset{compat=1.15} to \pgfplotsset{compat=1.14} and include a \usepackage{l3regex}. Note: The latter package will probably be removed from distributions in the future.


Update 2: I've just introduced a nearly on-the-fly command which replaces your addplot. The only problem is that it includes the axis environment (you cannot add another plot there), because the y labels have to be adjusted as options there.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage{xparse}

\ExplSyntaxOn
\fp_new:N \l__roald_ymax_fp
\fp_new:N \l__roald_ymin_fp
\fp_new:N \l__roald_nmax_fp

\fp_new:N \l_roald_precision_fp

\cs_generate_variant:Nn \regex_split:nnN { nxN }
\cs_generate_variant:Nn \fp_set:Nn { Nx }

\DeclareDocumentCommand { \precisionforcoord } { m }
  {
    \fp_zero:N \l__roald_ymin_fp
    \fp_zero:N \l__roald_ymax_fp
    \regex_split:nxN { \( } { #1 } \l_tmpa_seq
    \seq_remove_all:Nn \l_tmpa_seq { ~ }
    \seq_map_inline:Nn \l_tmpa_seq
      {
        \tl_set:Nn \l_tmpa_tl { ##1 }
        \tl_replace_all:Nnn \l_tmpa_tl { ) } { }
        \regex_split:nxN { \, } { \l_tmpa_tl } \l_tmpb_seq
        \fp_set:Nx \l_tmpa_fp { \seq_item:Nn \l_tmpb_seq { 2 } }
        \fp_compare:nT { \l__roald_ymin_fp = 0 } { \fp_gset_eq:NN \l__roald_ymin_fp \l_tmpa_fp }
        \fp_compare:nT { \l__roald_ymax_fp = 0 } { \fp_gset_eq:NN \l__roald_ymax_fp \l_tmpa_fp }
        \fp_compare:nT { \l_tmpa_fp > \l__roald_ymax_fp } { \fp_gset_eq:NN \l__roald_ymax_fp \l_tmpa_fp }
        \fp_compare:nT { \l_tmpa_fp < \l__roald_ymin_fp } { \fp_gset_eq:NN \l__roald_ymin_fp \l_tmpa_fp }
      }
    \fp_set:Nn \l__roald_nmax_fp { ceil ( ln ( abs( \l__roald_ymax_fp ) ) / ln ( 10 ) ) + 1 }
    \fp_set:Nn \l_roald_precision_fp { \l__roald_nmax_fp - ( ceil ( ln ( abs( \l__roald_ymax_fp - \l__roald_ymin_fp ) ) / ln ( 10 ) ) ) }
    \def\precision{\fp_to_int:N \l_roald_precision_fp}
  }
\DeclareDocumentCommand { \axisplot } { O{} m }
  {
    \precisionforcoord{#2}
    \begin{axis}[y~tick~label~style={
            /pgf/number~format/.cd,
            fixed,
            zerofill,
            precision=\precision,
            /tikz/.cd,},#1]
      \addplot coordinates #2;
    \end{axis}
  }
\ExplSyntaxOff

\def\coordinatesa{
    (10,          -14135746)
    (72.421875,   -14136100)
    (166.054688,  -14136829)
    (228.476562,  -14137018)
    (290.898438,  -14137701)
}

\def\coordinatesb{
    (10,          -14136846)
    (72.421875,   -14136949)
    (166.054688,  -14136829)
    (228.476562,  -14136718)
    (290.898438,  -14136866)
}

\begin{document}
\begin{tikzpicture}
\axisplot[title={A, Precision=\precision}]{\coordinatesa}
\end{tikzpicture}
\vskip1em
\begin{tikzpicture}
\axisplot[title={B, Precision=\precision}]{\coordinatesb}
\end{tikzpicture}
\end{document}

precision