4

I am trying to make a plot more automatic and I am trying to impose the presence of samples near point of interest.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\alist(\Wmax)}
    \foreach \i in {(\Wmin):(0.5*1/#2),(0.5*1/#2):(2*1/#2),(2*1/#2):(0.5*1/#3),(0.5*1/#3):(2*1/#3),(2*1/#3):(\Wmax)}
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}

This is the MWE, it works. But I wanted to replace

    \foreach \i in {(\Wmin):(0.5*1/#2),(0.5*1/#2):(2*1/#2),(2*1/#2):(0.5*1/#3),(0.5*1/#3):(2*1/#3),(2*1/#3):(\Wmax)}
        \addplot [domain=\i,samples=50]

by

    \foreach \i in {\alist}
        \addplot [domain=\i,samples=50]

But it doesn't compile. The list creation comes from a code I found here, and it seems like \alist contains the good thing but I can't seem to use it in the foreach.

I see two things you could do if you wish to help me :

  • help me make the use of \alist work in \foreach (done)
    • answer 1 : change the expression \foreach \i in {\alist} to \foreach \i in \alist
    • answer 2 : use an array with \usepackage{listofitems} like so \readlist\alistlst{\alist}% \foreachitem\i\in\alistlst[]{%
  • find a simple way to generate the sampling like with samples at

Thank you in advance.

If you are curious about the result :

result of the plot

1
  • What is the purpose of \TracStack's 1st argument? (Seems #1 doesn't occur in \TracStack's definition.) May 5, 2021 at 15:47

4 Answers 4

3

Edit 1:

pgfmanual.pdf says about \foreach's ⟨list⟩-argument:

Again, in the easiest case, ⟨list⟩ is either a comma-separated list of values surrounded by curly braces or it is the name of a macro that contain such a list of values. Anything can be used as a value, but numbers are most likely.

The phrase "name of a macro that contain such a list of values" is sort of misleading but that statement means:

If ⟨list⟩ is something that is not nested between a pair of curly braces, then ⟨list⟩ is taken for a control-sequence whose toplevel-expansion forms the comma-separated list of values in question.

Therefore all you need to do is omitting the curly braces that surround \alist:
Just change the expression \foreach \i in {\alist} to \foreach \i in \alist.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\alist(\Wmax)}
    \foreach \i in \alist % <- curly braces surrounding \alist are omitted here.
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}

enter image description here


Previous answer:

One problem is that with \foreach \i in {\alist} the macro \alist is not expanded before \foreach is carried out.

Therefore \foreach won't take \alist's expansion, i.e., the token-sequence (\Wmin):(0.5*1/#2),(0.5*1/#2):(2*1/#2),(2*1/#2):(0.5*1/#3),(0.5*1/#3):(2*1/#3),(2*1/#3):(\Wmax) for its argument but will take the single token \alist for its argument.

You can apply \expandafter\PassFirstToSecond\expandafter{\alist}{\foreach...}-trickery for having \alist expanded before having \foreach carried out:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newcommand\PassFirstToSecond[2]{#2{#1}}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\alist(\Wmax)}
    \expandafter\PassFirstToSecond\expandafter{\alist}{\foreach \i in }%
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}

enter image description here

Another approach: In case \alist is just a scratch-macro put \noexpand\foreach \noexpand\i inside the last \xdef\alist, and then call \alist instead of \foreach:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\noexpand\foreach \noexpand\i in {\alist(\Wmax)}}
    \alist
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}

enter image description here

1
  • Thank you for your answer and even more for the second Edition
    – LMT-PhD
    May 5, 2021 at 17:50
4

Define:

\def\foreachinlist#1#2{\expandafter\foreachinlistA\expandafter#1\expandafter{#2}}
\def\foreachinlistA#1{\foreach#1in}

and use:

\foreachinlist \i \alist

In your example:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\def\foreachinlist#1#2{\expandafter\foreachinlistA\expandafter#1\expandafter{#2}}
\def\foreachinlistA#1{\foreach#1in}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\alist(\Wmax)}
    \foreachinlist \i \alist
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}
3

