19

I am trying for teaching purpose to explain how basically linear regression might work and how it could be extended. Since I am not the TeXpert I fear that my idea might be tricky and more difficult than it probably can be. I have seen many nice plots with tikz and pgfplots.

I searched around and found finally the following image.

enter image description here

This image looks quite appropriate, cause I can explain how the regression might look like. But the problem is that I cannot manipulate, e.g. draw grid, change the naming of x_0 resp \epsilon, change the red line to a dotted one, add other points than P and Q, etc. If the function itself is x^2 or some mixture, I don't mind for explanation. My main objective is to illustrate the basic ideas. And if I would have a sample, then I could extend it little bit further to mean, variance, etc.

Is anybody willing to give me a helping hand? I don't mind if somebody could point me to existing samples. Would be fine as well.

4
  • 4
    Welcome to TeX.SX. Questions about how to draw specific graphics that just post an image of the desired result are really not reasonable questions to ask on the site. Please post a minimal compilable document showing that you've tried to produce the image and then people will be happy to help you with any specific problems you may have. See minimal working example (MWE) for what needs to go into such a document. Mar 28, 2014 at 21:13
  • 2
    If you are just getting started, try reading the Tikz manual. (That should kill a week or two.) Mar 28, 2014 at 21:31
  • OK, I'll try it, but this might be not within the next few days. Since it's not a nail-burning issue I have some time...
    – LeO
    Mar 28, 2014 at 21:33
  • See the first tutorial in the PGF-TikZ Manual: chapter 2 pag. 29 (for TikZ version 3.0): in there you will find almost everything you need to get started on your project.
    – Pier Paolo
    Mar 28, 2014 at 22:27

4 Answers 4

28
+300

With TikZ it is really easy. I used Plain TeX, so you will need to \input tikz.tex instead of \usepackage{tikz} and instead of \begin{document}...\end{document} you issue \bye at the end of your document.

Typeset the following code with pdftex

\input tikz.tex
\nopagenumbers% for cropping
\usetikzlibrary{arrows,intersections}
\tikzpicture[
        thick,
        >=stealth',
        dot/.style = {
            draw,
            fill=white,
            circle,
            inner sep=0pt,
            minimum size=4pt
        }
    ]
    \coordinate (O) at (0,0);
    \draw[->] (-0.3,0) -- (8,0) coordinate[label={below:$x$}] (xmax);
    \draw[->] (0,-0.3) -- (0,5) coordinate[label={right:$f(x)$}] (ymax);
    \path[name path=x] (0.3,0.5) -- (6.7,4.7);
    \path[name path=y] plot[smooth] coordinates {(-0.3,2) (2,1.5) (4,2.8) (6,5)};
    \scope[name intersections={of=x and y,name=i}]
        \fill[gray!20] (i-1) -- (i-2 |- i-1) -- (i-2) -- cycle;
        \draw (0.3,0.5) -- (6.7,4.7) node[pos=0.8,below right] {Sekante};
        \draw[red] plot[smooth] coordinates {(-0.3,2) (2,1.5) (4,2.8) (6,5)};
        \draw (i-1) node[dot,label={above:$P$}] (i-1) {} -- node[left] {$f(x_0)$} (i-1 |- O) node[dot,label={below:$x_0$}] {};
        \path (i-2) node[dot,label={above:$Q$}] (i-2) {} -- (i-2 |- i-1) node[dot] (i-12) {};
        \draw (i-12) -- (i-12 |- O) node[dot,label={below:$x_0 + \varepsilon$}] {};
        \draw[blue,<->] (i-2) -- node[right] {$f(x_0 + \varepsilon) - f(x_0)$} (i-12);
        \draw[blue,<->] (i-1) -- node[below] {$\varepsilon$} (i-12);
        \path (i-1 |- O) -- node[below] {$\varepsilon$} (i-2 |- O);
        \draw[gray] (i-2) -- (i-2 -| xmax);
        \draw[gray,<->] ([xshift=-0.5cm]i-2 -| xmax) -- node[fill=white] {$f(x_0 + \varepsilon)$}  ([xshift=-0.5cm]xmax);
    \endscope
\endtikzpicture
\bye

This will produce the following output (cropped)

enter image description here

As intersections are computed by the intersections library this solution is adaptive. In this code, not actually the point Q is moved, but one of the points on the red line, which causes Q to move (if you look closely you can see, that the red line gets an ugly bump while Q moves right).

