6

I would like to perform the sum of some value inside a foreach cycle as in the following example:

\usepackage{amssymb} %maths
\usepackage{amsmath} %maths
\usepackage{booktabs}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{ifthen}
\usetikzlibrary{arrows.meta}
\usepackage[utf8]{inputenc} %utile per scrivere direttamente in caratteri accentuati
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\n}{5}
\draw[-Latex](0,0)--(\n+.5,0);
\draw[scale=1,domain=0:\n,smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\foreach \k in {0,...,10}
{
\pgfmathsetmacro{\x}{5*\k/10}
\pgfmathsetmacro{\Y}{exp(-\x)}
\pgfmathsetmacro{\y}{exp(-\x)+rand/3}
\pgfmathsetmacro{\diff}{\y-\Y}
\pgfmathsetmacro{\Diff}{100*(\y-\Y)}
\pgfmathsetmacro{\squareddiff}{abs(\diff^2)}
\fill[](\x,\y)circle(1pt);
\ifthenelse{0<\Diff}{\node[scale=.25,above]at(\x,\y+.1){$(x_{\k},y_{\k})$};
}{\node[scale=.25,below]at(\x,\y-.1){$(x_{\k},y_{\k})$};
}
\draw[dotted](\x,\y)--(\x,\Y);
\node[scale=.2]at(\x,-1.25){$y_{\k}-f(x_{\k})$};
\node[scale=.25]at(\x,-1.5){$\diff$};
\node[scale=.2]at(\x,-1.75){$(y_{\k}-f(x_{\k}))^2$};
\node[scale=.25]at(\x,-2){$\squareddiff$};
\node[]at(2.5,-3){$\sum\limits_{k}^n(y_k-f(x_k))^2=?$};
}
\end{tikzpicture}
\end{document}
  • Would you please complete your code snippet to a complete and compilable example? – muzimuzhi Z May 19 at 6:54
  • @muzimuzhiZ I added something..is it working? Sorry I used to compile with latexit and that's what is needed to compile there. I will provide an image as soon as it will be accepted by the server! – yngabl May 19 at 7:01
8

The problem is that the ordinary \foreach puts the stuff it is iterating over in groups. There are a few options:

  1. Use \pgfplotsforeachungrouped\k in{0,...,10} instead if you keep loading pgfplots.
  2. Make the macro for the sum global. Works but isn't great.
  3. Just use the ordinary \loop ... \repeat command. This has been used here to declare a pgf function sum.
  4. Use other tools.

This illustrates the third option explicitly.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta}
\usepackage[utf8]{inputenc} %utile per scrivere direttamente in caratteri accentuati
\begin{document}

\begin{tikzpicture}
% if you ever use the calc library you may want to avoid using `\n`, `\x` and 
% \y for macros but here it is fine.
\pgfmathsetmacro{\n}{5}
\draw[-Latex](0,0)--(\n+.5,0);
\draw[scale=1,domain=0:\n,smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\edef\k{0}
\edef\TotalSquareDiff{0}
\pgfmathsetseed{1}% so that others can cross check
\loop
\pgfmathsetmacro{\x}{5*\k/10}
\pgfmathsetmacro{\Y}{exp(-\x)}
\pgfmathsetmacro{\y}{exp(-\x)+rand/3}
\pgfmathsetmacro{\diff}{\y-\Y}
\pgfmathsetmacro{\Diff}{100*(\y-\Y)}
\pgfmathsetmacro{\squareddiff}{\diff*\diff}
\fill(\x,\y)circle[radius=1pt];
\ifdim0pt<\Diff pt\relax
\node[scale=.25,above]at(\x,\y+.1){$(x_{\k},y_{\k})$};
\else
\node[scale=.25,below]at(\x,\y-.1){$(x_{\k},y_{\k})$};
\fi
\draw[dotted](\x,\y)--(\x,\Y);
\node[scale=.2]at(\x,-1.25){$y_{\k}-f(x_{\k})$};
\node[scale=.25]at(\x,-1.5){$\diff$};
\node[scale=.2]at(\x,-1.75){$(y_{\k}-f(x_{\k}))^2$};
\node[scale=.25]at(\x,-2){$\squareddiff$};
\pgfmathsetmacro{\TotalSquareDiff}{\TotalSquareDiff+\squareddiff}%
\edef\k{\the\numexpr\k+1}
\ifnum\k<11
\repeat
\node at(2.5,-3){$\sum\limits_{k}^n(y_k-f(x_k))^2=\pgfmathprintnumber\TotalSquareDiff$};
\end{tikzpicture}
\end{document}

enter image description here

| improve this answer | |
  • Cool man. Thanks! Btw, are you alive, dead or both? – yngabl May 19 at 7:10
  • 5
    @yngabl This is not certain. ;-) – user194703 May 19 at 7:10
  • 2
    @yngabl there is also the [third option...] (goodreads.com/quotes/…) – Rmano May 19 at 7:59
  • Quantum physics can say Mass, but if the cat meows and draw with tikz, he is not dead. – Fran May 19 at 8:53
3

Here is a solution using remember and evaluate:

