In the last post, I described how I use Ti*k*Z to create a graph that might otherwise be created freehand:

In this post, I will describe one method for using Ti*k*Z to to plot a function defined by a formula, such as
\[y = \left(2x^2 - x - 1\right)e^{-x}.\]
Then I will show two ways to make a function go through a certain point.

# Plotting from a formula

## Simple example

There are a number of ways to achieve this, and PGF actually includes the functionality to perform calculations in TeX. (For example, I have used the PGF pseudorandom number generator in graphics. Someone even made Ti*k*Z code to generate a random city skyline.) However, for efficiency sake, I prefer to have the calculations done outside TeX, in a more efficient computer language.

The trick is to use the `gnuplot`

table import format. You simply have to generate a text file with a list of coordinates in the following form:

`-1.250000 11.779907`

`-1.240000 11.456050`

`-1.230000 11.138839`

This file contains the coordinates \((-1.25, 11.779907)\), \((-1.24, 11.456050)\), \((-1.23, 11.138839)\).

There are a number of ways to generate such a file. Since I like Python, I used the following (simple) Python script:

`#! /usr/bin/env python3`

`import numpy as np`

`f = lambda x: (2*x**2 - x - 1)*np.exp(-x)`

`xvals = np.arange(-1.25, 10.25, 0.01)`

`with open("plot1.table", "wt") as outfile:`

` for x in xvals:`

` outfile.write("{:f} {:f}\n".format(x, f(x)))`

Now, this curve can be imported into your Ti*k*Z illustration using `\draw`

[. . .] `plot`

; in this case:

`\draw[thick, blue, <->] plot[smooth] file {plot1.table};`

Here is a complete example (with coordinate axes and everything):

`\documentclass[border=0.25cm]{standalone}`

`\usepackage{tikz}`

`\usepackage{fouriernc}`

`\begin{document}`

`\begin{tikzpicture}[yscale=0.5]`

` \draw[gray] (-1.25, -1.25) grid (10.25, 12.25);`

` % x-axis`

` \draw[thick, black, ->] (-1.25, 0) -- (10.25, 0)`

` node[anchor=south west] {$x$};`

` % x-axis tick marks`

` \foreach \x in {-1, 10}`

` \draw[thick] (\x, 0.2) -- (\x, -0.2)`

` node[anchor=north] {\(\x\)};`

` % y-axis`

` \draw[thick, black, ->] (0, -1.25) -- (0, 12.25)`

` node[anchor=south west] {$y$};`

` % y-axis tick marks`

` \foreach \y in {-1, 12}`

` \draw[thick] (-0.1, \y) -- (0.1, \y)`

` node[anchor=west] {\(\y\)};`

` % graph of function`

` \draw[thick, blue, <->] plot[smooth] file {plot1.table};`

`\end{tikzpicture}`

`\end{document}`

And here is the output:

In my Python script above, I carefully chose the set of inputs \(x\) (`np.arange(-1.25, 10.25, 0.01)`

, i.e., every real number of the form \(-1.25 + 0.01k, \; k \in \mathbb{Z}\) in the interval \([-1.25, 10.25)\)) to keep \(f(x) < 12\). This can also be handled computationally.

## Example involving asymptotes

For example, suppose I want to plot \(y = r(x)\), where \[r(x) = \frac{6x^3 + 21x^2 - 21x - 36}{3x^3 + 3x^2 - 12x - 12},\] with \(-15.5 \leq x \leq 15.5\). Let's additionally suppose I want to only see \(y\)-values with \(-15.5 \leq y \leq 15.5\). (In other words, the "viewing rectangle" will be \([-15.5, 15.5] \times [-15.5, 15.5]\).)

Factoring the numerator and denominator, we have:

\[r(x) = \frac{6x^3 + 21x^2 - 21x - 36}{3x^3 + 3x^2 - 12x - 12}\] \[\phantom{r(x)}= \frac{\left(x + 1\right) \left(2 x - 3\right) \left(3 x + 12\right)}{\left(x + 1\right) \left(x + 2\right) \left(3 x - 6\right)}\] \[\phantom{r(x)}= \frac{\left(2 x - 3\right) \left(3 x + 12\right)}{\left(x + 2\right) \left(3 x - 6\right)}, \; x \not = -1.\]

As you can see, we will have vertical asymptotes at \(x = -2\) and \(x = 2\), and a hole at \(x = -1\). There will also be a horizontal asymptote at \(y = 2\).

