1

I want to make a groupplot of a number of columns from a CSV file. The CSV file looks like this:

a,b,x,y
1,2,3,4
5,6,8,1
9,2,4,5
5,5,1,9

Therefore I made a package that uses the code below to plot all of the columns (inspiration taken from http://www.traag.net/2015/01/12/plot-multiple-files-using-pgfplots/).

This works. However, I want to replace the fixed statement {a,b,y} in the main plotting loop

\pgfplotsforeachungrouped \y in {a,b,y}

by something like

\pgfplotsforeachungrouped \y in \csvPlotYCol

where \csvPlotYCol is a variable that is passed as an option from the command call. So, I could choose the columns to be plotted when I call the CSV plot commmand.

This does not work, unfortunately. I am quite sure that this is an expansion problem but I do not know how to solve it. I tried:

\noexpand\expandafter\addplot table\expandafter[x=\x, y=\y, col sep=comma] {#2};%

instead of

\noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%

with no success.

I would be happy to hear your thoughts.


Find the full compilable code below. This is the main.tex file:

\documentclass{article}
\usepackage{csvplot}

  \pgfplotsset{style1/.style=%
    {%
    height = .5\textwidth,%
    width = .5\textwidth,%
    grid = both,%
    }%
  }%

\begin{document}

    \csvPlotXY[%
        style = style1,%
        align = force,%
        caption = This is a caption,%
        label = mark1,%
        xCol = {x},%
        yCol = {a,b,y},%
    ] {data.csv}

    In \autoref{mark1} you see lines.

\end{document}

This is the complete package I wrote: You need to call it csvplot.sty

\NeedsTeXFormat{LaTeX2e}%
\ProvidesPackage{csvplot}[2017/05/17 CSV Plot]%

\RequirePackage{etoolbox}%
\RequirePackage{pgfplots}%
\RequirePackage{tikz}%
\RequirePackage{pgfkeys}%
\RequirePackage{float}%
\RequirePackage{hyperref}%

\pgfplotsset{compat=newest}%
\usepgfplotslibrary{groupplots}%

\DeclareOption{default}{%
\pgfplotsset{csvPlotStyle/.style=%
    {%
    grid=both,%
    }%
}%
}%

\ExecuteOptions{default}%
\ProcessOptions\relax%

% Set up the keys
\pgfkeys{
    % Switch to /csvPlotXY key subset
    /csvPlotXY/.is family, /csvPlotXY,%
    % User options
    %% default options
    default/.style = {width = \textwidth , height = .5\textwidth, xCol = x, yCol = y, style = csvPlotStyle, align = top},%
    %% definitions
    width/.estore in = \csvPlotWidth,%
    height/.estore in = \csvPlotHeight,%
    xCol/.estore in = \csvPlotXCol,%
    yCol/.estore in = \csvPlotYCol,%
    style/.estore in = \csvPlotStyle,%
    caption/.estore in = \csvPlotCaption,%
    label/.estore in = \csvPlotLabel,%
    align/.style = {alignments/#1/.get = \csvPlotAlignment},%
    % dictionary for alignment of figure
    alignments/.cd,%
        top/.initial = t,%
        here/.initial = h,%
        bottom/.initial = b,%
        force/.initial = H,%
        page/.initial = p,%
}

\newcommand{\csvPlotXY}[2][]{%
    \pgfkeys{/csvPlotXY, default, #1}%
    % Expand figure options
    \def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
        \centering
    \begin{tikzpicture}%
        \begin{groupplot} [
            width=\csvPlotWidth,%
            height=\csvPlotHeight,%
            % Plot loop: All x/y columns for multiple plots in one axis
            \csvPlotStyle,%
            ]%
            \pgfplotsforeachungrouped \x in {x} {%
                \pgfplotsforeachungrouped \y in {a,b,y} {%
                    \eappto\PlotList{%
                        \noexpand\nextgroupplot%
                        \noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
                        \noexpand\addlegendentry{\y}%
                    }%
                }%
            }%
            \PlotList%
        \end{groupplot}%
    \end{tikzpicture}%
        \caption{\csvPlotCaption}%
        \label{\csvPlotLabel}%
    \end{figure}
}%

This is the input data in data.csv:

a,b,x,y
1,2,3,4
5,6,8,1
9,2,4,5
5,5,1,9

At the moment, columns a, b, and y are always plotted, so that compilation works.

This is the result: Compilation result

  • Please provide a compileable example, not just code snippets. Welcome to the site. – Steven B. Segletes May 17 '17 at 13:04
2

The key was to modify the style file to take advantage of the keys, as you admittedly had it hardwired to plot a,b,y versus x. However, the trick is that the macros holding the xCol and yCol keys (which are \csvPlotXCol and \csvPlotYCol) had to be expanded in order to be digested by \pgfplotsforeachungrouped. The revised macro is

\newcommand{\csvPlotXY}[2][]{%
    \pgfkeys{/csvPlotXY, default, #1}%
    % Expand figure options
    \def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
        \centering
    \begin{tikzpicture}%
        \begin{groupplot} [
            width=\csvPlotWidth,%
            height=\csvPlotHeight,%
            % Plot loop: All x/y columns for multiple plots in one axis
            \csvPlotStyle,%
            ]%
            \def\tmpX{\pgfplotsforeachungrouped \x in }%
            \def\tmpY{\pgfplotsforeachungrouped \y in }%
            \expandafter\tmpX\expandafter{\csvPlotXCol} {%
                \expandafter\tmpY\expandafter {\csvPlotYCol} {%
                    \eappto\PlotList{%
                        \noexpand\nextgroupplot%
                        \noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
                        \noexpand\addlegendentry{\y}%
                    }%
                }%
            }%
            \PlotList%
        \end{groupplot}%
    \end{tikzpicture}%
        \caption{\csvPlotCaption}%
        \label{\csvPlotLabel}%
    \end{figure}
}%

The MWE. In the 1st plot, it is a,b,y versus x; in the 2nd, it is b,y versus x, and in the 3rd plot, it is b,y versus a.

\documentclass{article}
\usepackage{csvplot}

  \pgfplotsset{style1/.style=%
    {%
    height = .5\textwidth,%
    width = .5\textwidth,%
    grid = both,%
    }%
  }%

\begin{document}
    \csvPlotXY[%
        style = style1,%
        align = force,%
        caption = This is a caption,%
        label = mark1,%
        xCol = {x},%
        yCol = {a,b,y},%
        caption = {plotted against ``x''},
    ] {data.csv}

    \csvPlotXY[%
        style = style1,%
        align = force,%
        caption = This is a caption,%
        label = mark1,%
        xCol = {x},%
        yCol = {b,y},%
        caption = {plotted against ``x''},
    ] {data.csv}

    \csvPlotXY[%
        style = style1,%
        align = force,%
        caption = This is a caption,%
        label = mark1,%
        xCol = {a},%
        yCol = {b,y},%
        caption = {plotted against ``a''},
    ] {data.csv}
\end{document}

The csvplot.sty style file, including the revised \csvPlotXY macro:

\NeedsTeXFormat{LaTeX2e}%
\ProvidesPackage{csvplot}[2017/05/17 CSV Plot]%

\RequirePackage{etoolbox}%
\RequirePackage{pgfplots}%
\RequirePackage{tikz}%
\RequirePackage{pgfkeys}%
\RequirePackage{float}%
\RequirePackage{hyperref}%

\pgfplotsset{compat=newest}%
\usepgfplotslibrary{groupplots}%

\DeclareOption{default}{%
\pgfplotsset{csvPlotStyle/.style=%
    {%
    grid=both,%
    }%
}%
}%

\ExecuteOptions{default}%
\ProcessOptions\relax%

% Set up the keys
\pgfkeys{
    % Switch to /csvPlotXY key subset
    /csvPlotXY/.is family, /csvPlotXY,%
    % User options
    %% default options
    default/.style = {width = \textwidth , height = .5\textwidth, xCol = x, yCol = y, style = csvPlotStyle, align = top},%
    %% definitions
    width/.estore in = \csvPlotWidth,%
    height/.estore in = \csvPlotHeight,%
    xCol/.estore in = \csvPlotXCol,%
    yCol/.estore in = \csvPlotYCol,%
    style/.estore in = \csvPlotStyle,%
    caption/.estore in = \csvPlotCaption,%
    label/.estore in = \csvPlotLabel,%
    align/.style = {alignments/#1/.get = \csvPlotAlignment},%
    % dictionary for alignment of figure
    alignments/.cd,%
        top/.initial = t,%
        here/.initial = h,%
        bottom/.initial = b,%
        force/.initial = H,%
        page/.initial = p,%
}

\newcommand{\csvPlotXY}[2][]{%
    \pgfkeys{/csvPlotXY, default, #1}%
    % Expand figure options
    \def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
        \centering
    \begin{tikzpicture}%
        \begin{groupplot} [
            width=\csvPlotWidth,%
            height=\csvPlotHeight,%
            % Plot loop: All x/y columns for multiple plots in one axis
            \csvPlotStyle,%
            ]%
            \def\tmpX{\pgfplotsforeachungrouped \x in }%
            \def\tmpY{\pgfplotsforeachungrouped \y in }%
            \expandafter\tmpX\expandafter{\csvPlotXCol} {%
                \expandafter\tmpY\expandafter {\csvPlotYCol} {%
                    \eappto\PlotList{%
                        \noexpand\nextgroupplot%
                        \noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
                        \noexpand\addlegendentry{\y}%
                    }%
                }%
            }%
            \PlotList%
        \end{groupplot}%
    \end{tikzpicture}%
        \caption{\csvPlotCaption}%
        \label{\csvPlotLabel}%
    \end{figure}
}%
\endinput

The output:

enter image description here

  • Thank you for your work and this solution! In the meantime I actually found a different way to solve the problem myself. Find it below. – elagil May 17 '17 at 13:58
1

I found a solution to the problem with the following expansion of the Macro, found in csvplot.sty. It probably does exactly the same thing as the answer above that came just before this one, which is to expand the Macro before use. However, this is done with different commands.

\newcommand{\csvPlotXY}[2][]{%
    \pgfkeys{\csvPlotXY, default, #1}%
    % Expand figure options
    \def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
        \centering
    \begin{tikzpicture}%
        \begin{groupplot} [
            width=\csvPlotWidth,%
            height=\csvPlotHeight,%
            % Plot loop: All x/y columns for multiple plots in one axis
            \csvPlotStyle,%
            ]%
            \edef\XIterate{%
                \noexpand\pgfplotsforeachungrouped \noexpand\x in {\csvPlotXCol}
            }
            \edef\YIterate{%
                \noexpand\pgfplotsforeachungrouped \noexpand\y in {\csvPlotYCol}
            }
            \XIterate {%
                \YIterate {%
                    \eappto\PlotList{%
                        \noexpand\nextgroupplot%
                        \noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
                        \noexpand\addlegendentry{\y}%
                    }%
                }%
            }%
            \PlotList%
        \end{groupplot}%
    \end{tikzpicture}%
        \caption{\csvPlotCaption}%
        \label{\csvPlotLabel}%
    \end{figure}
}%

Especially the definition of a temporary Macro with

\edef\XIterate{%
    \noexpand\pgfplotsforeachungrouped \noexpand\x in {\csvPlotXCol}
}

that is then called with \XIterate

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.