2

I am trying to plot a function that is the sum of another function based on the parameter.

A famous example of this is the "sum of squares", however the functions I really want to do this do not have an explicit formula.

The following example shows the result I would like to get and a method how I would like to have it, which is obviously not giving the correct result.

\documentclass[border=10]{standalone}

\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}

\begin{document}
  % Explicit formula
  \pgfmathdeclarefunction{explicit_sum}{1}{%
    \pgfmathparse{(#1*(#1-1))/2}%
  }

  % The inner function
  \pgfmathdeclarefunction{square}{1}{%
    \pgfmathparse{#1*#1}%
  }

  % Compute the sum of another function
  % Does not work...
  \pgfmathdeclarefunction{manual_sum}{1}{%
    %Parameter should be integral
    \pgfmathtruncatemacro\cnt{#1}
    \pgfmathsetmacro\ret{0}
    \foreach \i in {1,...,\cnt} {
      \pgfmathsetmacro\ret{\ret + sum(\i)}
    }
    \pgfmathparse{\ret}
  }

  \begin{tikzpicture}
    \begin{axis}
      % Expected
      \addplot[samples at={1,...,10}] {explicit_sum(x)};

      % Does not work
      \addplot[samples at={1,...,10}] {manual_sum(x)};
    \end{axis}    
  \end{tikzpicture}

\end{document}
  • Are you trying to accumulate a function value ? – percusse Feb 5 '16 at 22:16
  • Yes, I would like to accumulate a function for 1,...,#1 – kap Feb 5 '16 at 22:30
  • Well I think the \pgfmathparse needs to be inside the \foreach when I switch that the plot returns a straight line, I think the remaining issue is the same as found in Summation of a list of numbers. – Dai Bowen Sep 9 '16 at 22:30
3

If it is allowed to produce an "invisible" table to define the x values and then make the calculations in another column, then you could do the following.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
    % Explicit formula
    \pgfmathdeclarefunction{explicit_sum}{1}{%
        \pgfmathparse{(#1*(#1-1))/2}%
    }
    \pgfplotstableset{
        % define how the 'x' column shall be filled
        % (in this case just with integers counting from 1)
        create on use/x/.style={
            create col/set list={1,...,100}
        },
        % -----
        % now you can either create here a column with your function ...
        create on use/fx/.style={
            create col/expr={(\thisrow{x})^2}
        },
        % ... and then accumulate the values here ...
        create on use/sum/.style={
            create col/expr accum={
                \pgfmathaccuma + \thisrow{fx}
            }{0},       % <-- start with `0'
        },
        % -----
        % ... or you accumulate directly with the function
        create on use/sum2/.style={
            create col/expr accum={
                \pgfmathaccuma + (\thisrow{x})^2
            }{0},       % <-- start with `0'
        },
        % -----
    }
    % here you create a new table using the columns you need and
    % with the first mandatory argument you specify the number of elements
    % the table should have
    % (so either `sum2' is redundant or (`fx' and `sum') are redundant)
    \pgfplotstablenew[
        columns={x,fx,sum,sum2},
    ]{10}{\loadedtable}
\begin{document}
%    % maybe it is useful to typeset the table for debugging purposes
%    \pgfplotstabletypeset[
%        columns={x,fx,sum,sum2},
%    ]{\loadedtable}
    \begin{tikzpicture}
        \begin{axis}[
            % added for debugging purposes or here to quicker check,
            % it one gets the desired output
            nodes near coords,
        ]
        % Expected
        \addplot+[samples at={1,...,10}] {explicit_sum(x)};

        % when the table is created, you can use the columns here
        \addplot table [x=x,y=sum] {\loadedtable};
        \end{axis}
    \end{tikzpicture}
\end{document}

image showing the result of above code

3

TL; DR, the function declaration should be

  \pgfmathdeclarefunction{manual_sum}{1}{%
    \pgfmathfloattoint{#1}\let\cnt\pgfmathresult%
    \pgfmathsetmacro\ret{0}%
    \foreach\i in{1,...,\cnt}{%
      \pgfmathsetmacro\ret{\ret+\i}         % summing integer itself
     %\pgfmathsetmacro\ret{\ret+square(\i)} % general case
      \xdef\ret{\ret}%
    }%
    \pgfmathparse{\ret}%
  }

There are two problems in your code:

  • First, \foreach introduces nested grouping and \ret is trapped in the group.
  • Second, since activates FPU, the \pgfmathtruncatemacro\cnt{#1} will make \cnt be 1.
    • (This is in fact the flag of #1 in the FPU representation.)
    • (flag 1 stands for positive number.)

To come over the first obstacle, I usually use \xdef to smuggle the value. It is also worth noting that introduces \pgfplotsforeachungrouped, which is literally an ungrouped version of \foreach.

For the second obstacle, one needs to check the manual carefully and finds that \pgfmathfloattoint{#1}\let\cnt\pgfmathresult is the correct way to do the job.


this will bring you a curve that is different from the explicit_sum, and then you will realize that #1*(#1-1)/2 is not the correct formula.

  • +1 Nice one. This will be "magic" for me forever I think, but luckily there are people like you who know stuff like that. If I see it correct you are doing $\sum_i x_i$, right, but the question was: "Sum a function". Since OP declared the function square I think this was an example for a function. Could you modify your answer accordingly. (At least this I would be able to ;)) (OP himself wrote sum(\i) which most probably was an error, because \ret stores the sum, right? – Stefan Pinnow Oct 31 '16 at 6:59
  • @StefanPinnow Yes it is $\sum_i x_i$, indeed. I ignored square() because explicit_sum() is defined to be triangle numbers. (It would have been #1*(#1+1)*(2*#1-1)/6 for summing squares.) Nonetheless I added a commented line for summing squares. And right, \ret stores the sum. (I guess \ret stands for return.) – Symbol 1 Oct 31 '16 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.