To handle the asymptotes, we plot the function \[\hat r(x) = \frac{\left(2 x - 3\right) \left(3 x + 12\right)}{\left(x + 2\right) \left(3 x - 6\right)}\] along three intervals:

- \([-15.5, -2)\),
- \((-2, 2)\), and
- \((2, 15.5]\)

(Actually, for each of the above intervals \(I\), we plot something approximating \(\left\{(x, \hat r(x)): x \in I \text{ and } |\hat r(x)|\leq 16\right\}\).)

Here is the Python script:

`#! /usr/bin/env python3`

`import numpy as np`

`r = lambda x: (2*x - 3)*(3*x + 12)/((x + 2)*(3*x - 6))`

`xvals = [`

` np.arange(-15.5, -2, 0.01),`

` np.arange(-2.01, 2, 0.01),`

` np.arange(2.01, 15.6, 0.01)`

` ]`

`for idx, interval in enumerate(xvals):`

` with open("plot2_{}.table".format(idx), "wt") as outfile:`

` for x in interval:`

` if abs(r(x)) <= 16:`

` outfile.write("{:f} {:f}\n".format(x, r(x)))`

Here is the corresponding LaTeX code:

`\documentclass[border=0.25cm]{standalone}`

`\usepackage{tikz}`

`\usepackage{fouriernc}`

`\begin{document}`

` \begin{tikzpicture}[scale=0.5] % Scale keeps the graphic small`

` \draw[gray] (-15.5, -15.5) grid (15.5, 15.5);`

` % x-axis`

` \draw[thick, black, ->] (-15.5, 0) -- (15.5, 0)`

` node[anchor=south west] {$x$};`

` % x-axis tick marks`

` \foreach \x in {-15, -10, -5, 5, 10, 15}`

` \draw[thick] (\x, 0.5) -- (\x, -0.5)`

` node[anchor=north] {\(\x\)};`

` % y-axis`

` \draw[thick, black, ->] (0, -15.5) -- (0, 15.5)`

` node[anchor=south west] {$y$};`

` % y-axis tick marks`

` \foreach \y in {-15, -10, -5, 5, 10, 15}`

` \draw[thick] (-0.5, \y) -- (0.5, \y)`

` node[anchor=west] {\(\y\)};`

` % graph of function`

` \draw[thick, blue, <->] plot[smooth] file {plot2_0.table};`

` \draw[thick, blue, <->] plot[smooth] file {plot2_1.table};`

` \draw[thick, blue, <->] plot[smooth] file {plot2_2.table};`

` % hole at (-1, 5)`

` \draw[thick, blue, fill=white] (-1, 5) circle (2.5mm);`

` % vertical asymptotes`

` \draw[thick, dashed, red] (-2, -15.5) -- (-2, 15.5);`

` \draw[thick, dashed, red] (2, -15.5) -- (2, 15.5);`

` % horizontal asymptote`

` \draw[thick, dashed, red] (-15.5, 2) -- (15.5, 2);`

` \end{tikzpicture}`

`\end{document}`

And here is the result:

# Plotting functions that go through certain points: two ways

Suppose I want to plot a function that go through certain points, say:

- \((-4, 2)\),
- \((-1, 6)\),
- \((2, 3)\), and
- \((4, 5)\).

I want the function to be differentiable.

## Method one: Bézier curves

Recall from the last post that a (cubic) Bézier curve is specified by four points:

- A start point (\((x_0, y_0)\) in the diagram below)
- Two control points (\((x_1, y_1)\) and \((x_2, y_2)\) in the diagram below)
- An end point (\((x_3, y_3)\) in the diagram below)

The syntax is: `\draw (`

\(x_0, y_0\)`) .. controls (`

\(x_1, y_1\)`) and (`

\(x_2, y_2\)`) .. (`

\(x_3, y_3\)`);`

Now, we can combine multiple Bézier curves into a single `\draw`

. For example, `\draw (`

\(x_0, y_0\)`) .. controls (`

\(x_1, y_1\)`) and (`

\(x_2, y_2\)`) .. (`

\(x_3, y_3\)`) .. controls (`

\(x_4, y_4\)`) and (`

\(x_5, y_5\)`) .. (`

\(x_6, y_6\)`);`

will produce:

