# Python: Plotting Functions
([home](https://github.com/alexhkurz/introduction-to-programming/blob/master/README.md) ... [previous](https://hackmd.io/@alexhkurz/SJ1DcL43L) ... [next](https://hackmd.io/@alexhkurz/HyJqEPN2L))
(we spent more than one session on this)
This session is a digression. We are still learning the very basics of programming and Python. But one can spend a lot of time there without getting to the applications that make programming really interesting and useful. For example, we have seen in the last session that we can define mathematical functions. But what if we want to plot them?
We could take the slow route and learn how to do this from scratch. This would be an interesting exercise ... but take a lot of time. Instead, we do it the modern way by using a library, that is, code that others wrote for us. The advantage is that we get much more quickly to where we want to be. The disadvantage is that we will use code that we will not understand in all detail. We will trust other programmer's work.
So I googled "plot functions in Python", read a few of the links that came up and decided to follow the article [Matplotlib: Plot a Function y=f(x)](https://scriptverse.academy/tutorials/python-matplotlib-plot-function.html).
(As a side remark, if you follow the link above, you will see that we jump right into the middle of a larger tutorial. If you already know what you want, it is usually not necessary to read a tutorial from the beginning. It is faster to pick and choose. Nevertheless, this tutorial looks good to me, so I would encourage you to read more of it, if this topics interests you.)
If you didn't [install Python](https://www.python.org/downloads/) yet, do this now. Then we need to install the library. Try
pip install matplotlib
Sometimes installing packages needs some fiddling around, but it should work out after a while.
So now we can plot some functions.
## Plotting one function
Copy-paste the program below into a new file in your editor or dowload [plot1.py](https://github.com/alexhkurz/introduction-to-numbers/blob/master/src/plot1.py).
(One thing to do when jumping into the middle of a tutorial is to cut out everything you don't need for now. This is why `plot1.py` is shorter than the program in the tutorial.)
import matplotlib.pyplot as plt
import numpy as np
# 100 linearly spaced numbers
x = np.linspace(-5,5,100)
# the function
y = x**2
# plot the function
plt.plot(x,y)
# show the plot
plt.show()
**Activity:**
- Where it says "the function" enter various functions you know from mathematics and plot them: lines, polynomials, exponentials, logarithms, hyperbola, sine, cosine, ... [*Practical Hint:* Before running a modified program again, make sure that you closed the window with the previous graph.]
- Find out what `np.linspace` does by changing the three parameters (one at a time) and observing how the plots change.
- What happens if you replace `plt.plot` by `plt.scatter`?
- Repeat the previous item by changing the parameters of `np.linspace`.
- Can you change the parameters of `np.linspace` so that the graph has exactly 6 dots?
- In the scatterplot of a parabola such as $y=x^2$, why does the distance between the dots increase with the distance of $x$ from the vertex?
- What happens if you swap `x` and `y` in `plot(x,y)`?
- The names `x` and `y` are chosen by the programmer. Replace them by other names. The behaviour of the program when you run it should not change.
- Python does not know that we are used to call the horizontal axis the $x$-axis and the vertical axis the $y$-axis. How does the Python program above "know" that the `x`-values go on the horizontal axis and the `y`-values go on the vertical axis?
## Drawing coordinate systems
You will have noticed that Python graphs the function in a box surrounded by lines (called "spines" in matplotlib) at the top and bottom and at the left and right.
In mathematics, we are used to see cooridinate systems with two axis that intersect at the origin (the point $(0,0)$). We can achieve this by inserting the following before calling `plt.plot`.
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
The first two lines are needed for internal bookkeeping. The next two lines move the left and bottom spines to the origin. The last two lines make the top and right spines invisible.
**Exercise:** With the code above in place for drawing the coordinate system, find a way to complete the lines in the program starting `x =` and `y =` so that the origin of the coordinate system is not visible in the plot. Explain how this can happen.
To avoid the unpleasant phenomenon we discovered in the previous exercise, we can do one of the following.
- Increase the area that is displayed in the plot. This can be done by changing the parameters of `np.linspace`.
- Make the axis intersect not in the origin but in the middle of the plot.
The latter can be achieved by replacing the middle two lines of the code above by
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
If you want on the horizontal axis the stepsize between two ticks to be $1$ add the line
plt.xticks(np.arange(min(x), max(x)+1, 1))
(This only works properly if the name of the variable you want to plot on the horizontal axis is `x`. If not you have to adapt the code appropriately.)
The last line of code computes the ticks from the data. But sometimes you want to custome the range "by hand". For example, if you want both axis to run from $-5$ to $5$ with ticks at every unit step, you can insert in your code (just before `plt.show`)
plt.xticks(range(-5, 6))
plt.yticks(range(-5, 6))
(Why do we write `6` above and not `5`? A range `(a,b)` in Python consists of all numbers greater or equal than `a` and smaller than `b`.)
**Exercise:** Can you guess what to do in order to change the stepsize on the vertical axis? Find out by experimenting yourself.
For example, if the name of the variable you want to plot on the vertical axis is `y1` and the stepsize is $2$, then you can add
plt.yticks(np.arange(min(y1), max(y1)+1, 2))
**Activity:** Go through the previous activity again and, for each example graph, find the nicest way of displaying the coordinate system.
## Lines and parabolas
A lot of school mathematics becomes much easier if one has a firm grasp of certain functions, in particular lines and parabolas. A good way to understand these functions is by plotting lots of them and trying to understand how their shape changes when you change their defining parameters. This is the purpose of the next exercises.
**Exercise:** (Straight lines)
- Plot the function $y=2*x + 3$.
- The general form a line is $y=ax+b$ where the so-called parameters $a,b$ are numbers you can fix as you please. Plot lines for different values of $a,b$.
- Explain in your own words how the curve changes when you change the values of $a,b$.
**Exercise:** (Parabolas)
- Plot the function $y=x^2-1$. For what values of $x$ does the curve intersect the $x$-axis?
- Now plot the function $y=ax^2+bx +c$ for different values of $a,b,c$. Can you say how changing each of $a,b,c$ affects the shape of the curve?
**Exercise:** (Exponential function) Plot the function $y=2^x$
- in the range $-1\le x\le 1$;
- in the rangeand $-10\le x\le 10$; what does
If you do enough of these exercises you should end up seeing a mental picture of a curve just from looking at its equation.
Moreover, many of the more interesting questions you will encounter in school exams are much easier to solve if you can mix geometric and algebraic reasoning. This is much easier if you can plot functions approximately in your mind.
We will see an example of this in the next section.
## Plotting two functions
If you want to do some more useful things, you need a bit more "infrastructure" in your code. Let us say we want to find out whether (and possible where) two functions intersect.
The following example is taking from a SAT style math test of students at a US university. The question had various multiple choice style answers about whether and where the curves intersect. To answer the question it was not necessary to compute the solution. It was enough to have a mental picture of where the curves lie in the coordinate plate.
The question was about the solutions of
$$x-7-\sqrt{36x}=0$$
If you split this into the two functions
$$y=x-7 \quad\quad\quad y=\sqrt{36x}$$
then the question becomes where the two curves intersect.
So let us plot the two functions using [plot2.py](https://github.com/alexhkurz/introduction-to-numbers/blob/master/src/plot2.py).
**Exercise:**
- Change the parameter values in `x = np.linspace(-5,5,100)`, so that you can find the intersection of the two curves.
- Also compute the intersection by solving a quadratic equation.
- Now replace $y=x-7$ by more general lines of the form $y=ax+b$. Try different values for $a$ and $b$. For which values do the curves intersect?
- Narrow down the previous question by assuming $b=0$. Experimenting with the program, for which values of $a$ do the curves intersect?
- Continuing from the previous item, answer the same question by solving a quadratic equation.
- (This requires a bit more algebra.) Given $f(x)=ax+b$ and $g(x)=\sqrt{36x}$, for which values of $a$ and $b$ has the equation $f(x)=g(x)$ exactly two solutions?
## Inverse functions
Many functions we know are defined as **inverse functions** of more familiar funtions:
- subtraction is the inverse of addition
- division is the inverse of multiplication
- square root is the inverse of squaring
- logarithm is the inverse of exponentiation
For example, you need inverse functions to play the game what-is-the-number (a more serious application is decoding encrypted messages):
**Exercise:** I am thinking of a number. If I square the number, then add 1, then multiply by 2, I get 20. What is the number?
Typically, computing the inverse function is more difficult than computing the original function. (This insight can also be used for cryptography.)
But geometrically, the inverse function is easy to obtain. Let us take
$$y=x^2.$$
To compute $x$ from $y$, we need to know whether $x$ was positive or negative to begin with. So let us assume that $x\ge 0$.
Solving for $x$, we get $$x=\sqrt y.$$
These two functions have the same graph.
**Exercise:**
- Plot the two functions above with [plot3.py](https://github.com/alexhkurz/introduction-to-numbers/blob/master/src/plot1.py).
- Modify the program by starting from a different function, say, $y=2x+3$. What is the inverse function? Plot both using the modified program.w
We are used to the function and the inverse function to have different graphs. So why do the two functions above have the same graph?
Note that in $y=x^2$ the variable $x$ is the input of the squaring function and in $x=\sqrt y$ the variable $y$ is the input of the square-root function.
Graphs do not have input and output, but functions do.
As graphs, $y=x^2$ and $x=\sqrt y$ are entirely equivalent (for $x\ge 0$) in the sense that both equations determine exactly the same graph. As functions, squaring and square-root are very different, in fact, inverse to each other.
So how do we plot the inverse function of a given function? There are two ways.
- We can plot the inverse function by plotting the graph of the function itself with $x$ and $y$-axis interchanged. See [plot4.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/plot4.py) for the case of the squaring function.
- We can use expicitely the inverse function. See [plot5.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/plot5.py) for the case of the squaring function.
- Check that the inverse function is, as it should be, the mirror image of the function, mirrorred at the diagonal $y=x$. [*Hint:* If a unit on the horizontal axis has a different length than a unit on the vertical axis, you can correct this by stretching the window in one but not the other direction.]
**Activity:**
- Plot various functions and their inverse functions by adapting both [plot4.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/plot4.py) and [plot5.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/plot5.py).
- In particular plot the exponential function $2^x$ and the logarithm $log_2 x$. [*Hint:* Google "numpy logarithm" to find out how to compute logarithms in Python. You may have to look at several hits to find the best explanation, but "Stackoverflow" is usually a good bet.]
## Coordinate transformations
**Activity:** Going back to [Drawing coordinate systems](#Drawing-coordinate-systems), include the code that draws the coordinate system with the two axis intersecting at the orgin, that is,
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
Take any of the curves you have drawn previously and find out to shift them top/bottom and right/left. Formulate a rule of how to do this. Explain this rule in terms of shifting the coordinate system (instead of shifting the curve).
## References
I used the following references when I worked on this session.
<span style="color:lightgray">(If you work in an academic environment you always have to be aware of plagiarism. The safe way to avoid plagiarism is to cite your sources. You don't need to cite what is considered as common knowledge in the audience you are writing for or what is not relevant to the content such as the source I used to learn how to typeset this sentence in a light grey colour.)</span>
I mainly relied on:
- Scriptverse, [Matplotlib: Plot a Function y=f(x)](https://scriptverse.academy/tutorials/python-matplotlib-plot-function.html)
The following also proved useful:
- [How do you make the x-axis pass through (0,0) with matplotlib in Python?](https://stackoverflow.com/questions/44016339/how-do-you-make-the-x-axis-pass-through-0-0-with-matplotlib-in-python)
- [NumPy: Logarithm with base n](https://stackoverflow.com/questions/25169297/numpy-logarithm-with-base-n)
- GeeksforGeeks, [Graph Plotting in Python](https://www.geeksforgeeks.org/graph-plotting-in-python-set-1/)