`LogLevel(1001)`

# 68 Calculus plots with Makie

The Makie.jl webpage says

From the Japanese word Maki-e, which is a technique to sprinkle lacquer with gold and silver powder. Data is basically the gold and silver of our age, so let’s spread it out beautifully on the screen!

`Makie`

itself is a metapackage for a rich ecosystem. We show how to use the interface provided by the `GLMakie`

backend to produce the familiar graphics of calculus.

## 68.1 Figures

Makie draws graphics onto a canvas termed a “scene” in the Makie documentation. A scene is an implementation detail, the basic (non-mutating) plotting commands described below return a `FigureAxisPlot`

object, a compound object that combines a figure, an axes, and a plot object. The `show`

method for these objects display the figure.

For `Makie`

there are the `GLMakie`

, `WGLMakie`

, and `CairoMakie`

backends for different types of canvases. In the following, we have used `GLMakie`

. `WGLMakie`

is useful for incorporating `Makie`

plots into web-based technologies.

We begin by loading the main package and the `norm`

function from the standard `LinearAlgebra`

package:

```
using GLMakie
import LinearAlgebra: norm
```

The `Makie`

developers have workarounds for the delayed time to first plot, but without utilizing these the time to load the package is lengthy.

## 68.2 Points (`scatter`

)

The task of plotting the points, say \((1,2)\), \((2,3)\), \((3,2)\) can be done different ways. Most plotting packages, and `Makie`

is no exception, allow the following: form vectors of the \(x\) and \(y\) values then plot those with `scatter`

:

```
= [1,2,3]
xs = [2,3,2]
ys scatter(xs, ys)
```

The `scatter`

function creates and returns an object, which when displayed shows the plot.

### 68.2.1 `Point2`

, `Point3`

When learning about points on the Cartesian plane, a “`t`

”-chart is often produced:

```
x | y
-----
1 | 2
2 | 3
3 | 2
```

The `scatter`

usage above used the columns. The rows are associated with the points, and these too can be used to produce the same graphic. Rather than make vectors of \(x\) and \(y\) (and optionally \(z\)) coordinates, it is more idiomatic to create a vector of “points.” `Makie`

utilizes a `Point`

type to store a 2 or 3 dimensional point. The `Point2`

and `Point3`

constructors will be utilized.

`Makie`

uses a GPU, when present, to accelerate the graphic rendering. GPUs employ 32-bit numbers. Julia uses an `f0`

to indicate 32-bit floating points. Hence the alternate types `Point2f0`

to store 2D points as 32-bit numbers and `Points3f0`

to store 3D points as 32-bit numbers are seen in the documentation for Makie.

We can plot a vector of points in as direct manner as vectors of their coordinates:

```
= [Point2(1,2), Point2(2,3), Point2(3,2)]
pts scatter(pts)
```

A typical usage is to generate points from some vector-valued function. Say we have a parameterized function `r`

taking \(R\) into \(R^2\) defined by:

`r(t) = [sin(t), cos(t)]`

`r (generic function with 1 method)`

Then broadcasting values gives a vector of vectors, each identified with a point:

```
= [1,2,3]
ts r.(ts)
```

```
3-element Vector{Vector{Float64}}:
[0.8414709848078965, 0.5403023058681398]
[0.9092974268256817, -0.4161468365471424]
[0.1411200080598672, -0.9899924966004454]
```

We can broadcast `Point2`

over this to create a vector of `Point`

objects:

`= Point2.(r.(ts)) pts `

```
3-element Vector{Point{2, Float64}}:
[0.8414709848078965, 0.5403023058681398]
[0.9092974268256817, -0.4161468365471424]
[0.1411200080598672, -0.9899924966004454]
```

These then can be plotted directly:

`scatter(pts)`

The plotting of points in three dimensions is essentially the same, save the use of `Point3`

instead of `Point2`

.

```
r(t) = [sin(t), cos(t), t]
= range(0, 4pi, length=100)
ts = Point3.(r.(ts))
pts scatter(pts; markersize=5)
```

To plot points generated in terms of vectors of coordinates, the component vectors must be created. The “`t`

”-table shows how, simply loop over each column and add the corresponding \(x\) or \(y\) (or \(z\)) value. This utility function does exactly that, returning the vectors in a tuple.

`unzip(vs) = Tuple([vs[j][i] for j in eachindex(vs)] for i in eachindex(vs[1]))`

`unzip (generic function with 1 method)`

In the `CalculusWithJulia`

package, `unzip`

is implemented using `SplitApplyCombine.invert`

.

We might have then:

`scatter(unzip(r.(ts))...; markersize=5)`

where splatting is used to specify the `xs`

, `ys`

, and `zs`

to `scatter`

.

(Compare to `scatter(Point3.(r.(ts)))`

or `scatter(Point3∘r).(ts))`

.)

### 68.2.2 Attributes

A point is drawn with a “marker” with a certain size and color. These attributes can be adjusted, as in the following:

```
scatter(xs, ys;
=[:x,:cross, :circle], markersize=25,
marker=:blue) color
```

Marker attributes include

`marker`

a symbol, shape.`marker_offset`

offset coordinates`markersize`

size (radius pixels) of marker

A single value will be repeated. A vector of values of a matching size will specify the attribute on a per point basis.

## 68.3 Curves

The curves of calculus are lines. The `lines`

