2

I found these neat little additions here, but I'm having a hard time reading the code:

\makeatletter
\def\pgfplotsutil@decstringcounter#1{%
    \begingroup
        \c@pgf@counta=#1\relax
        \advance\c@pgf@counta by -1
        \edef#1{\the\c@pgf@counta}%
        \pgfmath@smuggleone#1%
    \endgroup
}%

\pgfplotsset{
    /pgfplots/each nth point**/.style 2 args={%
        /pgfplots/x filter/.append code={%
            \ifnum\coordindex=0
                \def\c@pgfplots@eachnthpoint@xfilter{#2}%
                \def\c@pgfplots@eachnthpoint@xfilter@zero{0}%
            \fi
            \ifx\c@pgfplots@eachnthpoint@xfilter@zero\c@pgfplots@eachnthpoint@xfilter
                \def\c@pgfplots@eachnthpoint@xfilter{#1}%
            \else
                \let\pgfmathresult\pgfutil@empty
            \fi
            \pgfplotsutil@decstringcounter\c@pgfplots@eachnthpoint@xfilter
        }%
    },
}

\pgfplotsset{
    /pgfplots/each nth point*/.style 2 args={%
        /pgfplots/x filter/.append code={%
            \ifnum\coordindex=0
                \def\c@pgfplots@eachnthpoint@xfilter{0}%
                \edef\c@pgfplots@eachnthpoint@xfilter@cmp{#1}%
            \else
                \ifnum\coordindex>#2\relax
                    \pgfplotsutil@advancestringcounter\c@pgfplots@eachnthpoint@xfilter
                    \ifx\c@pgfplots@eachnthpoint@xfilter@cmp\c@pgfplots@eachnthpoint@xfilter
                        \def\c@pgfplots@eachnthpoint@xfilter{0}%
                    \else
                        \let\pgfmathresult\pgfutil@empty
                    \fi
                \fi
            \fi
        }%
    },
}
\makeatother

I'm familiar with the use of \makeatletter and \makeatother and I'm familiar with programming concepts, but this syntax always gives me trouble.

  1. Does each nth point** shift the plotted points vertically?

  2. I know in general that each nth point* plots every point at the beginning, then starts plotting every nth point after a specified number of data points.

    a. Does the first if plot the first coordinate and then redefine a variable for the remainder of the data points? Using the first argument?

    b. Does the first if inside the first else activate when the data point corresponding to the second argument is reached?

    c. Is the rest of the code just from the normal each nth point code, with the nested else throwing out/not plotting the point for any index that gets there?

There is a point (no pun intended) to this exercise. I'd like to alter every nth point* so that it will take 3 arguments instead of two (I presume /.style 2 args= becomes /.style 3 args=) so it can plot every nth point except for a certain region (arg2 < x < arg3) in which every point will be plotted.

3
  • For the final part, there's no /.style 3 args= for more than two arguments there's /.style n args=. Mar 10, 2015 at 16:06
  • @GonzaloMedina oh okay, how do i specify that i'd like 3 arguments instead of more? Mar 10, 2015 at 17:55
  • 1
    You use /.style n args={3}{code with #1 #2 #3}. Mar 10, 2015 at 20:34

1 Answer 1

5

I've added some comments for the code given. The first part is an overkill for my taste though. It is just a function to decrease a counter value and the argument is a number. Same can be easily done by other means but anyways.

\makeatletter
\def\pgfplotsutil@decstringcounter#1{%
    \begingroup% Standard scoping for the actions
        \c@pgf@counta=#1\relax% Equate the temp TikZ counter to #1
        \advance\c@pgf@counta by -1% Decrease the temp TikZ counter by 1
        \edef#1{\the\c@pgf@counta}%Redefine the argument #1
        \pgfmath@smuggleone#1% Make sure the argument has this meaning after the scope ends.
    \endgroup% End scoping
}%

Then we have a slightly more involved one

\pgfplotsset{
    /pgfplots/each nth point**/.style 2 args={%A style def that takes 2 arguments
        /pgfplots/x filter/.append code={%Add the following code to the existing key code
            \ifnum\coordindex=0% Obvious! 
% If true define the following two counters as such (but they are not actual TeX counters!)
                \def\c@pgfplots@eachnthpoint@xfilter{#2}%
                \def\c@pgfplots@eachnthpoint@xfilter@zero{0}%
            \fi% End of if
% Here it is again a bit I-wouldn't-do-that code. Compares the values of two "counters".
% What is implemented here is simply taking a Mod(myvalue,n) is zero? op. 
% If yes then Reset the "counter" to n and don't touch \pgfmathresult (point is passed)
% If no empty \pgfmathresult so (point is discarded)
            \ifx\c@pgfplots@eachnthpoint@xfilter@zero\c@pgfplots@eachnthpoint@xfilter
                \def\c@pgfplots@eachnthpoint@xfilter{#1}%
            \else
                \let\pgfmathresult\pgfutil@empty
            \fi
% Decrease the coord count by 1 and done. Hence next the  "obvious" \ifnum is skipped
            \pgfplotsutil@decstringcounter\c@pgfplots@eachnthpoint@xfilter
        }%
    },
}

Now to the single starred version (I skipped the similar parts)

\pgfplotsset{
    /pgfplots/each nth point*/.style 2 args={%
        /pgfplots/x filter/.append code={% Same
            \ifnum\coordindex=0% Same 
                \def\c@pgfplots@eachnthpoint@xfilter{0}% Same
                \edef\c@pgfplots@eachnthpoint@xfilter@cmp{#1}% Same
            \else% Same 
                \ifnum\coordindex>#2\relax% If we passed a certain coordinate num
% We don't have the def on the next macro but naming is obvious
% It is very similar to the above but this time the counter is increased from 0 to n
                    \pgfplotsutil@advancestringcounter\c@pgfplots@eachnthpoint@xfilter
% If the comparator value and the actual counter is equal?
                    \ifx\c@pgfplots@eachnthpoint@xfilter@cmp\c@pgfplots@eachnthpoint@xfilter%
% Yes reset the counter and don't touch \pgfmathresult (point is passed)
                        \def\c@pgfplots@eachnthpoint@xfilter{0}%
                    \else    
% No empty and point is discarded
                        \let\pgfmathresult\pgfutil@empty
                    \fi% 
                \fi%
            \fi%
        }%
    },
}
\makeatother

I think this is a very convoluted way of doing things. Following does the same, with three arguments as you asked for. You can remove the comments to go back to the compact version.

\documentclass{standalone}
\usepackage{pgfplots}
\makeatletter
\pgfplotsset{
my filter/.style args={every#1between#2and#3}{%
/pgfplots/x filter/.append code={%
\ifnum\coordindex<#2%
  % Nothing
\else% Did we pass #3?
  \ifnum\coordindex>#3%
    %Nothing
  \else% Ok filter is on, don't disturb \pgfmathresult for convenience
    \pgfmathsetmacro\temp{int(mod(\coordindex,#1))}%
    \ifnum0=\temp\relax% Are we on the nth point?
      % Yes do nothing let it pass
    \else% discard it
      \let\pgfmathresult\pgfutil@empty
    \fi%
  \fi%
\fi%
}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}[my filter=every 50 between 700 and 1000]
% If works properly we should see some ragged part among the smooth part
\addplot[samples=1501] {sin(deg(5*x))};
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

5
  • this looks awesome, let me try to see if i can figure it out. i actually need the opposite, what i meant by 'so it can plot every nth point except for a certain region (arg2 < x < arg3) in which every point will be plotted' was ragged everywhere except a smooth part in the middle Mar 10, 2015 at 21:32
  • i'll accept this one, i just ended up asking this as a follow up question here Mar 10, 2015 at 23:12
  • 1
    This is awesome! (Getting close to the ideal: a "dynamic" each nth point option!)
    – Bibi
    Feb 3, 2016 at 9:22
  • @Bibi You can use the same key more than once ;)
    – percusse
    Feb 3, 2016 at 9:28
  • Hmm... This is AWESOME! ;)
    – Bibi
    Feb 3, 2016 at 9:43

You must log in to answer this question.

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