My workflow for creating animations is the following:

  • Modify the source file, such that for each variation a seperate page in the output is created (in most cases using the PGF \foreach loop, like here)
  • Crop the resulting PDF using Heiko Oberdiek's pdfcrop.
  • Import the cropped PDF in GIMP.
  • In GIMP: Reverse the layer order and export as .gif with the option As Animation checked and a delay of 200 milliseconds (otherwise it is too fast for me).

The following contains the code used to create the animation. I marked the extra and modified lines needed in contrast to the above code.

\input tikz.tex
\nopagenumbers% for cropping
\usetikzlibrary{arrows,intersections}
\foreach \Q in {4,4.1,4.2,...,5,4.9,4.8,...,4.1} {%<-- added
\tikzpicture[
        thick,
        >=stealth',
        dot/.style = {
            draw,
            fill=white,
            circle,
            inner sep=0pt,
            minimum size=4pt
        }
    ]
    \coordinate (O) at (0,0);
    \draw[->] (-0.3,0) -- (8,0) coordinate[label={below:$x$}] (xmax);
    \draw[->] (0,-0.3) -- (0,5) coordinate[label={right:$f(x)$}] (ymax);
    \path[name path=x] (0.3,0.5) -- (6.7,4.7);
    \path[name path=y] plot[smooth] coordinates {(-0.3,2) (2,1.5) (\Q,2.8) (6,5)};%<-- modified
    \scope[name intersections={of=x and y,name=i}]
        \fill[gray!20] (i-1) -- (i-2 |- i-1) -- (i-2) -- cycle;
        \draw (0.3,0.5) -- (6.7,4.7) node[pos=0.8,below right] {Sekante};
        \draw[red] plot[smooth] coordinates {(-0.3,2) (2,1.5) (\Q,2.8) (6,5)};%<-- modified
        \draw (i-1) node[dot,label={above:$P$}] (i-1) {} -- node[left] {$f(x_0)$} (i-1 |- O) node[dot,label={below:$x_0$}] {};
        \path (i-2) node[dot,label={above:$Q$}] (i-2) {} -- (i-2 |- i-1) node[dot] (i-12) {};
        \draw (i-12) -- (i-12 |- O) node[dot,label={below:$x_0 + \varepsilon$}] {};
        \draw[blue,<->] (i-2) -- node[right] {$f(x_0 + \varepsilon) - f(x_0)$} (i-12);
        \draw[blue,<->] (i-1) -- node[below] {$\varepsilon$} (i-12);
        \path (i-1 |- O) -- node[below] {$\varepsilon$} (i-2 |- O);
        \draw[gray] (i-2) -- (i-2 -| xmax);
        \draw[gray,<->] ([xshift=-0.5cm]i-2 -| xmax) -- node[fill=white] {$f(x_0 + \varepsilon)$}  ([xshift=-0.5cm]xmax);
    \endscope
\endtikzpicture
\eject%<-- added
}%<-- added
\bye

enter image description here

3
  • I am completely kicked off my feet, since there are three great solutions and I have no real clue which one I like most... I am curious in your approach how the animated gif was created. Just for proper understanding of the graphic: You have the fixed linear regression and you start moving Q on that line toward infinity? Right? Cause the red curve adapts automatically. Would you mind to give a short hint in your code what to change that Q moves along the Sekante resp. what to do that Q moves along f(x)? Anyway, I highly appreciate....
    – LeO
    Mar 29, 2014 at 17:08
  • @LeO See my updated answer. Mar 29, 2014 at 20:32
  • Thx for the answer.
    – LeO
    Mar 30, 2014 at 14:36
24

My attempt with TikZ. Note that the code can probably be made more compact, but in an attempt to make it as easy to understand as possible, I chose to make it a little verbose.

\documentclass[tikz,border=3pt]{standalone}
\usepackage{tikz}

\usetikzlibrary{arrows,calc}

\begin{document}

