10

I use addplot to plot a data set which has nan values.

The data file contains 5 columns. First column is the x-axis (time), the second and fourth is the wavelenght (same element, but 2 measurements) with its corresponding errors in the third and fifth column. I can plot it with errorbars, but the last addplot does not work.

I want to make different y expr for different cases (value is NaN or not), because otherwise pgfplots just skips the "fit" if there's a "NaN".

Here is a minimal example:

\documentclass[11pt]{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\usepackage{verbatim}

\begin{filecontents*}{data.dat}
time    w1  e1  w2  e2
1   3019    40  nan nan
2   3045    34  nan nan
3   3100    50  3104    24
4   3500    13  3498    90
5   3800    90  3803    12
6   nan nan 3980    43
7   nan nan 3985    80
\end{filecontents*}

\begin{document}

\begin{tikzpicture}
\begin{axis} [
compat=newest,
y tick label style={/pgf/number format/1000 sep=},
ymin=2900,
ymax=4400]

    \addplot [only marks, mark=+, color=red, thick,
    error bars/.cd,
    y explicit,
    y dir=both
    ] table [x index=0, y index=1, y error index=2] {data.dat};
    \addlegendentry{measurement 1}

    \addplot [only marks, mark=+, color=green, thick,
    error bars/.cd,
    y explicit,
    y dir=both
    ] table [x index=0, y index=3,y error index=4] {data.dat};
    \addlegendentry{measurement 2}

\begin{comment}
\addplot [color=blue, thick
    ] table [x index=0,

                %this is the part I have no idea how to make it work:

                if (index 1 and index 3 are not NaN):
                  y expr= (index 1 + index 3)/2
                  y error expr= max{index 2, index 4}
                else if (index 3 = NaN):
                  y index =1
                  y error index=2
                else if (index 1 = NaN):
                  y index =3
                  y error index=4
                 ] {data.dat};
    \addlegendentry{fit}
\end{comment}

\end{axis}
\end{tikzpicture}

\end{document}

I hope it's obvious what I am trying to do. I am looking forward for your comments and thanking you in anticipation!

  • Hi Andy, welcome to the site! Could you include a dummy data file in your question, and complete the code snippet to a full minimal example document (starting from '\documentclass')? That makes it easier for others to start working on a solution. – Jake May 13 '13 at 22:09
  • ok, the exciting part is between \begin{comment} and \end{comment} – Andy May 13 '13 at 22:43
7

You can define a customized math "function" which relies on the fact that it is evaluated while the input table is read. In other words, it is only valid within your context.

It uses the FPU of pgf which is used by pgfplots, and, in particular, its method \pgfmathfloatparsenumber. A float in pgf has "flags" which is an integer with the meaning

0 == '0' (the number is +- 0.0),
1 == '+', 
2 == '-',
3 == 'not a number'
4 == '+ infinity'
5 == '- infinity'

consequently, we can call \pgfmathfloatparsenumber and use \pgfmathfloatgetflagstomacro to access the flag. Integer comparisons can be done by means of \ifnum<int>=<int> \else \fi.

Defining two functions, one for Y and one for the error bar results in

\documentclass[11pt]{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\usepackage{verbatim}

\begin{filecontents*}{data.dat}
time    w1  e1  w2  e2
1   3019    40  nan nan
2   3045    34  nan nan
3   3100    50  3104    24
4   3500    13  3498    90
5   3800    90  3803    12
6   nan nan 3980    43
7   nan nan 3985    80
\end{filecontents*}

\begin{document}
\thispagestyle{empty}

%                if (index 1 and index 3 are not NaN):
%                  y expr= (index 1 + index 3)/2
%                  y error expr= max{index 2, index 4}
%                else if (index 3 = NaN): % && index 1 is not NaN
%                  y index =1
%                  y error index=2
%                else if (index 1 = NaN): % && index 3 is not NaN
%                  y index =3
%                  y error index=4
\pgfmathdeclarefunction{VAL}{0}{%
    \pgfmathfloatparsenumber{\thisrowno{1}}\let\A=\pgfmathresult
    \pgfmathfloatparsenumber{\thisrowno{3}}\let\C=\pgfmathresult
    \pgfmathfloatgetflagstomacro\A\flags
    \ifnum\flags=3 %
        \pgfmathfloatgetflagstomacro\C\flags
        \ifnum\flags=3 %
            % A == nan && C == nan
            \let\pgfmathresult=\A
        \else
            % A == nan && C != nan
            \let\pgfmathresult=\C
        \fi
    \else
        \pgfmathfloatgetflagstomacro\C\flags
        \ifnum\flags=3 %
            % A != nan && C == nan
            \let\pgfmathresult=\A
        \else
            % A != nan && C != nan
            \pgfmathparse{(\A + \C)/2}%
        \fi
    \fi
}%
\pgfmathdeclarefunction{VALERR}{0}{%
    \pgfmathfloatparsenumber{\thisrowno{1}}\let\A=\pgfmathresult
    \pgfmathfloatparsenumber{\thisrowno{2}}\let\B=\pgfmathresult
    \pgfmathfloatparsenumber{\thisrowno{3}}\let\C=\pgfmathresult
    \pgfmathfloatparsenumber{\thisrowno{4}}\let\D=\pgfmathresult
    \pgfmathfloatgetflagstomacro\A\flags
    \ifnum\flags=3 %
        \pgfmathfloatgetflagstomacro\C\flags
        \ifnum\flags=3 %
            % A == nan && C == nan
            \let\pgfmathresult=\B
        \else
            % A == nan && C != nan
            \let\pgfmathresult=\D
        \fi
    \else
        \pgfmathfloatgetflagstomacro\C\flags
        \ifnum\flags=3 %
            % A != nan && C == nan
            \let\pgfmathresult=\B
        \else
            % A != nan && C != nan
            \pgfmathparse{max(\B,\D)}%
        \fi
    \fi
}%

\begin{tikzpicture}
\begin{axis} [
compat=newest,
y tick label style={/pgf/number format/1000 sep=},
ymin=2900,
ymax=4400]

\addplot [color=blue, thick,
    error bars/.cd,
    y explicit,
    y dir=both,
    ] table [
        x index=0,
        y expr=VAL,
        y error expr=VALERR,
    ]
                 {data.dat};
    \addlegendentry{fit}

\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

note that I have eliminated the two other \addplot statements.

The \let\<macro>=<othermacro> copies <othermacro> to <macro>. The constructions \ifnum<\macro>=3 % compares two integers. Note the trailing space after 3, it is important to tell TeX that it should stop to search for further numeric literals. It will be omitted from the output.

  • Thank you very much! It works. I need to study this closely, because I want to extend it for more than 2 measurements. – Andy May 15 '13 at 18:02
  • Hello Christian, can you tell me what the {0} stands for in \pgfmathdeclarefunction{VAL}{0}{% ? And is there a flag for 'is a number' in opposite to 3? – Andy May 15 '13 at 19:07
  • The {0} means that the declared math function takes no arguments. – Christian Feuersänger May 15 '13 at 19:26
  • There are 5 different flags with the meaning described above: 0 means that the number is +- 0, 1 means that it is positive, 2 means it is negative. Anything above 2 means it is no bounded number. – Christian Feuersänger May 15 '13 at 19:27
  • what is +-0 ? every number? or just zero? I just implemented it for my issue and somehow the code \addplot [color=blue, thick, error bars/.cd, y explicit, y dir=both, ] table [ x index=0, y expr=VAL, y error expr=VALERR, ] {data.dat}; \addlegendentry{fit} influences the position of the plot. I try to create a minimal example and post it tomorrow. Thank you up to now, I hope my problems aren't too annoying. – Andy May 15 '13 at 20:56

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.