Tenho algumas tabelas que quero ler e plotar, cada uma delas com seu estilo. Por uma questão de conveniência, gosto de usar as mesmas tags. Aqui está um 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}
Posso obter o mesmo resultado usando \pgfplotsforeachinvoke
ou \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}
É claro que neste caso simples eu poderia usar de forma simples
\addplot[#1] table[x=x,y=y] {#1.dat};
mas às vezes o nome do arquivo não segue um padrão ou outras vezes quero apenas ler e armazenar uma tabela para modificá-la ou reutilizá-la várias vezes.
Responder1
Bem-vindo ao TeX.SE! Uma coisa é sempre possível:
escrever uma macro que monte uma lista de tokens do jeito que você quiser (aqui, concatena uma série de
\addplot
comandos com opções apropriadas);em seguida, usando uma segunda macro (no meu código, construída a partir do segundo argumento de
\foreachTable
) que gera algo como\begin{axis}[...]#1\end{axis}
,#1
substituída pela lista de tokens montada anteriormente que contém todos os\addplot
comandos.
Esta técnicasempre funciona(depois que a segunda macro for expandida, o fluxo de entrada do TeX estará exatamente no mesmo estado como se você tivesse inserido todo o código manualmente). Você pode, portanto, usá-lo para gerar programaticamente tabelas, imagens, o que quiser.
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}
Explicação da chamada:
\foreachTable{tabA, tabB}
{
\begin{axis}[legend, legend pos=south east]
#1
\end{axis}
}
{ \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }
O primeiro argumento é a lista de entradas (cada entrada leva a um \addplot
comando).
O segundo argumento é o que será inserido após o #1
interior dele ter sido substituído pelos \addplot
comandos gerados automaticamente.
O terceiro argumento especifica o código para cada gráfico gerado automaticamente, com algumas substituições convenientes:
#1
substituído pelo nome da entrada (aqui:tabA
thentabB
);\myTable
substituído pelo token de sequência de controle construído a partir do nome da entrada (aqui:\tabA
para a primeira entrada,\tabB
para a segunda).
Se quiser adicionar manualmente mais gráficos (aqui, um antes e outro depois dos gerados automaticamente), você pode, por exemplo, fazer:
\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 pessoas que não têm\regex_replace_all:nnN
Se você l3kernel
for muito velho para ter \regex_replace_all:nnN
, você pode:
acrescentar
\cs_generate_variant:Nn \tl_replace_all:Nnn { Nno }
antes\cs_new_protected:Npn \millo_foreach_table_do_axis:nNn #1#2#3
;substitua a linha
\regex_replace_all:nnN { \c{myTable} } { \c{##1} } \l_tmpa_tl
com
\exp_args:NNno \tl_replace_all:Nno \l_tmpa_tl { \myTable } { \use:c {##1} }
Então deve funcionarna condiçãoque você não usa \myTable
aparelho interno. Por exemplo, use
\foreachTable{tabA, tabB}
{
...
}
{ \addplot[#1] table[x=x,y=y] \myTable; \addlegendentry{#1} }
em vez de:
\foreachTable{tabA, tabB}
{
...
}
{ \addplot[#1] table[x=x,y=y] {\myTable}; \addlegendentry{#1} }