\begin{tikzpicture}[>=stealth',
                    dot/.style={circle,draw,fill=white,inner sep=0pt,minimum size=4pt}]

    % draw axis lines
    \draw[->,thick] (-0.5,0) -- ++(11,0) node[below left]{$x$};
    \draw[->,thick] (0,-0.5) -- ++(0,7) node[below right]{$f(x)$};
    \coordinate (O) at (0,0);

    % create path for function curve
    \path[thick,red] (-0.3,2) to[out=-25, in=200] coordinate[pos=0.2] (p) coordinate[pos=0.6] (q) (9,5);
    % fill area
    \fill[blue, opacity=.1] (p) -| (q);
    % draw the secant line with fixed length
    \draw[shorten <=-1.5cm] (p) -- ($ (p)!7.5cm!(q) $) node[below right, pos=0.9]{Sekante};
    % draw function curve
    \draw[thick,red] (-0.3,2) to[out=-25, in=200] (9,5);

    % draw all points
    \node[dot,label={above:$P$}] (P) at (p) {};
    \node[dot,label={above:$Q$}] (Q) at (q) {};
    \node[dot] (p1) at (P |- O) {};
    \node[dot] (p2) at (Q |- O) {};
    \node[dot] (p3) at (P -| Q) {};

    % draw lines between nodes and place text
    \draw (P) -- node[left]{$f(x_{0})$} (p1) node[dot,label={below:$x_{0}$}]{};
    \draw (p2) node[dot,label={below:$x_{0} + \varepsilon$}]{} -- (p3);
    \path (p1) -- node[below]{$\varepsilon$} (p2);

    % draw blue arrows between nodes
    \draw[<->,blue,thick] (P) -- node[below]{$\varepsilon$} (p3);
    \draw[<->,blue,thick] (Q) -- node[right]{$f(x_{0} + \varepsilon) - f(x_{0})$} (p3);

    % draw the explanation for the y-value of point Q
    \draw[help lines] (Q) -- (Q -| {(9.5,0)}) ++(-0.5,0) coordinate (p4);
    \draw[help lines, <->] (p4) -- node[fill=white,text=black]{$f(x_{0} + \varepsilon)$} (p4 |- O);

\end{tikzpicture}

\end{document}

This gives the output

Output


For an animation that shows how the secant changes with different placements of the point Q along the fixed function curve, the following code should provide a starting point.

\documentclass[tikz,border=3pt]{standalone}
\usepackage{tikz}

\usetikzlibrary{arrows,calc}

\begin{document}

% create figures with different placement of Q along the function curve
\foreach \i in {0.45,0.46,...,0.72,0.71,0.70,...,0.46}{% <-- specify step

\begin{tikzpicture}[>=stealth',
                    dot/.style={circle,draw,fill=white,inner sep=0pt,minimum size=4pt}]

    % draw axis lines
    \draw[->,thick] (-0.5,0) -- ++(11,0) node[below left]{$x$};
    \draw[->,thick] (0,-0.5) -- ++(0,7) node[below right]{$f(x)$};
    \coordinate (O) at (0,0);

    % create path for function curve
    \path[thick,red] (-0.3,2) to[out=-25, in=200] coordinate[pos=0.2] (p) coordinate[pos=\i] (q) (9,5);
    % fill area
    \fill[blue, opacity=.1] (p) -| (q);
    % draw the secant line with fixed length
    \draw[shorten <=-1.5cm] (p) -- ($ (p)!7.5cm!(q) $) node[below right, pos=0.9]{Sekante};
    % draw function curve
    \draw[thick,red] (-0.3,2) to[out=-25, in=200] (9,5);

    % draw all points
    \node[dot,label={above:$P$}] (P) at (p) {};
    \node[dot,label={above:$Q$}] (Q) at (q) {};
    \node[dot] (p1) at (P |- O) {};
    \node[dot] (p2) at (Q |- O) {};
    \node[dot] (p3) at (P -| Q) {};

    % draw lines between nodes and place text
    \draw (P) -- node[left]{$f(x_{0})$} (p1) node[dot,label={below:$x_{0}$}]{};
    \draw (p2) node[dot,label={below:$x_{0} + \varepsilon$}]{} -- (p3);
    \path (p1) -- node[below]{$\varepsilon$} (p2);

    % draw blue arrows between nodes
    \draw[<->,blue,thick] (P) -- node[below]{$\varepsilon$} (p3);
    \draw[<->,blue,thick] (Q) -- node[right]{$f(x_{0} + \varepsilon) - f(x_{0})$} (p3);

    % draw the explanation for the y-value of point Q
    \draw[help lines] (Q) -- (Q -| {(9.5,0)}) ++(-0.5,0) coordinate (p4);
    \draw[help lines, <->] (p4) -- node[fill=white,text=black]{$f(x_{0} + \varepsilon)$} (p4 |- O);

\end{tikzpicture}
}

\end{document}

After compiling the output PDF to a GIF (100 ms per frame), the result is as follows

Animation

1
  • I am completely kicked off my feet, since there are three great solutions and I have no real clue which one I like most... What I really like in your code are the comments, cause I get a better idea what belongs to which art. Great :)
    – LeO
    Mar 29, 2014 at 17:09
15

Just for fun as usual with PSTricks.

