5

As everyone knows from this answer, it is possible to filter rows from a table using discard if not style/filter. But this solution works only if one provides a filename as the argument to \addplot table, and it won't work if one read the table using \pgfplotstableread{file}\name and use it as the argument \addplot[discard if not...] table \name;:

no

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\usepackage{pgfplotstable}
\usepackage{filecontents}


\begin{filecontents}{fulltable.dat}
houses  instance    value
20      1           8919
20      2           8965
20      3           8901
20      4           8816
20      5           8875
20      6           9027
20      7           8915
20      8           8907
20      9           8832
20      10          8934
200     1           84714
200     3           85630
200     4           84748
200     5           84565
200     6           85109
200     7           84588
200     8           84638
200     9           84673
200     10          85170
\end{filecontents}


\begin{document}

\pgfplotsset{
    discard if not/.style 2 args={
        x filter/.code={
            \edef\tempa{\thisrow{#1}}
            \edef\tempb{#2}
            \ifx\tempa\tempb
            \else
                \def\pgfmathresult{inf}
            \fi
        }
    }
}

\pgfplotstableread{fulltable.dat}\fulltable

\begin{tikzpicture}[trim axis left]
  \begin{axis}[
      title={{\bfseries Plot for 20 houses instances}},
      xlabel={Instance},
      ylabel={Value}]
    \addplot+[only marks, discard if not={houses}{20}] table[x=instance, y=value]
      {fulltable.dat};
  \end{axis}
\end{tikzpicture}

\begin{tikzpicture}[trim axis left]
  \begin{axis}[
      title={{\bfseries Plot for 20 houses instances}},
      xlabel={Instance},
      ylabel={Value}]
    \addplot+[only marks, discard if not={houses}{20}] table[x=instance, y=value]
      {\fulltable};
  \end{axis}
\end{tikzpicture}

\end{document}

What to do? I want this thing working for macros.

  • Welcome to TeX.SX. I guess than you have to fix the already reported bug or wait until it will be fixed by somebody else ... – Stefan Pinnow Feb 20 '17 at 20:03
7

tl;dr

The following work

\def\thisrowunavailableloadtabledirectly{thisrow_unavailable_load_table_directly}
\def\sudogetthisrow#1#2{
    \edef#2{\thisrow{#1}}
    \ifx#2\thisrowunavailableloadtabledirectly % if \thisrow fails to get the element
                            % then #2 is thisrow_unavailable_load_table_directlye
                            % we have a backup
        \getthisrow{#1}{}
        \let#2=\pgfplotsretval
    \fi
}

\pgfplotsset{
    discard if not/.style 2 args={
        x filter/.code={
            \sudogetthisrow{#1}\tempa
            \edef\tempb{#2}
            \ifnum\tempa=\tempb
            \else
                \def\pgfmathresult{inf}
            \fi
            \message{^^J\tempa,\tempb,\pgfmathresult^^J}
        }
    }
}

Story

When reading the table from a macro, pgfplots will execute the macro \pgfplots@addplotimpl@table@fromstructure@. In this situation \thisrow and \thisrowno do not work. Therefore in pgfplotscoordprocessing.code.tex line 6522-6529 the author added some comment

% These macros are-unfortunately- not accessable here. And the
% worst is: error messages are impossible either because they are
% not executed... try to provide useful hints:
\def\thisrow##1{thisrow_unavailable_load_table_directly}%
\def\thisrowno##1{thisrowno_unavailable_load_table_directly}%
% this should work.
\def\getthisrow##1##2{\pgfplotstablegetelem{\coordindex}{##1}\of{#3}{##2}}%
\def\getthisrowno##1##2{\pgfplotstablegetelem{\coordindex}{[index]##1}\of{#3}{##2}}%
%

It seems like the author suggests that we should use \getthisrow{houses}\tempa instead.

However if you try it, you will get another error. The reason is that \pgfplotstablegetelem takes only three arguments. So {##2} (which will be \tempa) will be left outside and inevitably issues a undefined control sequence.

So the trick here is to define a sudo version of getthisrow which

  • try to get the element by \edef\tempa{\thisrow{houses}}
  • if it fails, try \getthisrow{houses}{} (Notice the empty argument)
    • \pgfplotstablegetelem will store the element to \pgfplotsretval
    • let tempa be \pgfplotsretval

Full working code

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\usepackage{pgfplotstable}
\usepackage{filecontents}


\begin{filecontents}{fulltable.dat}
houses  instance    value
20      1           8919
20      2           8965
20      3           8901
20      4           8816
20      5           8875
20      6           9027
20      7           8915
20      8           8907
20      9           8832
20      10          8934
200     1           84714
200     3           85630
200     4           84748
200     5           84565
200     6           85109
200     7           84588
200     8           84638
200     9           84673
200     10          85170
\end{filecontents}


\begin{document}

\def\thisrowunavailableloadtabledirectly{thisrow_unavailable_load_table_directly}
\def\sudogetthisrow#1#2{
    \edef#2{\thisrow{#1}}
    \ifx#2\thisrowunavailableloadtabledirectly % if \thisrow fails to get the element
                            % then #2 is thisrow_unavailable_load_table_directlye
                            % we have a backup
        \getthisrow{#1}{}
        \let#2=\pgfplotsretval
    \fi
}

\pgfplotsset{
    discard if not/.style 2 args={
        x filter/.code={
            \sudogetthisrow{#1}\tempa
            \edef\tempb{#2}
            \ifnum\tempa=\tempb
            \else
                \def\pgfmathresult{inf}
            \fi
            \message{^^J\tempa,\tempb,\pgfmathresult^^J}
        }
    }
}

\pgfplotstableread{fulltable.dat}\fulltable

\begin{tikzpicture}[trim axis left]
  \begin{axis}[
      title={{\bfseries Plot for 20 houses instances}},
      xlabel={Instance},
      ylabel={Value}]
    \addplot+[only marks, discard if not={houses}{20}] table[x=instance, y=value]
      {fulltable.dat};
  \end{axis}
\end{tikzpicture}

\begin{tikzpicture}[trim axis left]
  \begin{axis}[
      title={{\bfseries Plot for 20 houses instances}},
      xlabel={Instance},
      ylabel={Value}]
    \addplot+[only marks, discard if not={houses}{20}] table[x=instance, y=value]
      {\fulltable};
  \end{axis}
\end{tikzpicture}

\end{document}

  • 2
    nice solution, however I afraid it is usable only for few, very skilled pgfplot users. For wider use, features are very useful, the complexity use of this macros should be hidden from user :). Maybe in some kind data-filter library? – Zarko Mar 5 '17 at 15:22

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.