7

I was wondering if there is any way to make pgfplots read the xlabel and ylabel from a file. This is similar to this question Using Labels from a File in PGFplot but I'd like to read the column headings and use them as axis descriptions (not as labels for individual ticks).

To stick with the example from the other post, for a file foo.dat like this

# foo.dat
# X-Position Height
  1          15
  2          20
  3          12
  4          24

I would like to have an axis environment equivalent to

\begin{axis}[xlabel=X-Position, ylabel=Height]
   \addplot file {foo.dat};
\end{axis}

but without having to specify xlabel=X-Position, ylabel=Height explicitly.

The reason for this strange question is that I'm using a tex file in a script to generate plot images. Without axis descriptions I can generate a data file, copy both the data file and the prepared tex file into a temporary folder an compile everything. If what I asked is not possible, I would have to change the tex file. I can deal with this by generating the tex file on the fly in this case, but I was just wondering if there was a better solution.

1 Answer 1

9

Yes, that is possible using the macros of pgfplotstable (which is always shipped together with pgfplots).

pgfplotstable allows to read the table into some in-memory structure, and it supports \pgfplotstableforeachcolumn<\tablename>\as<\loopvariable>{<loop body>}. Inside of <loop body>, the macro <\loopvariable> expands to the column name and \pgfplotstablecol expands to the column index.

Thus, we can iterate over all columns and have access to name and index. We only need to combine this with a TeX expansion trick and a mapping from column indices to axis directions (0=>x, 1=>y) and have a running prototype:


\documentclass[a4paper]{article}

\usepackage{filecontents}

\begin{filecontents}{foo.dat}
# foo.dat
 X-Position Height
  1          15
  2          20
  3          12
  4          24
\end{filecontents}

\usepackage{pgfplots}
\pgfplotsset{compat=1.3}
\usepackage{pgfplotstable}

\begin{document}

\begin{tikzpicture}
    % this here allows to set labels by INDEX rather than 'x', 'y', or 'z':
    \pgfplotsset{
        label no 0/.style={xlabel={#1}},
        label no 1/.style={ylabel={#1}},
        label no 2/.style={zlabel={#1}},
    }
    % this loads your external data file:
    \pgfplotstableread{foo.dat}\loadedtable

    % this iterates over every column name, where the current column name is stored in
    % '\col':
    \pgfplotstableforeachcolumn\loadedtable\as\col{%
        % this here defines '\temp' to be 
        %   '\pgfplotsset{label no 0={X-Position}}'
        % instead of
        %   '\pgfplotsset{label no 0={\col}}'
        % purpose: '\col' must be expanded (\'e'def) immediately
        % before it is overwritten in the next loop iteration.
        \edef\temp{\noexpand\pgfplotsset{label no \pgfplotstablecol={\col}}}
        % this here calls '\temp':
        \temp
    }%

    % the axis always uses the currently set options - in our case
    % 'xlabel' and 'ylabel':
    \begin{axis}
    \addplot table {\loadedtable};  
    \end{axis}
\end{tikzpicture}
\end{document}

Note that I removed the # before your column headings in foo.dat: pgfplotstable will ignore any data line which starts with # (which is considered to be a comment char).

The <name>/.style={<stuff>} syntax is the way of pgf to define a style called <name>. Whenever <name>={<value>} is used, it expands to the keys <stuff> where #1 is replaced by <value>. That's how the mapping from column index to x, y, and z is done.

The remaining tricky part with \edef does precisely what I wrote in the source comment - but it is not commonly known. It is some kind of scripting element in TeX (see texdoc TeX-programming-Notes if you want to learn more about TeX's expansion control).

1
  • Great answer, thanks! Maybe a variant of this would make a nice macro for pgfplots. Something like \plottablecolumns{3}{1}{foo.dat} could be used to add an axis environment with xlabel=columnheader[3], ylabel=columnheader[1] and exactly one plot that plots columns 3 (as x) and 1 (as y). Would probably need some if-then-else construct to pick the correct columns during the loop. Anyway, that was just a thought, all I needed right now was what you explained in your answer.
    – Flogo
    Commented Sep 15, 2011 at 21:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .