过滤表中的行

过滤表中的行

我有一张包含许多实例结果的大表,我想制作按一个(或多个)字段分组的单独表格和图表。在这个最小工作示例中,我想为所有 20 个房屋实例制作一个表格和一个图表,为所有 200 个房屋实例制作另一个表格和图表。

最好的办法是从原始表格中获取两个子表格,只保留 houses=20 或 houses=200 的行(如果我可以在表格文件中分离数据,我就会得到这样的行)。我希望避免每次排版表格或绘图时都明确过滤,或者至少应该使用最少的代码来执行此操作(也许定义自定义样式?)。

\documentclass{article}

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

\usepackage{pgfplotstable}

\begin{document}

\pgfplotstableread{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
}{\fulltable}


Table for all instances

\pgfplotstabletypeset{\fulltable}

\begin{tikzpicture}
  \begin{axis}[
      title={Values for all instances},
      xlabel={Instance},
      ylabel={Value}]
    \addplot+[scatter, only marks] table[x=instance, y=value]
      {\fulltable};
  \end{axis}
\end{tikzpicture}

\newpage

Table for 20 houses instances

???

Plot for 20 houses instances

???

\end{document}

编辑

通过查看类似的问题,我想出了这个部分解决方案:

%\filtertable{table}{field}{value}{#1}
\newcommand{\filtertable}[4]{
\pgfplotstablegetelem{#4}{#2}\of{#1}
\ifnum\pgfplotsretval=#3\relax
\else\pgfplotstableuserowfalse\fi
}

%\filtertableplot{table}{field}{value}
\newcommand{\filtertableplot}[3]{
\pgfplotstablegetelem{\coordindex}{#2}\of{#1}
\ifnum\pgfplotsretval=#3
\else
\def\pgfmathresult{}
\fi
}

Table for 200 houses instances

\pgfplotstabletypeset[
    columns={instance,value},
    row predicate/.code={\filtertable{\fulltable}{houses}{200}{#1}}
  ]
  {\fulltable}

\begin{tikzpicture}
  \begin{axis}[
      title={Values for 200 houses instances},
      xlabel={Instance},
      ylabel={Value},
      x filter/.code={\filtertableplot{\fulltable}{houses}{200}{#1}}]
    \addplot+[scatter, only marks] table[x=instance, y=value]
      {\fulltable};
  \end{axis}
\end{tikzpicture}

有没有办法避免重复表名,避免明确使用#1,并将x filter=...和包装row predicate=...在样式中?

答案1

您可以使用以下方式过滤要绘制的值discard if not={<column name>}{<value>}您可以使用以下键当条形图基于符号值时,是否可以更改单个条形的颜色?. 这允许您输入

\addplot+[only marks, discard if not={houses}{20}] table[x=instance, y=value]
      {fulltable.dat};

houses仅绘制值为 的条目20。为此,您需要将以下代码块放入前言中,并绘制文件中的数据(而不是使用 创建的表中的数据\pgfplotstableread)。

\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
        }
    }
}

对于表格,您可以执行类似操作(尽管代码有点棘手)。它允许您键入

\pgfplotstabletypeset[discard if not={houses}{20}]{fulltable.dat}

过滤行。

\makeatletter
\pgfplotstableset{
    discard if not/.style 2 args={
        row predicate/.code={
            \def\pgfplotstable@loc@TMPd{\pgfplotstablegetelem{##1}{#1}\of}
            \expandafter\pgfplotstable@loc@TMPd\pgfplotstablename
            \edef\tempa{\pgfplotsretval}
            \edef\tempb{#2}
            \ifx\tempa\tempb
            \else
                \pgfplotstableuserowfalse
            \fi
        }
    }
}
\makeatother


\documentclass{article}

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

\usepackage{pgfplotstable}
\usepackage{filecontents}

\begin{document}

\pgfplotstableread{
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
}{\fulltable}

\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}

\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
        }
    }
}

\makeatletter
\pgfplotstableset{
    discard if not/.style 2 args={
        row predicate/.code={
            \def\pgfplotstable@loc@TMPd{\pgfplotstablegetelem{##1}{#1}\of}
            \expandafter\pgfplotstable@loc@TMPd\pgfplotstablename
            \edef\tempa{\pgfplotsretval}
            \edef\tempb{#2}
            \ifx\tempa\tempb
            \else
                \pgfplotstableuserowfalse
            \fi
        }
    }
}
\makeatother

\centering
{\bfseries Table for 20 houses instances:}

\pgfplotstabletypeset[discard if not={houses}{20}]{fulltable.dat}

\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}


\end{document}

答案2

最简单的答案是利用 /pgfplots/boxplot/data filter/.code={} 选项。请参阅 pgfplots 手册第 501 页。您可以尝试 \addplot table[only if={entry of houses is 20}]{fulltable.dat};

相关内容