# Plotting a curve with given values and derivative values

Is there a way, using TikZ, to plot a smooth curve satisfying

f( 0) = -1,   f'( 0) =  0
f( 2) =  2,   f'( 2) = -1
f(-2) = -1,   f'(-2) =  1


Of course, I could find a polynomial satisfying the given conditions, but I'd rather just feed the conditions to TikZ and let it do the work.

-
Although you can probably get a smooth curve, it probably isn't going to be the polynomial you want. –  Peter Grill Feb 16 '12 at 16:26
@PeterGrill I don't want any specific polynomial, just a smooth curve with the given properties. It's a standard calculus problem: "on the graph given, sketch a curve with the following properties". I'm typing up solutions. –  Quinn Culver Feb 16 '12 at 19:24
Yes, but in standard calculus problems one is trying to find a polynomial or some combination of known functions that fit the requirements. The solutions here will produce a smooth curve which is one of infinitely many solutions. –  Peter Grill Feb 16 '12 at 19:27
@PeterGrill I'm telling you exactly what the problem says. The students, too, have infinitely many correct options, since they only have to "sketch a curve". –  Quinn Culver Feb 17 '12 at 0:29

As Peter commented the curve that you define is not unique. If this is not a problem then you can use the control points for the curve generation by giving tangent specifications at points that you would like. I tried to sketch a little bit how the mechanism works in this answer.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw[style=help lines] (-3,-3) grid[step=1cm] (3,3);
\node (O) at (0,0) {0};
\draw[thick] (-3,0) -- (3,0) (0,-3) -- (0,3);
\draw (-2,-1) node[below] {$f(-2)$}.. controls (-1,0) and (-1,-1)  .. (0,-1) %
node[below right] {$f(0)$}.. controls ++(1,0) and (1,3) .. (2,2)node[below] {$f(2)$};
\end{tikzpicture}
\end{document}


You can further play around with the control points' distance (by keeping the direction constant) to the defined points to increase the contribution of that control point.

-

This solution is similar to that by @percusse and @Altermundus in that control points are computed using the slope at the given points. One small benefit of the method proposed here is that it is extensible to more than just three points, and at each point a unique value of <delta x> can be specified so that one can have more control the behavior at that point

To start the curve use