command of `Makie`

will render a curve by connecting a series of points with straight-line segments. By taking a sufficient number of points the connect-the-dot figure can appear curved.

### 68.3.1 Plots of univariate functions

The basic plot of univariate calculus is the graph of a function \(f\) over an interval \([a,b]\). This is implemented using a familiar strategy: produce a series of representative values between \(a\) and \(b\); produce the corresponding \(f(x)\) values; plot these as points and connect the points with straight lines.

To create regular values between `a`

and `b`

typically the `range`

function or the range operator (`a:h:b`

) are employed. The related `LinRange`

function is also an option.

For example:

```
f(x) = sin(x)
= 0, 2pi
a, b = range(a, b, length=250)
xs lines(xs, f.(xs))
```

`Makie`

also will read the interval notation of `IntervalSets`

and select its own set of intermediate points:

`lines(a..b, f)`

As with `scatter`

, `lines`

returns an object that produces a graphic when displayed.

As with `scatter`

, `lines`

can can also be drawn using a vector of points:

```
= [Point2(x, f(x)) for x ∈ xs]
pts lines(pts)
```

(Though the advantage isn’t clear here, this will be useful when the points are generated in different manners.)

When a `y`

value is `NaN`

or infinite, the connecting lines are not drawn:

```
= 1:5
xs = [1,2,NaN, 4, 5]
ys lines(xs, ys)
```

As with other plotting packages, this is useful to represent discontinuous functions, such as what occurs at a vertical asymptote or a step function.

#### Adding to a figure (`lines!`

, `scatter!`

, …)

To *add* or *modify* a scene can be done using a mutating version of a plotting primitive, such as `lines!`

or `scatter!`

. The names follow `Julia`

’s convention of using an `!`

to indicate that a function modifies an argument, in this case the underlying figure.

Here is one way to show two plots at once:

```
= range(0, 2pi, length=100)
xs lines(xs, sin.(xs))
lines!(xs, cos.(xs))
current_figure()
```

The `current_figure`

call is needed to have the figure display, as the returned value of `lines!`

is not a figure object. (Figure objects display when shown as the output of a cell.)

We will see soon how to modify the line attributes so that the curves can be distinguished.

The following shows the construction details in the graphic:

```
= range(0, 2pi, length=10)
xs lines(xs, sin.(xs))
scatter!(xs, sin.(xs);
=10)
markersizecurrent_figure()
```

As an example, this shows how to add the tangent line to a graph. The slope of the tangent line being computed by `ForwardDiff.derivative`

.

```
import ForwardDiff
f(x) = x^x
= 0, 2
a, b= 0.5
c = range(a, b, length=200)
xs
tl(x) = f(c) + ForwardDiff.derivative(f, c) * (x-c)
lines(xs, f.(xs))
lines!(xs, tl.(xs), color=:blue)
current_figure()
```

This example, modified from a discourse post by user `@rafael.guerra`

, shows how to plot a step function (`floor`

) using `NaN`

s to create line breaks. The marker colors set for `scatter!`

use `:white`

to match the background color.

```
= -5:5
x = 5eps() # for rounding purposes; our interval is [i,i+1) ≈ [i, i+1-δ]
δ = Float64[]
xx for i ∈ x[1:end-1]
append!(xx, (i, i+1 - δ, NaN))
end
= floor.(xx)
yy
lines(xx, yy)
scatter!(xx, yy, color=repeat([:black, :white, :white], length(xx)÷3))
current_figure()
```

### 68.3.2 Text (`annotations`

)

Text can be placed at a point, as a marker is. To place text, the desired text and a position need to be specified along with any adjustments to the default attributes.

For example:

```
= 1:5
xs = Point2.(xs, xs)
pts scatter(pts)
annotations!("Point " .* string.(xs), pts;
= 50 .- 2*xs,
fontsize = 2pi ./ xs)
rotation
current_figure()
```

The graphic shows that `fontsize`

adjusts the displayed size and `rotation`

adjusts the orientation. (The graphic also shows a need to manually override the limits of the `y`

axis, as the `Point 5`

is chopped off; the `ylims!`

function to do so will be shown later.)

Attributes for `text`

, among many others, include:

`align`

Specify the text alignment through`(:pos, :pos)`

, where`:pos`

can be`:left`

,`:center`

, or`:right`

.`rotation`

to indicate how the text is to be rotated`fontsize`

the font point size for the text`font`

to indicate the desired font

#### Line attributes

In a previous example, we added the argument `color=:blue`

to the `lines!`

call. This was to set an attribute for the line being drawn. Lines have other attributes that allow different ones to be distinguished, as above where colors indicate the different graphs.

Other attributes can be seen from the help page for `lines`

, and include:

`color`

set with a symbol, as above, or a string`label`

a label for the line to display in a legend`linestyle`

available styles are set by a symbol, one of`:dash`

,`:dot`

,`:dashdot`

, or`:dashdotdot`

.`linewidth`

width of line`transparency`

the`alpha`

value, a number between \(0\) and \(1\), smaller numbers for more transparent.

#### Simple legends

A simple legend displaying labels given to each curve can be produced by `axislegend`

. For example:

```
= 0..pi
xs lines(xs, x -> sin(x^2), label="sin(x^2)")
lines!(xs, x -> sin(x)^2, label = "sin(x)^2")
axislegend()
current_figure()
```