```
using MTH229
using Plots
plotly()
```

`Plots.PlotlyBackend()`

A notebook for this material: ipynb

The `Julia`

language is a new language and as such, certain design decisions are still being made. One key decision is the interface for creating graphics. At this point there are many different ones (`Makie`

, `PyPlot`

, plotly, plotlyjs, `GR`

, `Winston`

, `Gadfly`

, `Gaston`

,…), and perhaps more will be generated before a dominant one is arrived at. As such, we don’t try to teach the details of any one of them.

Currently, the `Plots`

package provides a unified interface to many backend plotting packages. We will use the popular `Plots`

package in these examples, but recognize that it is likely the `Makie`

will eventually become the preferred plotting package.

For the impatient, this is all that is needed to know to get up and running to make a plot.

First load the necessary package:

```
using MTH229
using Plots
plotly()
```

`Plots.PlotlyBackend()`

plotly

The default graphics of `Plots`

are *static*. Adding one additional call, `plotly()`

. will use an interactive backend for `Plots`

which will show the `(x,y)`

position of points on the graph when a mouse hovers over them. (The default can be re-loaded by the command: `gr()`

.)

Once done, graphing a function is as easy as specifying the function and the domain to graph over, e.g.:

```
f(x) = exp(-x^2 / 2)
plot(f, -3, 3) # plot f over [-3,3]
```

Graphs can be layered by using the `plot!`

function (with an exclamation point indicating a current graph is begin modified):

```
f(x) = cos(x)
g(x) = 1 - x^2/2
plot(f, -pi/2, pi/2)
plot!(g) # the domain to plot is optional if adding a layer
```

For the more patient, the rest of the sections cover some additional details including how to specify a graph by defining the points that are used to make the plot.

The most basic usage for plotting a function follows this pattern:

`plot(function_object, from, to) # or plot(f, a, b)`

as in

`plot(sin, 0, 2pi)`

That creates the graphic. The `Plots`

package is an interface to several plotting “backends.” Within `IJulia`

and using `plotly()`

the graph will be automatically displayed as an `SVG`

graphic that allows you to zoom and pan with the mouse.

Alert

This is another example of a general template **action(function_object, args…)** for performing some action on a function. In this case, the action is to plot a function and the additional *args…* indicate the domain to plot over.)

Again, we plot a function, this time a basic polynomial:

```
f(x) = x^2 - 2x + 2
plot(f, -3, 3)
```

A graph can have layers added to it using `plot!`

or other such functions. For example, adding the function `zero`

will emphasize the `x`

axis:

```
f(x) = x^2 - 2x + 2
plot(f, -3, 3)
plot!(zero) # x axis
```

The automatic legend can be suppressed by passing the keyword argument `legend=false`

to the initial `plot`

command.

Adding points can be done with the `scatter!`

command. We put the `x`

and `y`

values into containers defined by `[]`

. For example, the polynomial \(x^2 - 3x +2\) has roots at \(2\) and \(1\), we emphasize this through:

```
f(x) = x^2 - 3x + 2
= [1, 2]
rts plot(f, 0, 3)
scatter!(rts, [0, 0])
```

`Plots`

plots functions by creating a large number of paired points \((x, f(x))\); it then plots these points; and, finally, connects the points with line segments. In the numerous function evaluations, it is of course quite possible that some of the points will return `Inf`

or `NaN`

. (Where `Inf`

is a floating point value for infinity and results from evaluations like `1/0`

and `NaN`

stands for “not a number”, and results from indeterminate evaluations such as `0/0`

.)

The values which are `Inf`

can not reasonably be plotted. Values which are `NaN`

can not reasonably plotted. What to do? Such points are simply not plotted, and no line segments are drawn causing the plot to be discontinuous. This convention can be utilized to good effect.

For example, to create bounded graphs, we can trim out any large values and replace them with `NaN`

. A function that can be used to modify an arbitrary function (like \(f(x) = 1/x\)) and return a function that can be plotted can be defined as follows:

`trim(f; val=10) = x -> abs(f(x)) > val ? NaN : f(x)`

`trim (generic function with 1 method)`

This action is very similar to clamping.

The `MTH229`

package implements this in the function `rangeclamp(f, hi=20, lo=-hi)`

. (Base `Julia`

has a `clamp`

function.)

Using `rangeclamp`

is fairly simple. The output is a function, so can be passed directly to the `plot`