\ExtrapolateStart{<delta x>}{<x>}{<y>}{<y'>}


All the points following (except the last) are specified with

\Extrapolate{<delta x>}{<x>}{<y>}{<y'>}


and the last point is specified with

\ExtrapolateEnd{<delta x>}{<x>}{<y>}{<y'>}


Here is the output with various settings:

The control points are shown in blue for debugging purposes, but that part of the code can be commented out if that is not needed.

Here is an example where the x, y, and y' values are specified for 5 points with:

    \ExtrapolateStart{\DeltaXStart}{-2}{0}{3.0}% delta x, x, y, y'
\Extrapolate{\DeltaXMiddle}{-1}{2}{1}
\Extrapolate{\DeltaXMiddle}{0}{1}{-2}
\Extrapolate{\DeltaXMiddle}{1}{-1}{-0.5}
\ExtrapolateEnd{\DeltaXEnd}{2}{1}{2.0}


## Notes:

• While I was trying to come up with a decent graphs for the 5 point solution I observed various kinks in the lines, but now am no longer able to reproduce that problem. Not sure how this problem was magically fixed. The only thing I can think of is that perhaps the values I was providing for the coordinates and the derivative did not make sense and hence resulted in the strange graphs, but this needs further investigation.

## Code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\ExtrapolateStart}[4]{%
($(#2,#3)-(#1, #1*#4)$) --%
(#2,#3) .. controls%
($(#2,#3)+(#1, #1*#4)$)%
}%
\newcommand{\Extrapolate}[4]{%
and%
($(#2,#3)-(#1, #1*#4)$) ..%
(#2,#3) .. controls%
($(#2,#3)+(#1, #1*#4)$)%
}%

\newcommand{\ExtrapolateEnd}[4]{%
and%
($(#2,#3)-(#1, #1*#4)$) ..%
(#2,#3) --%
($(#2,#3)+(#1, #1*#4)$)%
}%

%--------- For debugging use only
\newcommand{\ShowPoints}[4]{%
\filldraw [blue, opacity=0.5]%
(#2,#3) circle (2pt)%
($(#2,#3)-(#1, #1*#4)$)  circle (1pt) --%
($(#2,#3)+(#1, #1*#4)$)  circle (1pt)%
}%

\node [draw,shape=rectangle,fill=white,#1] at (-1,2.5)  {#2};
}

%
\begin{document}
\noindent
Example using 3 points where $x$, $f(x)$ and $f^\prime(x)$ are given for various $\Delta x$:
\bigskip\par\noindent
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.5}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;

% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXMiddle$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{1.0}%
\newcommand*{\DeltaXMiddle}{1.0}%
\newcommand*{\DeltaXEnd}{1.0}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;

% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXMiddle$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.4}%
\newcommand*{\DeltaXMiddle}{1.0}%
\newcommand*{\DeltaXEnd}{0.6}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;

% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}

\newpage\noindent
Example using 5 points where $x$, $f(x)$ and $f^\prime(x)$ are given:
\bigskip
\par\noindent
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.3}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{0}{3.0}
\Extrapolate{\DeltaXMiddle}{-1}{2}{1}
\Extrapolate{\DeltaXMiddle}{0}{1}{-2}
\Extrapolate{\DeltaXMiddle}{1}{-1}{-0.5}
\ExtrapolateEnd{\DeltaXEnd}{2}{1}{2.0}
}
\draw [ultra thick, red, smooth] \MyPath;

% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{0}{3.0};
\ShowPoints{\DeltaXMiddle}{-1}{2}{1};
\ShowPoints{\DeltaXMiddle}{0}{1}{-2};
\ShowPoints{\DeltaXMiddle}{1}{-1}{-0.5};
\ShowPoints{\DeltaXEnd}{2}{1}{2.0};
%
\AddLabel[xshift=2cm]{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.3}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{-1}{-2}{0}
\Extrapolate{\DeltaXMiddle}{0}{1.5}{0}
\Extrapolate{\DeltaXMiddle}{1}{-2}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-2}
}
\draw [ultra thick, red, smooth] \MyPath;

% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{-1}{-2}{0};
\ShowPoints{\DeltaXMiddle}{0}{1.5}{0};
\ShowPoints{\DeltaXMiddle}{1}{-2}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-2};
%
\AddLabel{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}
\end{document}

-

I think it is much better to use MetaPost or Asymptote to draw the curve. They provide direction curve specifier ({dir}) to obtain proper splines. TikZ is not good at interpolation and curve fitting. The algorithm used by MetaPost and Asymptote is too complex for pure TeX drawing packages.

An Asymptote example,

unitsize(2cm);
draw ( (-2,-1) {(1,1)} .. (0,-1) {(1,0)} .. (2,2) {(1,-1)} );
dot((0,-1) ^^ (2,2) ^^ (-2,1));


Here, specifier {(1,1)} after (-2,1) means the direction of tangent is (1,1), i.e. (1,f'(x)).

And it is easy to define a function to generalize the method:

unitsize(2cm);

// points should be sorted by x
guide fit_curve(pair[] points, real[] diffs)
{
guide g;
for (int i = 0; i < points.length; ++i)
g = g .. points[i] {(1,diffs[i])};
return g;
}

pair[] pts = { (-2,-1), (0,-1), (2,2) };
real[] diffs = { 1, 0, -1 };

draw (fit_curve(pts, diffs));
dot(pts);

-
it's f(-2)=-1 in the question –  Alain Matthes Feb 16 '12 at 17:28
@Altermundus: Sorry, fixed. –  Leo Liu Feb 17 '12 at 1:45

You could use the (a,b) to[in=<degrees>,out=<degrees>] (c,d) options. Without any looseness specified, it is set to one. The second picture illustrates it's influence in the range from zero (blue) to two (red). If you don't want to compute the <degrees> yourself, you could do it via the atan function of pgfmath, it should be atan(incline)+180 for in and atan(incline) for the out value.

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[scale=2]
\draw (-2,-1) to[out=45,in=180] (0,-1) to[out=0,in=135] (2,2);
\draw (-2,-1) circle (0.1) (0,-1) circle (0.1) (2,2) circle (0.1);
\end{tikzpicture}

\begin{tikzpicture}[scale=2]
\foreach \x in {0,10,...,100}
{   \pgfmathsetmacro{\loose}{\x/50}
\draw[looseness=\loose,color=red!\x!blue] (-2,-1) to[out=45,in=180] (0,-1) to[out=0,in=135] (2,2);
}
\draw (-2,-1) circle (0.1) (0,-1) circle (0.1) (2,2) circle (0.1);
\end{tikzpicture}

\end{document}


-
Hm... It's better than specifying problematic controls directly. –  Leo Liu Feb 18 '12 at 2:29

Update I added a macro to draw curve defined by three points and the tangent specifications at these points. The macro is named \expression

The polynomial here is f(x)= -(9/128)*x^5-(5/32)*x^4+(15/32)*x^3+x^2-1

I draw three functions

1) in orange the first try : (a).. controls ((a)+(1,f'(a)) and ((b)+(-1,f'(b)) .. (b) .. controls ((b)+(1,f'(b)) and ((c)+(-1,f'(c)) .. (c)

2)in blue :

(a).. controls ((a)+(1,f'(a)) and ((b)+(-1/2,f'(b)/2) .. (b) .. controls ((b)+(1,f'(b)) and ((c)+(-1/2,f'(c)/2) .. (c)

3) In red the polynomial, I used my package tkz-fct to draw this last function, because I can draw easily the tangents.

As you can see on the next picture, the results are not very bad. It's possible to make a macro to get the control points automatically.

Picture

The code

\documentclass[11pt]{scrartcl}
\usepackage{tkz-fct}
\usetikzlibrary{calc}

\newcommand\expression[9]{
(#1,#2) .. controls ($(#1,#2)+(1,#3)$) and ($(#4,#5)+(-1,-#6)$) ..(#4,#5)
..controls ($(#4,#5)+(1,#6)$) and ($(#7,#8)+(-1,-#9)$)..(#7,#8)
}

\begin{document}
\begin{tikzpicture}
\tkzInit[xmin=-3,xmax=3,ymax=3,ymin=-3];
\tkzAxeXY
\draw[help lines](-2,-2) grid (3,3);

\draw[orange,line width=1pt] \expression {-2} {-1}  {1}%
{0}  {-1}  {0}%
{2}  {2}   {-1};
\draw[blue,line width=1pt] (-2,-1) .. controls (-1,0) and (-0.5,-1) ..(0,-1)..controls(1,-1) and (1.5,2.5)..(2,2) ;
\tkzFct[color = red,domain =-2:2,line width=3pt,opacity=.5]{(-9./128)*x**5-(5./32)*x**4+(15./32)*x**3+x**2-1}

\begin{scope}[line width=.5pt]
\tkzDrawTangentLine[draw,color=green](-2)
\tkzDrawTangentLine[draw,color=green](0)
\tkzDrawTangentLine[draw,color=green](2)
\end{scope}

\end{tikzpicture}
\end{document}

-