2

When plotting and iterating through a list of filenames, I wanted to call them from a switch-code and apply them in \addplot. I used the switch-function \IfEqCase from the xstring package. However, the filenames contained underscores which caused compilation error Missing $ inserted, i.e. the underscore is interpreted as math mode even though this was inside the file address parameter of \addplot. I wonder: How can I call a filename with underscore from a switch-case (like \IfEqCase, but doesn't have to be that function) into the addplot parameter?

The bits to look for in the code: the new command \getFilename that calls \IfEqCase and is applied in the plotting: \addplot table {\getFilename{\i}}.

The code:

% !TeX program = lualatex
\documentclass[tikz,border=10pt]{standalone}
\usepackage{xstring}% for \IfEqCase
\usepackage{pgfplots}
\pgfplotsset{compat=1.17} 

\newenvironment{standalonepage}{}{}  
\standaloneenv{standalonepage} 

\begin{filecontents}{file_1_someInfo.csv}
    1,1
    2,2
    3,3
\end{filecontents}
\begin{filecontents}{file_2_someOtherInfo.csv}
    1,4
    2,5
    3,6
\end{filecontents}

\newcommand{\getFilename}[1]{ 
    \IfEqCase{#1}{ 
        {1}{file_1_someInfo}
        {2}{file_2_someOtherInfo}
    }[\PackageError{filename}{Undefined option to filename of file #1}{}]
}

\begin{document}
    \begin{standalonepage}
        \begin{tikzpicture}
            \begin{axis}
                \foreach \i in {1,2}{ 
                    \addplot+ table [x index=0,y index=1,col sep=comma] 
                         {\getFilename{\i}}; 
                    \edef\temp{\noexpand\addlegendentry{file no. \i};}
                    \temp
                };
            \end{axis}
        \end{tikzpicture}
    \end{standalonepage}
\end{document}

Attempts of fixing it, that failed

I have tried \catcode (as suggested whenever a text with underscore is fed into a newcommand's parameter) to change the category of the code:

\newcommand{\getFilename}[1]{\begingroup
    \catcode`_=12 \getthelist{#1}}
\newcommand{\getthelist}[1]{ 
    \IfEqCase{#1}{%krever package xstring
        {1}{file_1_someInfo}
        {2}{file_2_someOtherInfo}
    }[\PackageError{filename}{Undefined option to filename of file #1}{}]%
    \endgroup
} 

This results in the error Missing $ inserted.

The problem seem to be with the \IfEqCase, because the code works (no errors and the figure is plotted) if I rather define the command:

\newcommand{\getFilename}[1]{Folder_1_extraInfo}

but then I cannot iterate through the files.

I also tried to apply \IfEqCase directly into \addplot:

            \begin{axis}
                \foreach \i in {1,2}{ 
                    \addplot+ table [x index=0,y index=1,col sep=comma]     {\IfEqCase{\i}{ 
                            {1}{file_1_someInfo}
                            {2}{file_2_someOtherInfo}
                        }[\PackageError{filename}{Undefined option to filename of file #1}{}]
                    }; 
                    \edef\temp{\noexpand\addlegendentry{file no. \i};}
                    \temp
                };
            \end{axis}

but that resulted in the error Illegal parameter number in definition of \pgffor@body.

1
  • xstring functions are not expandable and can not be nested in tha way Feb 25, 2022 at 18:16

2 Answers 2

2

The usual problem: \IfEqCase returns instructions to print the result, not the result itself.

Here's an expandable version using expl3.

\begin{filecontents}{file_1_someInfo.csv}
    1,1
    2,2
    3,3
\end{filecontents}
\begin{filecontents}{file_2_someOtherInfo.csv}
    1,4
    2,5
    3,6
\end{filecontents}

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17} 

\ExplSyntaxOn
\NewExpandableDocumentCommand{\getFilename}{m}
  {
    \str_case_e:nnF {#1}
      { 
        {1}{file_1_someInfo}
        {2}{file_2_someOtherInfo}
      }
      {\PackageError{filename}{Undefined~option~to~filename~of~file~#1}}
    .csv
}
\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
  \begin{axis}
    \foreach \i in {1,2}{ 
      \addplot+ table [x index=0,y index=1,col sep=comma] {\getFilename{\i}}; 
      \expanded{\noexpand\addlegendentry{file no. \i}}
    }
  \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

I leave to you to make the legend not covering the data.

1
  • Thank you very much. That was exactly what I was looking for. Feb 28, 2022 at 11:41
1

Here is an alternative solution with functional package by using \prgRunTwoArgCode command.

\documentclass{article}

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

\begin{filecontents*}[overwrite]{file_1_someInfo.csv}
    1,1
    2,2
    3,3
\end{filecontents*}
\begin{filecontents*}[overwrite]{file_2_someOtherInfo.csv}
    1,4
    2,5
    3,6
\end{filecontents*}

\usepackage{functional}

\IgnoreSpacesOn
\prgNewFunction \GetFileName {m} {
  \strCaseF {#1} {
    {1}{\prgReturn{file_1_someInfo}}
    {2}{\prgReturn{file_2_someOtherInfo}}
  }
  {\PackageError{filename}{Undefined~option~to~filename~of~file~#1}}
}
\IgnoreSpacesOff

\begin{document}

\begin{tikzpicture}
  \begin{axis}
    \foreach \i in {1,2}{
      \prgRunTwoArgCode {\GetFileName{\expWhole{\i}}} {\expWhole{\i}} {
        \addplot+ table [x index=0,y index=1,col sep=comma] {##1.csv};
        \addlegendentry{file no. ##2};
      }
    }
  \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

You must log in to answer this question.

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