\documentclass{standalone}
\usepackage{amssymb} %maths
\usepackage{amsmath} %maths
\usepackage{booktabs}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{ifthen}
\usetikzlibrary{arrows.meta}
\usepackage[utf8]{inputenc} %utile per scrivere direttamente in caratteri accentuati
\begin{document}
\begin{tikzpicture}
  \pgfmathsetmacro{\n}{5}
  \draw[-Latex](0,0)--(\n+.5,0);
  \draw[scale=1,domain=0:\n,smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
  \foreach \k[
  evaluate=\k as \x using 5*\k/10,
  evaluate=\x as \Y using exp(-\x),
  evaluate=\x as \y using exp(-\x)+rand/3,
  evaluate=\y as \diff using \y-\Y,
  evaluate=\diff as \Diff using 100*\diff,
  evaluate=\diff as \squareddiff using (\diff)^2,
  remember=\totsd as \totsd (initially 0),                   % fake sum
  evaluate=\squareddiff as \totsd using \totsd+\squareddiff, % true sum
  ] in {0,...,10}
  {
    \fill[](\x,\y)circle(1pt);
    \pgfmathsetmacro\mypos{0<\Diff?"south":"north"}
    \node[scale=.25,anchor=\mypos]at(\x,{\y+(0<\Diff?+1:-1)*.1}){$(x_{\k},y_{\k})$};
    \draw[dotted](\x,\y)--(\x,\Y);
    \node[scale=.2]at(\x,-1.25){$y_{\k}-f(x_{\k})$};
    \node[scale=.25]at(\x,-1.5){$\diff$};
    \node[scale=.2]at(\x,-1.75){$(y_{\k}-f(x_{\k}))^2$};
    \node[scale=.25]at(\x,-2){$\squareddiff$};
    \node[scale=.18]at(\x,-2.25){$\sum\limits_{i=1}^{\k}(y_i-f(x_i))^2$};
    \node[scale=.25]at(\x,-2.5){$\totsd$};
  }
\end{tikzpicture}
\end{document}
| improve this answer | |
2

Here's with “other tools”. The macro \fpshow has an optional argument to use a certain number of decimal digits (rounded), default 2. Just to show the feature, I printed the sum of the squared differences rounded to four digits.

\documentclass{article}
\usepackage{amsmath} %maths
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{xparse,xfp}

\usepackage{ifthen}
\usetikzlibrary{arrows.meta}
\pgfplotsset{compat=1.17}

\ExplSyntaxOn
\NewDocumentCommand{\fpset}{mm}
 {
  \fp_if_exist:cF { l__yngabl_#1_fp } { \fp_new:c { l__yngabl_#1_fp } }
  \fp_set:cn { l__yngabl_#1_fp } { #2 }
 }
\NewExpandableDocumentCommand{\fpuse}{m}
 {
  \fp_use:c { l__yngabl_#1_fp }
 }
\NewExpandableDocumentCommand{\fpshow}{O{2}m}
 {
  \fp_eval:n { round(\fp_use:c { l__yngabl_#2_fp },#1) }
 }
\NewDocumentCommand{\xforeach}{mmm}
 {
  \cs_set:Nn \__ybgabl_xforeach:n { #3 }
  \int_step_function:nnN { #1 } { #2 } \__ybgabl_xforeach:n
 }
\NewExpandableDocumentCommand{\fpcompareTF}{mmm}
 {
  \fp_compare:nTF { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff


\begin{document}

\begin{tikzpicture}
\fpset{n}{5}
\draw[-Latex](0,0)--(\fpuse{n}+.5,0);
\draw[scale=1,domain=0:\fpuse{n},smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\fpset{total}{0}% initialize the total
\xforeach{0}{10}{
  \fpset{x}{5*\fpeval{#1/10}}
  \fpset{diff}{(-1)**randint(1,2)*rand()/3}
  \fpset{y}{exp(-\fpuse{x})}
  \fpset{sqdiff}{\fpuse{diff}*\fpuse{diff}}
  \fpset{total}{\fpuse{total}+\fpuse{sqdiff}}
  \fill[](\fpuse{x},\fpeval{\fpuse{y}+\fpuse{diff}}) circle(1pt);
  \fpcompareTF{\fpuse{diff}>0}
    { \node[scale=.25,above] at (\fpuse{x},\fpuse{y}+\fpuse{diff}+.1){$(x_{#1},y_{#1})$}; }
    { \node[scale=.25,below] at (\fpuse{x},\fpuse{y}+\fpuse{diff}-.1){$(x_{#1},y_{#1})$}; }
  \draw[dotted](\fpuse{x},\fpuse{y})--(\fpuse{x},\fpeval{\fpuse{y}+\fpuse{diff}});
  \node[scale=.2]at(\fpuse{x},-1.25){$y_{#1}-f(x_{#1})$};
  \node[scale=.25]at(\fpuse{x},-1.5){$\fpshow{diff}$};
  \node[scale=.2]at(\fpuse{x},-1.75){$(y_{#1}-f(x_{#1}))^2$};
  \node[scale=.25]at(\fpuse{x},-2){$\fpshow{sqdiff}$};
}
\node[]at(2.5,-3){$\displaystyle\sum_{k=0}^n(y_k-f(x_k))^2=\fpshow[4]{total}$};
\end{tikzpicture}

\end{document}

Advantages

  1. No group, but variables are set locally in the tikzpicture
  2. No risk to clobber existing macros
  3. Computations are made with 15 decimal digits

Disadvantages

  1. A bit more verbose
  2. Only “pure numbers” can be used

enter image description here

| improve this answer | |

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.