With a little help from listofitems:

\documentclass{standalone}
\usepackage{pgfplots,listofitems}
\pgfplotsset{compat=1.16}

\newcommand*{\TracStack}[4]{
    \gdef\alist{(\Wmin):}
    \foreach \i in {#2,#3} {
     \xdef\alist{\alist(0.5*1/\i),(0.5*1/\i):(2*1/\i),(2*1/\i):}
    }
    \xdef\alist{\alist(\Wmax)}
    \readlist\alistlst{\alist}% <-- READS \alist ITEMS INTO \alistlst LIST
    \foreachitem\i\in\alistlst[]{% <-- OPERATES ON SUCCESSIVE \alistlst ITEMS
        \addplot [domain=\i,samples=50]
        { 
            -(10*(log10(#2^2*x^2+1)))
            -(10*(log10(#3^2*x^2+1)))
        }[#4];
    }
}

\begin{document}
    \begin{tikzpicture} 
        \def\Wmax{10^(2)}
        \def\Wmin{10^(-1)}
        \begin{semilogxaxis}
        [ymin=-90,ymax=80]
        \TracStack{10}{10}{0.1}{}
        \TracStack{100}{5}{0.2}{red}
        \end{semilogxaxis}
    \end{tikzpicture}
\end{document}

enter image description here

5
  • Thank you for your answer, it answers my first point, even if I don't quite grasp the differences between \alist and \alistlst
    – LMT-PhD
    May 5, 2021 at 11:31
  • 1
    @LMT-PhD \alist is just a string filled with commas and data, whereas \alistlst is an array of separate elements. For example, the second element of the array is \alistlst[2], the fourth, \alistlst[4], which can be accessed independently. The \foreachitem syntax of the listofitems package (ctan.org/pkg/listofitems) provides the syntax to successively access each item of the list array. May 5, 2021 at 11:36
  • 1
    @LMT-PhD It seems the samples at data need not be looped. So, for example, if you can create a def, such as \def\z{.1, .2, .4, .8, 1.6, 3.2, 6.4, 12.8, 25.6, 51.2, 100}, then you can directly use \addplot [domain=\i,samples at=\z]{...}. Or are you asking how to create a sample for \alist? May 5, 2021 at 11:50
  • For samples at I'd like to be able generate the values to sample around the points of interest, in my example I impose more samples between X/2 and X*2 for each X of interest. But the values of Xs can change, and what happens if X*2 > X'/2, there might be an overlap.
    – LMT-PhD
    May 5, 2021 at 12:20
  • 1
    @LMT-PhD I don't do enough pgf/tikz work to fully grasp how to achieve your goal. But I would say this: if your axis is logarithmic, so should your samples, which is why, in my prior comment regarding \z, each sample point was based on a ratio to the prior value, rather than a delta from it. May 5, 2021 at 12:29
1

You can avoid all the \xdef business.

Here the name \foreachiinlist is completely arbitrary and its meaning will disappear as soon as the macro is executed. So you will have no \alist in the way any longer.

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\newcommand{\TracStackPoints}[1]{(0.5*1/#1),(0.5*1/#1):(2*1/#1),(2*1/#1):}

\newcommand*{\TracStack}[4]{%
  \begingroup
  \edef\foreachiinlist{%
    \endgroup
    \unexpanded{\foreach \i in }%
    {(\Wmin):\TracStackPoints{#2}\TracStackPoints{#3}(\Wmax)}%
  }%
  \foreachiinlist {
    \addplot [domain=\i,samples=50]
      { 
       -(10*(log10(#2^2*x^2+1)))
       -(10*(log10(#3^2*x^2+1)))
      }[#4];
  }%
}

\begin{document}

\begin{tikzpicture} 
  \def\Wmax{10^(2)}
  \def\Wmin{10^(-1)}
  \begin{semilogxaxis}[ymin=-90,ymax=80]
    \TracStack{10}{10}{0.1}{}
    \TracStack{100}{5}{0.2}{red}
  \end{semilogxaxis}
\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 .