Para las personas que no tienen\regex_replace_all:nnN

Para las personas que no tienen\regex_replace_all:nnN

Tengo algunas tablas que quiero leer y trazar, cada una con su propio estilo. Por conveniencia, me gusta usar las mismas etiquetas. Aquí hay un MWE:

\documentclass{minimal}

\usepackage{pgfplotstable}

\begin{filecontents}{tabA.dat}
x   y
0   0
1   1
2   2
3   3
\end{filecontents}
\begin{filecontents}{tabB.dat}
x   y
0   1
1   2
2   3
3   4
\end{filecontents}

\pgfplotsset{compat=newest,
tabA/.style={color=red,mark=*},
tabB/.style={color=black,mark=o},
}

\pgfplotstableread{tabA.dat}\tabA
\pgfplotstableread{tabB.dat}\tabB

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[legend,legend pos=south east]
            \addplot[tabA] table[x=x,y=y] {\tabA};\label{pgf:tabA}\addlegendentry{tabA}
            \addplot[tabB] table[x=x,y=y] {\tabB};\label{pgf:tabB}\addlegendentry{tabB}
        \end{axis}
    \end{tikzpicture}

\end{document}

¿Puedo lograr el mismo resultado usando \pgfplotsforeachinvokeo \foreach? Algo como

\begin{tikzpicture}
    \begin{axis}[legend,legend pos=south east]
        \pgfplotsinvokeforeach{tabA,tabB}{%
            % The following doesn't work, of course
            \addplot[#1] table[x=x,y=y] {\#1}; % <- Magic goes here 
        }
    \end{axis}
\end{tikzpicture}

Por supuesto, en este caso simple podría usar simplemente

\addplot[#1] table[x=x,y=y] {#1.dat};

pero a veces el nombre del archivo no sigue un patrón u otras veces solo quiero leer y almacenar una tabla para poder modificarla o reutilizarla varias veces.

Respuesta1

¡Bienvenido a TeX.SE! Siempre es posible una cosa:

  1. escribir una macro que ensamble una lista de tokens de la forma deseada (aquí, concatena una serie de \addplotcomandos con las opciones apropiadas);

  2. luego, uso una segunda macro (en mi código, construida a partir del segundo argumento de \foreachTable) que genera algo como \begin{axis}[...]#1\end{axis}, #1reemplazada por la lista de tokens previamente ensamblada que contiene todos los \addplotcomandos.

Esta tecnicasiempre funciona(Una vez que se ha expandido la segunda macro, el flujo de entrada TeX está exactamente en el mismo estado que si hubiera ingresado todo el código manualmente). Por lo tanto, puedes usarlo para generar tablas, imágenes, lo que quieras mediante programación.

Código completo:

\begin{filecontents}{tabA.dat}
x   y
0   0
1   1
2   2
3   3
\end{filecontents}

\begin{filecontents}{tabB.dat}
x   y
0   1
1   2
2   3
3   4
\end{filecontents}

\documentclass[tikz, border=2mm]{standalone}
\usepackage{xparse}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\ExplSyntaxOn
\seq_new:N \l__millo_plot_cmds_tl

\cs_new_protected:Npn \millo_foreach_table_do_axis:nNn #1#2#3
  {
    \tl_clear:N \l__millo_plot_cmds_tl
    \clist_map_inline:nn {#1}
      {
        \tl_set:Nn \l_tmpa_tl {#3}
        \regex_replace_all:nnN { \c{myTable} } { \c{##1} } \l_tmpa_tl
        \tl_put_right:NV \l__millo_plot_cmds_tl \l_tmpa_tl
      }

    \exp_args:No #2 \l__millo_plot_cmds_tl
  }

\NewDocumentCommand \foreachTable { m m m }
  {
    \cs_set_protected:Npn \__millo_axis_func:n ##1 {#2}
    \millo_foreach_table_do_axis:nNn {#1} \__millo_axis_func:n {#3}
  }
\ExplSyntaxOff

\pgfplotsset{
  tabA/.style={color=red,mark=*},
  tabB/.style={color=black,mark=o},
}

\pgfplotstableread{tabA.dat}\tabA
\pgfplotstableread{tabB.dat}\tabB

\begin{document}

\begin{tikzpicture}
  \foreachTable{tabA, tabB}
    {
      \begin{axis}[legend, legend pos=south east]
        #1
      \end{axis}
    }
    { \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }
\end{tikzpicture}

\end{document}

captura de pantalla

Explicación de la convocatoria:

\foreachTable{tabA, tabB}
  {
    \begin{axis}[legend, legend pos=south east]
      #1
    \end{axis}
  }
  { \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }

El primer argumento es la lista de entradas (cada entrada conduce a un \addplotcomando).

El segundo argumento es lo que se insertará después de que el #1interior haya sido reemplazado por los \addplotcomandos generados automáticamente.

El tercer argumento especifica el código para cada gráfico generado automáticamente, con algunos reemplazos convenientes:

  • #1reemplazado con el nombre de la entrada (aquí: tabAentonces tabB);

  • \myTablereemplazado con el token de secuencia de control creado a partir del nombre de la entrada (aquí: \tabApara la primera entrada, \tabBpara la segunda).

Si desea agregar manualmente más gráficos (aquí, uno antes y otro después de los generados automáticamente), puede, por ejemplo, hacer:

\foreachTable{tabA, tabB}
  {
    \begin{axis}[legend, legend pos=south east]
      \addplot {sin(deg(\x))}; \addlegendentry{$\sin$}
      #1
      \addplot {sqrt(\x)};     \addlegendentry{$x\mapsto \sqrt{x}$}
    \end{axis}
  }
  { \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }

ingrese la descripción de la imagen aquí

Para las personas que no tienen\regex_replace_all:nnN

Si l3kerneleres demasiado mayor para tenerlo \regex_replace_all:nnN, puedes:

  • añadir \cs_generate_variant:Nn \tl_replace_all:Nnn { Nno }antes \cs_new_protected:Npn \millo_foreach_table_do_axis:nNn #1#2#3;

  • reemplazar la línea

    \regex_replace_all:nnN { \c{myTable} } { \c{##1} } \l_tmpa_tl
    

    con

    \exp_args:NNno
    \tl_replace_all:Nno \l_tmpa_tl { \myTable } { \use:c {##1} }
    

Entonces debería funcionaren la condiciónque no uses \myTablebrackets internos. Por ejemplo, utilice

\foreachTable{tabA, tabB}
  {
    ...
  }
  { \addplot[#1] table[x=x,y=y] \myTable; \addlegendentry{#1} }

en lugar de:

\foreachTable{tabA, tabB}
  {
    ...
  }
  { \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }

información relacionada