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 \pgfplotsforeachinvoke
o \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:
escribir una macro que ensamble una lista de tokens de la forma deseada (aquí, concatena una serie de
\addplot
comandos con las opciones apropiadas);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}
,#1
reemplazada por la lista de tokens previamente ensamblada que contiene todos los\addplot
comandos.
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}
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 \addplot
comando).
El segundo argumento es lo que se insertará después de que el #1
interior haya sido reemplazado por los \addplot
comandos generados automáticamente.
El tercer argumento especifica el código para cada gráfico generado automáticamente, con algunos reemplazos convenientes:
#1
reemplazado con el nombre de la entrada (aquí:tabA
entoncestabB
);\myTable
reemplazado con el token de secuencia de control creado a partir del nombre de la entrada (aquí:\tabA
para la primera entrada,\tabB
para 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} }
Para las personas que no tienen\regex_replace_all:nnN
Si l3kernel
eres 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 \myTable
brackets 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} }