\documentclass[pstricks,border=12pt,12pt]{standalone}
\usepackage{pst-plot,pst-eucl}
\def\f{(x-1)^2/5+1}
\def\L#1#2#3{\psCoordinates[linestyle=dashed](#1)\uput[-90](#1|0,0){$#2\mathstrut$}\uput[180](0,0|#1){$#3$}}
\begin{document}
\begin{pspicture}[algebraic,saveNodeCoors,NodeCoorPrefix=N](-2,-1)(7,5)
    \psaxes[labels=none,ticks=none]{->}(0,0)(-1,-1)(6.5,4.5)[$x$,0][$y$,90]
    \psplot[linecolor=red]{-1}{5}{\f}
    \pstGeonode[PosAngle=90](*1 {\f}){P}(*3.5 {\f}){Q}
    \psdot(Q|P)
    \pcline[nodesep=-2](P)(Q)
    \L{P}{x}{f(x)}
    \L{Q}{x+\varepsilon}{f(x+\varepsilon)}
    \pcline[linecolor=blue](P)(Q|P)\nbput{$\varepsilon$}
    \pcline[linecolor=blue](Q)(!NQx NPy)\naput{$f(x+\varepsilon)-f(x)$}
    \uput[-45]([nodesep=-1]{p}Q){secant}
    \uput[0](*5 {\f}){\textcolor{red}{$y=f(x)$}}
\end{pspicture}
\end{document}

enter image description here

1
  • I am completely kicked off my feet, since there are three great solutions and I have no real clue which one I like most... What I like in your solution is the somehow own approach how the graphic would look like. Which is different in tiny details, but anyway great to see it :)
    – LeO
    Mar 29, 2014 at 17:13
10

MetaPost and Asymptote are also very good at this sort of drawing. Here is an attempt with MetaPost, which uses the Metafun format. I've tried to reproduce the initial picture as far as possible, and to make it easy to adapt its parametrization at need. It's to be processed with mpost --mem=metafun --tex=latex file.mp (at least on Unix systems).

input latexmp; setupLaTeXMP(textextlabel=enable, mode=rerun);

vardef drawemptydot expr z = 
  save circle; path circle; circle = fullcircle scaled 3bp shifted z;
  unfill circle;
  draw circle;
enddef;

u := cm; % Unit length

beginfig(1);

xmin := -0.5; xmax := 9.5; ymin := -0.5; ymax := 6;

path curve; curve = (-0.5, 3.5){dir -30} .. (2.5, 2){dir 15} .. (5, 3.5) .. (8, 6){dir 30};

% Triangle and labels
z.P = point 1 of curve; z.Q = point 2 of curve; 
z.R = (x.Q, y.P); z.S = (x.P, 0); z.T = (x.Q, 0);
fill z.P--z.Q--z.R--cycle scaled u withcolor 0.9[blue, white];
%
drawoptions(withcolor blue);
drawdblarrow (z.P -- z.R) scaled u shortened 2bp;
drawdblarrow (z.R -- z.Q) scaled u shortened 2bp;
label.bot("$\varepsilon$", u*.5[z.P, z.R]);
label.rt("$f(x_0+\varepsilon) - f(x_0)$", u*.5[z.R, z.Q]);
%
drawoptions(withcolor black);
draw ((x.P, 0) -- z.P) scaled u;
draw ((x.Q, 0) -- z.R) scaled u;
draw (z.Q -- (xmax, y.Q)) scaled u;

% The curve
draw curve scaled u withcolor red;

% Axes
drawarrow (xmin*u, 0) -- (xmax*u, 0);
drawarrow (0, ymin*u) -- (0, ymax*u);
label.bot("$x$", (xmax*u, 0));
label.lft("$f(x)$", (0, ymax*u));

% Other labels
label.ulft("$P$", u*z.P);
label.ulft("$Q$", u*z.Q);
label.bot("$x_0$", u*z.S);
label.bot("$x_0+\varepsilon$", u*z.T);
label.bot("$\varepsilon$", u*(.5(x.P+x.Q), 0));
label.lft("$f(x_0)$", u*(.5[z.S, z.P]));

z.U = (0.8[x.Q, xmax], y.Q);
drawdblarrow ((x.U, 0) -- z.U) scaled u shortened .5bp;
picture yQ_label; yQ_label = thelabel("$f(x_0+\varepsilon)$", u*.5[(x.U, 0), z.U]);
unfill bbox yQ_label; draw yQ_label;

% Secante
path secante; secante = 1.8[z.Q, z.P] -- 2.5[z.P, z.Q] ;
draw secante scaled u;
label.lrt("Sekante", u*point .9 of secante);
forsuffixes M = P, Q, R, S, T:
  drawemptydot z.M scaled u;
endfor;

endfig;
end.

enter image description here

You must log in to answer this question.

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