In general, this curve will *not* necessarily be differentiable. We can get differentiability by ensuring that \((x_2, y_2)\), \((x_3, y_3)\) and \((x_4, y_4)\) are colinear (i.e., the end of the first Bézier curve has the same derivative as the beginning of the second) with \(x_2 \not = x_3\):

Keeping these principles in mind, we can plot a function going through the desired points with:

`\documentclass[border=0.25cm]{standalone}`

`\usepackage{tikz}`

`\usepackage{fouriernc}`

`\begin{document}`

` \begin{tikzpicture}[scale=0.5] % Scale keeps the graphic small`

` \draw[gray] (-5.25, 0) grid (5.25, 8.25);`

` % x-axis`

` \draw[thick, black, ->] (-5.25, 0) -- (5.25, 0)`

` node[anchor=south west] {$x$};`

` % x-axis tick marks`

` \foreach \x in {-5, 5}`

` \draw[thick] (\x, 0.25) -- (\x, -0.25)`

` node[anchor=north] {\(\x\)};`

` % y-axis`

` \draw[thick, black, ->] (0, 0) -- (0, 8.25)`

` node[anchor=south west] {$y$};`

` % y-axis tick marks`

` \foreach \y in {4, 8}`

` \draw[thick] (-0.25, \y) -- (0.25, \y)`

` node[anchor=west] {\(\y\)};`

` % graph of function`

` \draw[thick, blue, <->] (-5.25, -0.5)`

` .. controls (-4, 0) and (-5, 0) .. (-4, 2)`

` .. controls (-3.5, 3) and (-3, 6) .. (-1, 6)`

` .. controls (1, 6) and (1.75, 4) .. (2, 3)`

` .. controls (2.25, 2) and (3, 2) .. (4, 5)`

` .. controls (4.5, 6.5) and (4.5, 7) .. (5.25, 8);`

` \end{tikzpicture}`

`\end{document}`

Here is the output:

## Method two: Polynomial interpolation

SciPy's interpolation functionality can find a smooth function that passes through an arbitrary list of points. Here is an example of a Python script to produce such a function and create a table in the necessary format:

`#! /usr/bin/env python3`

`import numpy as np`

`import scipy.interpolate`

`coords = [(-10, 8), (-4, 2), (-1, 6), (2, 3), (4, 5), (10, 1)]`

`# Since our goal is to plot from x = -5.25 to x = 5.25,`

`# we need to specify some points beyond that interval on both sides.`

`xcoords, ycoords = zip(*coords)`

`# This produces a seperate list of x-coordinates and y-coordinates`

`f = scipy.interpolate.interp1d(xcoords, ycoords, kind="cubic")`

`xvals = np.arange(-5.25, 5.25, 0.01)`

`yvals = f(xvals)`

`outcoords = zip(xvals, yvals)`

`# This produces a list of coordinate pairs`

`with open("plot3.table", "wt") as outfile:`

` for pair in outcoords:`

` outfile.write("{:f} {:f}\n".format(pair[0], pair[1]))`

Note that if we had set `coords = [(-4, 2), (-1, 6), (2, 3), (4, 5)]`

, then the resulting function would not have had a defined value outside of the interval \([-4, 4]\).

To plot, we use the following `tikzpicture`

:

`\documentclass[border=0.25cm]{standalone}`

`\usepackage{tikz}`

`\usepackage{fouriernc}`

`\begin{document}`

` \begin{tikzpicture}[scale=0.5] % Scale keeps the graphic small`

` \draw[gray] (-5.25, 0) grid (5.25, 8.25);`

` % x-axis`

` \draw[thick, black, ->] (-5.25, 0) -- (5.25, 0)`

` node[anchor=south west] {$x$};`

` % x-axis tick marks`

` \foreach \x in {-5, 5}`

` \draw[thick] (\x, 0.25) -- (\x, -0.25)`

` node[anchor=north] {\(\x\)};`

` % y-axis`

` \draw[thick, black, ->] (0, 0) -- (0, 8.25)`

` node[anchor=south west] {$y$};`

` % y-axis tick marks`

` \foreach \y in {4, 8}`

` \draw[thick] (-0.25, \y) -- (0.25, \y)`

` node[anchor=west] {\(\y\)};`

` % graph of function`

` \draw[thick, blue, <->] plot[smooth] file {plot3.table};`

` \end{tikzpicture}`

`\end{document}`

Here is the result:

As we have seen, creating plots with Ti*k*Z allows you a deep amount of control over the final result, and can be especially powerful when combined with a programming language such as Python.