call:

```
f(x) = 1/x
plot(rangeclamp(f), -3, 3)
```

Or

`plot(rangeclamp(f, 100), -3, 3)`

This trimming also works when `Inf`

and `-Inf`

values are encountered, as both can be ordered by `>`

.

:::{.callout-note} ## ylims, xlims

The range of `x`

values comes from the choice of `a`

and `b`

in `plot(f, a, b)`

and the range of `y`

values comes from the range of `f`

over the interval `[a,b]`

. These can be adjusted manually through the keyword arguments `xlims=(l,r)`

and `ylims=(m, M)`

. An alternate to clamping `f`

is to change the `y`

limits, though as no `NaN`

values are used, there can be artificacts in the resulting graphs:

```
f(x) = 1/x
plot(f, -3, 3, ylims = (-10, 10))
```

Consider a function with a parameter, `theta`

, defined by:

```
function g(x, theta=pi/4)
= 200*cos(theta)
a tan(theta)*x + (32/a)*x - 32*log(a/(a-x))
end
```

`g (generic function with 2 methods)`

Plotting `g`

will use the default value of \(\pi/4\). To plot with a different value, say \(\pi/3\) we can create a new function, fixing `theta`

:

```
f(x) = g(x, pi/3)
plot(f, 0, 100)
```

Which works, but is a bit verbose. It would be more convenient to use an anonymous function, to bypass the creation of a throwaway function:

`plot(x -> g(x, pi/3), 0, 100; ylims = (0, 150), legend=false)`

There are many instances where plotting with anonymous functions are convenient. It can be hard to get used to seeing that arrow, but it can simplify many expressions if used properly.

Plot the function \(f(x) = x^3 - x\) over \([-2,2]\). How many zeros are there?

Plot the function \(f(x) = x^3 - x\). When is the function positive?

Plot the function \(f(x) = 3x^4 + 8x^3 - 18x^2\). Where (what \(x\) value) is the smallest value? (That is, for which input \(x\) is the output :f(x) as small as possible.

Plot the function \(f(x) = 3x^4 + 8x^3 - 18x^2\). What is the smallest value?

Plot the function \(f(x) = 3x^4 + 8x^3 - 18x^2\). When is the function increasing?

A rational function is nothing more than a ratio of polynomial functions, say \(f(x) = p(x)/q(x)\). One interesting thing about such function is there can be asymptotes. These can be vertical (which can happen when \(q(x)=0\)), horizontal (as \(x\) gets large or small), or even slanted.

The vertical asymptotes require care when plotting, as the naive style of plotting where a collection of points is connected by straight lines can render poor graphs when the scale of \(y\) values get too large. The really large values plotted near the asymptote can wipe out the possibility of seeing other features of interest in a graph.

Some features of interest for a graph that are identifiable by calculus concepts are:

- zeroes
- vertical asymptotes
- horizontal asymptotes (or even slant ones)
- relative maximum and minimum
- increasing and decreasing parts
- changes in inflection

For example, if you want to find zeroes of a function, you really want to look at areas of the graph where the \(y\) values are close to \(0\). However, if you have a vertical asymptote on the same graph, the \(y\) values might also be asked to show very large or small values. With only a finite number of pixels available, it is impossible to easily do both.

What to do? If you were on a smartphone, you might be tempted to pan around to avoid the asymptotes, then pinch and zoom narrow the graph to the feature of interest. With `Julia`

you basically do the same thing, though panning and zooming is done by changing the domain of the \(x\) values used in plotting.

Let’s look at the function \(f(x) = 1/x\), which has an obvious vertical asymptote at \(0\).

One can try a simple plot:

`plot(x -> 1/x, -3, 3)`

The issue at \(0\) is avoided, as the points chosen by `Plots`

do not include \(0\). The asymptote appears as a strongly slanted line, as individual points are simply connected in a dot-to-dot manner.

Doing better without much work is done by simply restricting the part that is plotted. (Alternatively, you can use `NaN`

values or multiple functions on one.) For this example, we can easily draw the positive part:

`plot(x -> 1/x, 0, 3)`

It is best to avoid the asymptote at \(0\) completely by backing away by enough to avoid the large range on the \(y\) axis. In this case, starting around \(1/10\) is reasonable:

`plot(x -> 1/x, 1/10, 3)`

Let’s look at the rational function

\[ f(x) = \frac{(x-2)(x-3)}{x-1} \]

This will have a vertical asymptote at \(1\), zeros at \(2\) and \(3\) and a slant asymptote. A quick graph from \(-10\) to \(10\) shows just some of this:

```
f(x) = (x-2)*(x-3)/(x-1)
plot(f, -10, 10)
```

We can see the slant asymptote and the vertical asymptote, but have no chance of seeing the zeros or the local extrema. For that, we can restrict the domain to plot over.

For example, to graph to the right of the asymptote can be done with:

`plot(f, 1 + 0.5, 4)`

This shows the two zeros and gives an idea of the relative minimum. Similarly, a plot of the left of the asymptote can be illustrative. Here we step back by a bit:

`plot(f, -3, 1 - 0.1)`

It appears that the relative maximum occurs between \(-1\) and \(0\).

Here we see what happens to the asymptote. The scale of the \(y\) values is huge. We added a small amount to the left endpoint in case the function is not defined there, but this function takes the reciprocal of a small amount and makes it huge. Clearly we need to really avoid the issue. It isn’t hard – just add a little bit more to \(0\).

One solution to avoiding this issue is to use the `rangeclamp`

function that was previously described. This just caps off really large values so that the vertical asymptotes don’t affect the scale of the graph. We can see the asymptotes pretty clearly with:

`plot(rangeclamp(f), -10, 10)`

Let

\[ f(x) = \frac{5}{\cos x} + \frac{10}{\sin x}. \]

Estimate graphically the minimum value over \((0, \pi/2)\).

The domain comes from the fact that \(\sin(0) = 0\) and \(\cos(\pi/2) = 0\), so we will have asymptotes at each. A simple graph shows there are issues:

```
f(x) = 5/cos(x) + 10/sin(x)
plot(f, 0, pi/2)
```

As typical with vertical asymptotes, we can’t see finer features of the graph when the asymptotes are drawn. To remedy, we again back off from the boundaries. Since \(\sin(x)\) behaves like \(x\) near \(0\), we pick `delta = 0.3`

again and expect a max near \(10/(3/10) \approx 33\).

```
= 0.3;
delta plot(f, 0 + delta, pi/2 - delta)
```

With this, we see the minimum value is near \(y=20\) and occurs around \(0.9\).

The function \(f(x) = (x^3 - 2x) / (2x^2 -10)\) is a rational function with issues when \(2x^2 = 10\), or \(x = -\sqrt{5}\) or \(\sqrt{5}\).

Plot this function from \(-5\) to \(5\). How many times does it cross the \(x\) axis?

The function \(f(x) = (x^3 - 2x) / (2x^2 -10)\) has a slant asymptote. One can find the slope of this line using algebra, but if you prefer the computer, you can graph. Define both

```
f(x) = (x^3 - 2x) / (2x^2 -10)
g(x) = abs(x) > 5 ? f(x) : NaN
```

`g (generic function with 2 methods)`

then plot `g`

over \([-20, 20]\). Using algebra or this graph, estimate the slope?

The rational function \(f(x) = (x^2 - 3x - 2) / (x^2 - 4)\) has issues at \(-2\) and \(2\). How many times does its graph cross the \(x\) axis?

When we learn how to make a graph using paper and pencil, the “T” method is employed, so called as we draw a “T” and fill in values to plot for \(x\) and \(y\).

For example, a chalkboard after the instructor shows how to plot \(f(x) = x^2\) might have this drawn on it:

```
| y
x ------
1 | 1
2 | 4
3 | 9
4 | 16
```

As these are the steps done to create the ordered pairs for a plot, we would like to be able to mimic the following procedures used above in `Julia`

:

- choose a collection of \(x\) values
- create the corresponding \(y\) values
- plot the pairs \((x,y)\) and connect with lines

We have seen how variables can be used to refer to a single value, but we want to refer to more than one value now. A container for holding such is an `Array`

. Arrays are implemented in most all computer languages, though the term can mean different things. We are looking for vectors, or one-dimensional arrays. In general, an array is a multidimensional grid of values – all of the same type (integer, floating point, *functions*, …, or ANY).

For our purposes, we want vectors (one dimensional, \(n\) by 1 arrays in `Julia`

). These can be easily constructed in different ways.

`[]`

In many different contexts, `Julia`

uses `[]`

to create collections from individual components.

For example, to directly create a 1-dimensional array with the `[]`

syntax one simply types in the values separated by commas:

`1, 2, 3, 4, 5] [`

```
5-element Vector{Int64}:
1
2
3
4
5
```

Or

`1, 1, 2, 3, 5, 8] [`

```
6-element Vector{Int64}:
1
1
2
3
5
8
```

These create “vectors.” Row vectors (which are arrays, but not of type `Vector`

) are created when no commas are specified:

`13 21 34 55] [`

```
1×4 Matrix{Int64}:
13 21 34 55
```

The notation is that `[a, b, c]`

combines `a`

, `b`

, and `c`

vertically and `[a b c]`

combines them horizontally. The former is good to make column vectors for single values (scalars).

Row and column vectors are different! We will primarily use column vectors going forward.

**Containers are for like values…**

In general, `Julia`

uses `[`

and `]`

to create containers for like values. These containers can be more complicated than a single row or column. One subtle thing is that each object must be of the same value, though sometimes this happens by a silent conversion. So, mixing integer and floating point numbers will produce a container of just floating point values:

`1, 2.0] [`

```
2-element Vector{Float64}:
1.0
2.0
```

A basic set of numbers used in programming are the values `1`

,`2`

, …, `n`

. These are the simplest example of an *arithmetic progression* or sequence, which in general can start in a different place and have steps of a size different from \(1\):

\[ a, a + h, a+2h, a+3h, ..., a + nh \]

It should be possible to specify arithmetic sequences either by

- the start and end points and the number of points employed
- the start and end points and step size.

In `Julia`

the `range`

function will do the former and the range operator the latter.

Here are 5 evenly spaced numbers from \(0\) to \(\pi/2\) given by `range`

`range(0, pi/2, length=5)`

`0.0:0.39269908169872414:1.5707963267948966`

The `range`

function returns an object which is a sub-type of `AbstractVector`

, so can be used where vectors are used, in most cases. The `show`

method for ranges is such that the values are not displayed (nor are they computed until needed). To see the values, the abstract vector can be `collect`

ed into a vector:

`collect(range(0, pi/2, length=5))`

```
5-element Vector{Float64}:
0.0
0.39269908169872414
0.7853981633974483
1.1780972450961724
1.5707963267948966
```

The “range” operator, `:`

, is used to specify a step size, like \(h\) in the definition above. To get values which step by 1 we simply specify the start and end values:

`1:4`

`1:4`

That isn’t so impressive. The description `Julia`

uses to show this value is exactly how we defined it, but this range is specifying the values 1, 2, 3, 4. To see that, we `collect`

the values to make an array:

`collect(1:4)`

```
4-element Vector{Int64}:
1
2
3
4
```

The range operator returns a `Range`

object which is much more compact to store than the array. (The range object is an *iterator*, something to be stepped through one at a time. Iterating over the elements specified by a range does not require all the elements at once, so they are not generated.)

The range operator can also work with a step size:

```
=0; b=10; h=3
a:h:b
acollect(a:h:b)
```

```
4-element Vector{Int64}:
0
3
6
9
```

Notice, the value for `b`

is treated as as suggestion, the range will stop without exceeding `b`

.

The \(x\) values for a plot are typically a sequence of increasing values from \(a\) to \(b\). We would generally like to be able to specify the number of values to plot. This makes `range`

the go-to choice to use.

Which command will produce the sequence \(1,3,5,7,9,11, ..., 99\)?

Which command produces 10 numbers between 0 and 10 that are evenly spaced?

Which command does not produce the numbers \(1, 2, 3, 4, 5\)?

Which command does produces the numbers \(1, 1, 2, 3, 5, 8, 13\)?

A column vector has a natural sense of first, second, …, the \(n\)-th element. This allows `Julia`

to refer to the values by index (\(1\)-based, unlike some other computer languages). So, if `x`

is an array, `x[1]`

is the first value in that array. One can extract and *assign* values using indices. A simple example is:

```
= [2, 3, 5, 7, 11, 13, 17]
x 1]
x[3] x[
```

`5`

There are some special values. The `end`

value refers to the last (\(n\) th):

`end] x[`

`17`

The \(n\) – or number of elements – can be returned by `length`

:

`length(x)`

`7`

A range object can be used for indices:

`1:3] x[`

```
3-element Vector{Int64}:
2
3
5
```

The value `end`

can be used in a range when indexing:

`2:end] x[`

```
6-element Vector{Int64}:
3
5
7
11
13
17
```

(But not without indexing, as you can see by typing `2:end`

by itself.)

Left side of an equals sign

`Julia`

allows only three different types of expressions on the left side of an equals sign:

- a variable name, as in
`x = 42`

, - a function definition, as in
`f(x) = x^2 - 2`

, or - a assignment setting an index, as in
`x[1] = 2`

.

The left side is quite unlike a math equation, where arbitrary expressions are typical.

Let

`= [1, 1, 2, 3, 5, 8, 13] x `

```
7-element Vector{Int64}:
1
1
2
3
5
8
13
```

What is the value of `x[end - 1] + x[end]`

?

Let

`= [1, 1, 2, 3, 5, 8, 13] x `

```
7-element Vector{Int64}:
1
1
2
3
5
8
13
```

What is the value of `x[3]`

?

When a vector is created, if possible, the resulting values are converted to be the same type. Let

```
= [1, 2.0]
x = [1, 2.0, "three"] y
```

```
3-element Vector{Any}:
1
2.0
"three"
```

For `x[1]`

and `y[1]`

what does `typeof`

return?

(The `y`

container is of type `Any`

which allows it to hold any type of object, the `x`

container only holds values of a certain type.)

To specify the \(y\) values we wish to “map” the function `f`

to each \(x\) value. In `Julia`

there are many different ways to do this, we list four for completeness, but will restrict our attention to just the first three styles.

The `map`

function. In many areas of mathematics, one refers to a function as a “map” from the domain to the range. The implication is that the function takes all the \(x\) values to the corresponding \(y\) values at once (conceptually) and not one at a time. The `map`

function will apply the function `f`

to each value in the array `x`

, basically taking `[x1, x2, ..., xn]`

and returning `[f(x1), f(x2), ..., f(xn)]`

.

For example, let’s look at the simple polynomial \(f(x) = -16x^2 + 32x\). We define our `Julia`

function with:

`f(x) = -16x^2 + 32x`

`f (generic function with 1 method)`

If we want to look at this function for \(x\) values between \(0\) and \(2\) we might define the \(x\) values with:

`= range(0, 2, length=5) x `

`0.0:0.5:2.0`

Then the `map`

function will create the corresponding \(y\) values:

`map(f, x)`

```
5-element Vector{Float64}:
0.0
12.0
16.0
12.0
0.0
```

The syntax of `map`

requires a slight pause. Here we do not actually call the function `f`

, as in `f(2)`

. Rather, we pass the name of the function object to the `map`

argument – and `map`

calls the function for each value in the column vector `x`

and returns a corresponding column vector.

It is also quite common to use anonymous functions with `map`

. For example:

`map(u -> 10 * u^2, x)`

```
5-element Vector{Float64}:
0.0
2.5
10.0
22.5
40.0
```

We use `u`

for the dummy variable in the anonymous function, so as not to get it confused with the variable `x`

holding our values, but this is not necessary.

`Julia`

allows a function to be broadcast over a collection of values with the simple notational trick of inserting a “.” *before* the parenthesis used to call the function^{1}. To see, we have:

`sin.([1,2,3])`

```
3-element Vector{Float64}:
0.8414709848078965
0.9092974268256817
0.1411200080598672
```

In this use, the output is the same as though `map(sin, [1,2,3])`

were called. In general, this “.” notation is a bit different, as there can be multiple arguments passed and the size of the values is matched if possible by replication. For example, this command find the logarithm of \(5\) for different bases. The value \(5\) is replicated once for each of the bases:

`log.([2,pi,5,10], 5)`

```
4-element Vector{Float64}:
2.321928094887362
1.4059543061897808
1.0
0.6989700043360187
```

Note

The “dot” broadcasting is very succinct and useful, but using `map`

is more explicit and easier to reason about. We will mostly use broadcasting due to the simplicity.

Mathematicians are fond of set notation, as in this way to describe the \(y\) values in a graph:

\[ y = \{ f(x): x \text{ in } [0, 2] \}, \]

This is read: “the values \(f(x)\) *for* each \(x\) in the interval \([0,2]\).”

Here we define values `xs`

to represent the continuum of values in the interval \([0,2]\), then use a “comprehension” to create the set notation above. The syntax is similar:

```
= range(0, 2.0, length=5)
xs f(x) for x in xs] [
```

```
5-element Vector{Float64}:
0.0
12.0
16.0
12.0
0.0
```

The two approaches, broadcasting/maps and comprehensions, are equally useful. Perhaps `map`

is a bit less trouble, but comprehensions mirror a more familiar mathematical syntax and generalize to functions of more than one variable nicely. One difference to keep in mind when deciding which to use, is that broadcasting/mapping requires a function, whereas comprehensions use expressions.

Finally, for completeness, we mention another means to generate vectors of numbers that is more familiar to users of other computer languages.

The `for`

loop is a very common pattern in computer programming. For speed reasons, some languages (e.g., `MATLAB`

and `R`

) try to avoid for loops for a “vectorized” approach (see below), but `Julia`

works well with `for`

loops, and they are sometimes easier to understand than a vectorized approach.

A `for`

loop simply loops over each value in the iterable data vector `x`

giving it a temporary name as it goes. To use a `for`

loop to create the \(y\) values requires several steps. The first creates a container to hold the new values, using the `similar`

function to make a vector of the same size as `x`

below (but fills it with nonsense):

```
= similar(x);
y for i in 1:length(x)
= f( x[i] )
y[i] end
```

The `for`

loop ends with the keyword `end`

. Here we loop over each index of `x`

and assign to the corresponding `y`

value `f(x[i])`

.

Conceptually this is the opposite of `map`

where we think of the function acting on the entire column vector `x`

. Instead, we iterate one-by-one over the values of `x`

saving the function values as we go. The use of for loops is called *imperative programming*, as you describe each step. The use of functions like `map`

is called *declarative programming* as you simply declare what you want and the computer language does the rest.

In some languages for loops are avoided if possible, as they can be slower. As well, they can require extra bookkeeping, such as needing to allocate a container for the answers. That being said, in `Julia`

they are widely used for speed and storage reasons. As well, they are used when we need to refer to more than one index. An example of that is the following way to create a Fibonacci pattern from the formula \(x_i = x_{i-1} + x_{i-2}\):

```
= zeros(Int, 10); ## pre-allocate an integer array
x 1:2] = [1,1]
x[for i in 3:length(x)
= x[i-1] + x[i-2]
x[i] end
```

Related to a `for`

loop is the `while`

loop. This will repeat as long as some condition is true. The following pattern reproduces a `for`

loop:

```
= 1, length(x)
i, n while (i <= n)
print( x[i], " " ) ## do something ...
= i + 1
i end
```

We will use `while`

loops when we iterate some process and are waiting until some computed value gets close to \(0\).

Putting this altogether, to create the “T”-table used to graph \(y=x^2\), we could do any of these:

```
f(x) = x^2
= 1:4
xs = map(f, xs)
ys [xs ys]
```

```
4×2 Matrix{Int64}:
1 1
2 4
3 9
4 16
```

or

```
f(x) = x^2
= 1:4
xs = f.(xs)
ys [xs ys]
```

```
4×2 Matrix{Int64}:
1 1
2 4
3 9
4 16
```

or

```
= [1, 2, 3, 4]
xs = [x^2 for x in xs]
ys [xs ys]
```

```
4×2 Matrix{Int64}:
1 1
2 4
3 9
4 16
```

or

```
= 1:4
xs = similar(xs)
ys for i in 1:length(xs)
= xs[i]^2
ys[i] end
[xs ys]
```

```
4×2 Matrix{Int64}:
1 1
2 4
3 9
4 16
```

Many options, but the shortest to type is simply `[xs f.(xs)]`

, so that is what is used most commonly.

Does this command produce the values \(\{.1, .01, .001, .0001\}\)?

`= [(1/10)^i for i in 1:4] x `

Let \(f(x) = x^2 - 2x\). Which command will produce the \(y\) values for plotting \(f\) over \([0, 2]\)?

Will this command produce \(y\) values for plotting \(f(x)\) over \([0,1]\)?

```
f(x) = x^2 - 2x
f(x) for x in 0:1/100:1]; [
```

If one has two vectors `xvals`

and `yvals`

of equal size then creating a graphic for them is straightforward. The basic syntax is

`plot(xvals, yvals)`

For example, to plot \(y=x^2\) over \([-1,1]\) we might do:

```
f(x) = x^2
= range(-1, 1, length=101)
xs = f.(xs)
ys plot(xs, ys)
```

One can place both to get both points and lines. The `scatter`

function will plot the points, but not connect the lines. In the following, the `scatter!`

function is used. (Note the `!`

at the end.) This form adds the plot of the lines to the last graph, rather than make a new one.

```
= range(-2, 2, length=5)
xs = f.(xs)
ys plot(xs, ys)
scatter!(xs, ys, markersize=5)
```

Define \(f(x)\) to be a triangular function as follows:

`f(x) = max(0, 1.0 - abs(x))`

`f (generic function with 1 method)`

In many applications, the following transformation is employed:

\[ g(x, c, h) = \frac{1}{h} f(\frac{x - c}{h}) \]

For constants \(h\) and \(c\).

Make a graph of both \(f(x)\) and \(g(x, 1, 1/2)\) over the interval \([-2,3]\). Consult the graph to see which statement is true?

We saw that this will produce two graphs:

```
plot(sin, 0, 2pi)
plot!(x -> cos(x) > 0 ? 0.0 : NaN)
```

What is the sine curve doing when the flat line is drawn?

Make a graph of \(f(x) = x\), \(g(x) = \tan(x)\), and \(h(x) = \sin(x)\). Over the interval \([0,\pi/4]\). Based on this graph which of the following below seems correct?

As previously noted, We can use layering to plot two or more functions at once. For example, to graph both the sine and cosine function we have:

```
plot(sin, 0, 2pi)
plot!(cos)
```

Or to compare the effects of a simple transformation:

```
f(x) = x^2
g(x) = 15 + f(x-3)
plot(f, -10, 10)
plot!(g)
```

To print a heavier \(x\)-axis, we can graph the function \(y=0\), specified through the anonymous function `x -> 0`

:

```
f(x) = x^2 - 2
plot(f, -2, 2)
plot!(x -> 0)
```

The above, may also be done with `zero`

:

```
plot(f, -2, 2)
plot!(zero) # zero is a function returning 0, useful for programming in general.
```

plot([f,g],a,b)

There are various ways with `Plots`

to make multiple graphs at once. Two commonly seen ones are to pass in a vector of function, as with `plot([sin,cos], 0, 2pi)`

. For plotting with vectors, a matrix can be specified in which case *each* column specifies a different trace. For this, something like the following

```
= range(0, 2pi, length=101)
x = [sin.(x) cos.(x)] # two columns
ys plot(x, ys)
```

These styles are not utilized within these notes, though they can be convenient when many function are to be plotted at once.

Often we wish to plot a function derived from another function. For example, to add a secant or tangent line to a graph.

To illustrate, we can add a secant line, as follows for a specific `f`

, `a`

and `b`

.

```
f(x) = sin(x)
= 0, pi/2
a, b plot(f, a, b; legend=false)
secant_line(x) = f(a) + (f(b) - f(a)) / (b - a) * (x - a)
plot!(secant_line)
```

For creating secant lines, the `MTH229`

package provides a function `secant`

called with `f`

, `a`

, and `b`

that returns a *function*. To repeat the above, we might have:

```
plot(f, a, b; legend=false)
plot!(secant(f, a, b))
```

To name the secant line, it is suggested to so something like:

`= secant(f, a, b) sl `

```
Function of `x` to compute the secant line of `f` between `a` and `b`:
f(a) + ((f(b)-f(a)) / (b-a) * (x-a)
```

(This is in contrast to other other definitions of a function where `f(x)`

appear on the *left-hand* side of the definition; here just a variable name is used, as the function `secant`

returns a function object, we aren’t defining a function, just naming it.)

Environment of

`Julia`

when generated
`Julia`

version:

`VERSION`

`v"1.10.4"`

Packages and versions:

```
using Pkg
Pkg.status()
```

```
Status `~/work/mth229.github.io/mth229.github.io/Project.toml`
[a2e0e22d] CalculusWithJulia v0.2.6
[7073ff75] IJulia v1.25.0
[b964fa9f] LaTeXStrings v1.3.1
[ebaf19f5] MTH229 v0.3.2
[91a5bcdd] Plots v1.40.4
[f27b6e38] Polynomials v4.0.11
[438e738f] PyCall v1.96.4
[612c44de] QuizQuestions v0.3.23
[295af30f] Revise v3.5.14
[f2b01f46] Roots v2.1.5
[24249f21] SymPy v2.1.1
[56ddb016] Logging
```

For

*infix*functions, like`+`

, the dot appears before the operator, as with`.+`

.↩︎