Skip to main content

Chapter 14 Using Makie for Plots

As discussed in Chapter 13, one of the main plotting environments for Julia is Makie, a relatively new plotting environment that had a goal to develop a completely Julia-based environment that was designed to "create publication-quality vector graphics, animated movies and interactive data exploration tools. Most options that are available today lack one or more of the following attributes:" (cite Makie paper).

Section 14.1 Basic Plotting

Before plotting, make sure that you have the packages Makie and CairoMakie installed. The package CairoMakie is the backend package that does the plotting using the common interface (API) in the Makie package. Once the CairoMakie package is installed, to set this to the Makie backend enter:
x=1:10
y=[3.2,-4.5,7.8,4.2,-2.0,5.4,7.8,-2.4,-3.1,3.9]
where the 3rd line above will allow the plots to appear inside a notebook interface instead of as a separate window. As an example, we’ll use the scatter command on a pair of vectors.
x=1:10
y=[3.2,-4.5,7.8,4.2,-2.0,5.4,7.8,-2.4,-3.1,3.9]
scatter(x,y)
which results in the plot
Scatter plot of points with x values between 1 and 10 and y values between -5 and 8.
Figure 14.1. Scatter plot of some sample data
There are clearly a lot of options available for plots. It is important to understand the difference between altering the plot (say changing the style or color of the markers) and the axes (showing the grid or changing the limits). We will discuss all of these differences below, but an example to change the marker would be
fig = scatter(x,y, marker = :star8, markersize = 20, color = :red)
resulting in
Scatter plot of points with x values between 1 and 10 and y values between -5 and 8. The markers are 8-pointed red stars that are about twice the standard size.
Figure 14.2. Scatter plot of some sample data with non-standard marker style
To examine the list of markers and all other options for scatter, see the Makie documentation for scatter. Also, the Makie documentation for colors is helpful although you can see that there are many options. If you are only interested the the named colors, see the listing in the Colors.jl package, which is automatically loaded by Makie.
If instead we wish to make a line plot (connect the points by lines), simply use the lines function as in
lines(x, y)
resulting in
Line plot of points with x between 1 and 10 and y between -5 and 8.
Figure 14.3. Line plot of some sample data
to create a function plot, we can use either scatter or lines but typically use a line plot. For example
lines(0..2pi, sin)
and if the presence of sin by itself in the function seems odd to you, one can use lines(0..2pi, x -> sin(x)) that is an anonymous function notation instead. The first argument is a plotting range explained below. The result is
Plot of sin(x) from 0 to 2pi.
Figure 14.4. Plot of \(\sin(x)\) from 0 to 2\(\pi\text{.}\)
Typically it would be nice to use units of \(\pi\) for the x-axis labels, and we will be able to do that later.
You may have noticed that for the function plot above, the first argument is 0..2pi. We haven’t seen this structure before. Entering typeof(0..2pi) results in
ClosedInterval{Float64} (alias for IntervalSets.Interval{:closed, :closed, Float64})
indicating that this structure is part of the IntervalsSets package (that is a dependency of Makie). This makes plotting functions quite nice.
Similar to scatter plots, lines plots have options as well including linestyle, color and linewidth. The following is an example of changing all of these:
fig = lines(0..2pi, x -> sin(x), color = :darkgreen, linewidth = 10, linestyle = :dashdot)
which has the following output:
Scatter plot of points with x values between 1 and 10 and y values between -5 and 8.
Figure 14.5. Line plot of sine of x with styling on the line.
For all of the options of the lines plots, see the Makie documentation for lines.

Section 14.2 Updating the Axis object

We saw above how to update the options of the plot object, that is the markers for a scatter plot or the line segments in a lines plot. There are also options to the Axis object, like changing the limits or tick marks or including title or axis labels. As in common in Makie, there are multiple ways of accomplishing this and we will cover two of these. First, we will look at passing Axis options via the axis keyword. Alternatively, we will get a Axis object from a plot and then update the options.
Let’s start with just including a title to the Axis. The following is a simple way to do this.
fig = lines(0..2pi, sin, axis = (title = "Plot of sin(x)",))
where we use the axis option, which is common to all 2D plots. The axis option needs to be a named tuple with names coming from options to the Axis object. Although it may seem like a mistake, there is a comma after the string that is the end of the title, however, without the command, to the right of axis = is not a named tuple and there will be an error. The result of the command above is
Sine function plot on 0 to 2pi with title "Plot of sin(x)".
Figure 14.6. Sine plot with title
If you have multiple options, then it does not need to end with a comma. For example,
lines(0..2pi, sin, axis = (title = "Plot of sin(x)", xticks=0:pi/2:2pi))
produces the plot
Sine function plot on 0 to 2pi with title "Plot of sin(x)" and xticks from 0 to 2pi with pi/2 spacing.
Figure 14.7. Sine plot with title and changed xticks
If there are a lot of changes that are to be made to the axis option, this may be confusing if they are all inside the given plotting command. An alternative is to get the Axis object that the plotting routine created and then update the axis. Here’s an example how to both update the xlabel (label on the x-axis) and the tick marks along the x-axis.
fig, ax = lines(0..2pi, sin)
lines!(ax, 0..2pi, cos)
fig
And this results in the plot:
A scatter plot with the x-axis labeled "Num." and the tick marks set for integers 1,2, ..., 10.
Figure 14.8. Scatter plot with updated x-axis label and tick marks
Some comments about the code above. Notice that we have assigned the scatter method to the tuple fig, axis. The first is the Figure object that the scatter plot produces and the second is the Axis object. This is helpful for updating either, however most aspects of a plot that needs to be updated falls onto the Axis object. The 2nd and 3rd lines above update the Axis, which is technically a mutable struct and we use the same dot notation that we have with structs and tuples.
There will be other examples of changing the Axis object later in this and subsequent chapters. It always a good idea to look at the Axis documentation for all details. The two methods in this section should work to update any of the axis options. As yet another alternative, below we will see how to create an Axis object with desired properties, however if there are just a few alterations to an Axis, one of the methods here is preferred.

Section 14.3 Adding Additional plots to an Axis

We often want two plots (say two function plots or a function and scatter plot) on the same axes. In short, the way to do this is to get the variable representing the Axis. The technique in this section is to get the Axis associated with a plot and then add a line plot to the Axis. In the next section, we see a different technique, especially helpful for more complex layouts.
As an example, we will plot a sine curve with the following:
fig, ax = lines(0..2pi,sin)
which will produce the following plot:
A plot of sin(x) on the interval [0,2pi]
Figure 14.9. A plot of sin(x)
The left hand side of the assignment operator is fig, ax, which returns the created Figure and Axis objects when making a plot. Adding another plot to the one above is now relatively easy:
fig, ax = lines(0..2pi, sin)
lines!(ax, 0..2pi, cos)
fig
and note that the command is lines! because it modifies the ax variable. Also to get this to appear, the last line fig is used to get the plot to show. The result is
(for accessibility)
Figure 14.10. A plot with two function graphs: sin(x) and cos(x).
It would be helpful to have a legend to distinguish the two curves. We will learn how to add this to the plot in Subsection 14.6.2.

Note 14.11.

To include mutiple plots (different curves or scatter and a line plot) for example, use the ! version of the plot type. When using the ! version, the first argument should be the axis object that you want to place the plot in. You will see an error if the first argument is not an Axis object.

Section 14.4 Figures and Grid Layout in Makie

In the section above, we were able to get the figure and axis associated with a plot. This was helpful for either adding other plots to an axis or updating the axis. In this section, we will build a plot starting with Figure and Axis objects. This is mainly for more complex layouts, but is also an alternative to the methods from the previous sections.
First, a plot needs a Figure container and this can be created with:
fig = Figure()
And upon running this, you will see an empty figure (white square) that we need to add things to. Although this is not so interesting, it is important. There are many things that happen when creating a figure, but most importantly, there is a grid layout that is created. To place items in the grid, typically plots need to occur on axes, so we will place axes in a layout with row/column indexing. For example
fig = Figure()
ax1 = Axis(fig[1,1], title = "Axis 1")
ax2 = Axis(fig[2,1], title = "Axis 2")
ax3 = Axis(fig[1,2], title = "Axis 3")
ax4 = Axis(fig[2,2], title = "Axis 4")
fig
Overall the output of this is
A figure with four axes in a 2 by 2 grid, labelled "Axis 1", "Axis 3", "Axis 4" and "Axis 2" clockwise from the upper left.
Figure 14.12. A 2 by 2 grid layout of a figure with 4 axes.
and you should notice many things. We can add a Axis to a plot (or four of them) without any plot within them. We will learn how to add a plot to an axis below. Above, the axes were placed by adding a row and column to the fig (Figure) above where the row and column is used in an array like notation. Notice that fig[1,2] places the axis in the first row, second column. Also, the default plotting window (limits) for an Axis is between 0 and 10.
You may wish to stretch an Axis across multiple rows or columns. Here’s an example where the first row has one axis that stretches across 3 columns and the second row has 3 axes.
fig = Figure()
ax1 = Axis(fig[1,1:3], title = "Axis 1")
ax2 = Axis(fig[2,1], title = "Axis 2")
ax3 = Axis(fig[2,2], title = "Axis 3")
ax4 = Axis(fig[2,3], title = "Axis 4")
fig
A grid layout with one axis on the first row and 3 in the second row. The top row axis is labelled "Axis 1" and the bottom three are labelled "Axis 2", "Axis 3" and "Axis 4" from left to right.
Figure 14.13. A grid layout with one axis on the first row and 3 in the second row.

Section 14.5 Axis Options

We saw above how to place an Axis object inside a Figure. Upon creating the Axis, we can give other options. We will cover some of the important ones here, and then refer to the documentation. The first option to an Axis is a title that we saw above. Just pass the title in as a string. Other basic options are the xlabel and ylabel. The following code
fig = Figure()
ax = Axis(fig[1,1], title = "My Plot", xlabel = "x label", ylabel = "ylabel")
fig
results in
An empty plot with title "My Plot", xlabel of "x label" and ylabel as "y label".
Figure 14.14. An empty plot with values for the title, xlabel and ylabel.
Setting the limits on the axes is done with the limits option. For example:
fig = Figure()
ax = Axis(fig[1,1], limits = (-5,5,0,20))
fig
and notice the last line above or fig will show the figure. Nothing will be shown if this isn’t there. The result is
An empty plot with limits in the x-direction from -5 to 5 and in the y-direction from 0 to 20.
Figure 14.15. An empty plot with updated limits.
where the specification is limits = (xmin, xmax, ymin, ymax).
There are plenty of other options available for an Axis. See the documentation on Axis for more information. One big thing to note is the separation of axis options (anything that isn’t a plot) should be done to the Axis object, whereas as we will see below, changes to the plot will go on the individual plotting function. We will see other examples of this below.

Section 14.6 Adding Plots to Axes

Even though we can do some elaborate layout of axes, we haven’t done any plotting on them. In fact, there are two ways to plot via Makie. First, as we saw above, we can use plotting functions like lines or scatter to make plots. This is fine for relatively simple plots or just for a quick plot using defaults. If we desire additional features to a plot, generally we will create Figures and Axis objects and the add plots to them with commands like lines! or scatter! (note the !). Recall that convention in Julia is if an argument is being modified that the name should end in a !.
Let’s repeat the scatter plot at the top of this chapter. If we do:
x = 1:10
y = [3.2,-4.5,7.8,4.2,-2.0,5.4,7.8,-2.4,-3.1,3.9]
fig = Figure()
ax = Axis(fig[1,1], title = "Simple Scatter Plot", limits = (0,11,-10,10))
scatter!(ax, x, y)
fig
where we have set the limits to make them symmetric above and below the \(x\)-axis.
A scatter plot with sample data in which the limits are from 0 to 11 in the x-direction and from -10 to 10 in the y-direction.
Figure 14.16. A scatter plot with sample data in which the limits have been updated.
This is the way to include either multiple function plot or a scatter and function plot on the same axes. Consider the scatter plot from Chapter 13 which is the data from CO₂ levels. We can add an exponential function to them as well in the following way.
 1 
The data is available at this NOAA webpage and should be downloaded and saved in the same directory as your Julia notebook.
.
fig = Figure()
ax = Axis(fig[1,1], xlabel = "year", ylabel = "ppm CO2")
scatter!(ax, co2.year, co2.mean)
lines!(ax, 1958..2023, t->exp(-3.1637+0.00454247t), color = :darkorange)
fig
resulting in the following.
A scatter plot with an exponential increase from 320 ppm in 1960 to 420 in 2023 together with an exponential function that closely follows the points.
Figure 14.17. A scatter plot of CO₂ data and an exponential fit.
The exponential was found in a way similar to that of fitting curves in Chapter 28.

Subsection 14.6.1 Placing plots on different axes

Above, we saw adding different axes to a Figure by placing Axis objects in a grid. We can add plots to these axes using the scatter! or lines! methods where the first argument is the axis number where we wish to place the plot. As an example:
fig = Figure()
ax1 = Axis(fig[1,1], title="Axis 1")
ax2 = Axis(fig[2,1][1,1], title = "Axis 2")
ax3 = Axis(fig[2,1][1,2], title = "Axis 3")
lines!(ax1, 0..10,sin)
lines!(ax2, 0..10, t-> 10*exp(-t))
scatter!(ax3,0:10,10*rand(11))
fig
and the result is
(for accessibility)
Figure 14.18. An example of multiple plots on different axes.

Subsection 14.6.2 Adding a Legend

The example above with the sine and cosine curves beg the question of how to add a legend to a plot, which is usually a given when there are multiple plots on a given set of axes. We can do this with the example above by giving each curve a label and then adding a Legend to the Figure. The following will do this:
fig, ax = lines(0..2pi, sin, label="sin(x)")
lines!(ax,0..2pi, cos, label="cos(x)")
Legend(fig[1,2], ax)
fig
where first notice that we have added a label to each curve as a string and then the 3rd line will create a Figure and place it to the right of the plot (because of the fig[1,2]). The resulting plot is
(for accessibility)
Figure 14.19. The plots of sine and cosine together with a legend to the right.
We can still use the method of creating Figures and Axis objects above to create this as well. The following will produce the same plot:
fig = Figure()
ax = Axis(fig[1, 1])
lines!(ax, 0 .. 2pi, sin, label="sin(x)")
lines!(ax, 0 .. 2pi, cos, label="cos(x)")
Legend(fig[1, 2], ax)
fig
If instead you want a legend that sits inside the axis, we can use the axislegend method.
fig, ax = lines(0..2pi,sin,label="sin(x)")
lines!(ax,0..2pi,cos, label="cos(x)")
axislegend(ax)
fig
which produces the plot:
(for accessibility)
Figure 14.20. The plot of sine and cosine with the legend inside the axes box.
The location of the legend isn’t great in this situation. One can add the location option to the axislegend method which is a symbol of two characters, the first being "l", "r" or "c" for left, right or center for the horizontal placement and the second being "t", "b" or "c" for top, bottom or center for the vertical placement. Alternatively, it can be set as a tuple that is interpreted as the horizontal and vertical location as fractions from the lower left. To slide the legend box over just a bit we can use
fig, ax = lines(0..2pi,sin,label="sin(x)")
lines!(ax,0..2pi,cos, label="cos(x)")
axislegend(ax, position = (0.8, 1))
fig
and the result is
(for accessibility)
Figure 14.21.

Subsection 14.6.3 Adding Nicer Tick Labels

We saw above when plotting a trigonometric function that we often would like to use multiples of \(\pi\) for the x tick marks. We’ve seen that if we make multiples of \(\pi\text{,}\) we get floating point approximations on the axes. We will use a new package LaTeXStrings to use the power of LaTeX to make nicer looking plots.
First, make sure that you have added LaTeXStrings to your julia installation and include using LaTeXStrings to your notebook. In short, this package just makes it easier to enter latex into strings to be properly rendered. If you want to enter \frac{\pi}{2} into a julia string (and this is true in many languages), because backslash is a special character, to enter a backslash, we’d need to add \\. Therefore the string above would be "\\frac{\\pi}{2}" and although this isn’t too hard, LaTeXStrings makes it easier. It provides the string macro L as in
L"\frac{\pi}{2}"
and this will produce the latex output \(\frac{\pi}{2}\text{.}\)We will use this to produce nicer tick labels. But first, let’s just use LaTeXStrings to make a nicer title. The code
lines(-2..2,x -> x^2, axis = (title = L"A plot of $x^2$",))
In this case, we have used the axis option of the lines function, recalling that the axis needs to take a named tuple and if there is only one value, a trailing comma is necessary. The result of this is
(for accessibility)
Figure 14.22.
The following will produce a sine curve with nicer x-labels.
tick_pos = 0:pi/4:2pi
xlabels = [L"0", L"\frac{\pi}{4}", L"\frac{\pi}{2}", L"\frac{3\pi}{4}",
  L"\pi", L"\frac{5\pi}{4}", L"\frac{3\pi}{2}", L"\frac{7\pi}{4}", L"2\pi"]
fig = Figure()
ax = Axis(fig[1, 1],
  xticks=(tick_pos, xlabels),
  title=L"Sine Wave with $\pi$ Multiples"
)
lines!(ax, 0 .. 2pi, sin)
fig
(for accessibility)
Figure 14.23.
Notice that the tick_pos variable on line 1, defines where the ticks will be located on the \(x\)-axis. The xlabels is an array of latex strings. If there is a way to simplify this, then you can use a comprehension, a map or a loops to do this, but for simplicity, we just type these out. And then lastly, notice that these two variables are fed to the Axis using the xticks option as a tuple.

Section 14.7 Implicit Plots

Recall that in Subsection 13.4.6, an implicit plot is the set of points \((x,y)\) in which \(f(x,y) = c\) for some function \(f\) and constant \(c\text{.}\) As shown in that section, the classic example of this is that of a circle in the form \(x^2+y^2=1\text{.}\) Using makie, we use the contour function (more on this function below) as in
xs = ys =  LinRange(-1.25, 1.25, 100)
contour(xs, ys, (x, y) -> x^2 + y^2 - 1, levels=[0], 
  axis=(limits = (-1.2, 1.2, -1.2, 1.2),))
where there are \(x\) and \(y\) points defined to create a grid, a function (in this case we use an anonymous one) and the option levels=[0] to create the correct plot. The result of that above is:
(for accessibility)
Figure 14.24.
Wait. You said we’re plotting a circle, but this clearly is not a circle. Looks like an ellipse. The reason this occurred is that the aspect ratio of the plot is not one, therefore an object that we would expect to have a certain form may not.
 2 
Another classic example is that if there are normal lines either to a curve or two each other, if the aspect ratio is not one, they will not look to be normal/perpendicular.
We add the apsect = 1 as an option to an Axis as in
xs = ys =  LinRange(-1.25, 1.25, 100)
fig = contour(xs, ys, (x, y) -> x^2 + y^2 - 1, 
  levels=[0], axis=(limits = (-1.2, 1.2, -1.2, 1.2), aspect = 1))
and this produces the expected plot:
(for accessibility)
Figure 14.25.

Check Your Understanding 14.26.

An elliptic curve is the implicit graph of
\begin{equation*} y^2 = x^3 + ax + b \end{equation*}
for constants \(a\) and \(b\text{.}\) Produce a few graphs for different values of \(a\) and \(b\text{.}\)

Section 14.8 Surface Plots

If we have a function of two variables, a nice plot that shows the function is that of a surface plot, in which the height of the surface is the value of the function. A function of two variables is \(f(x,y) = x^2+y^2\) and we can plot this using Makie with the surface function.
xs = ys = LinRange(-3,3,100)
zs = [x^2 + y^2 for x in xs, y in ys]
surface(xs, ys, zs, axis=(type=Axis3,))
and the result in
(for accessibility)
Figure 14.27.
Notice that the option axis=(type=Axis3,) is used. This gives a proper perspective for the plot. Try removing it to see the result.
For a more interesting plot, we examine
\begin{equation} f(x,y) = \sin\left(\frac{1}{2}x^2-\frac{1}{4}y^2+2\right)\cos(x+y)\tag{14.1} \end{equation}
although the above code will also produce a plot, here’s some different options.
f(x, y) = sin(0.5x^2 - 0.25y^2 + 2) * cos(x + y)
xs = ys = LinRange(0, pi, 101)
zs = [f(x, y) for x in xs, y in ys]
fig = Figure()
ax = Axis3(fig[1,1],
  azimuth = 0.25pi,
  elevation = 0.1pi,)
surface!(ax, xs, ys, zs, colormap = :plasma)
fig
which results in
(for accessibility)
Figure 14.28.
Overall, the structure is the same in which there is a grid created (line 2) that both \(x\) and \(y\) take on values in \([0,\pi]\) and then use the function to create the \(z\) values. This time, we create a Figure and Axis object, however, in this case, we need an Axis3 object.
We also change the perspective of the plot with the azimuth (the angle of rotation around the \(z\)-axis) which can take on values between 0 and \(2pi\text{.}\) The elevation option is the angle that the viewpoint is above or below the \(xy\)-plane. Values can be between \(-\pi/2\) and \(\pi/2\text{.}\) Try changing these to see the view point change.
Notice also that we have added a new option \(colormap\) which changes the colors of the height of the surface plot. Above is :plasma and all of the colors are Symbols (start with a colon). There are hundreds of options, but the easiest way to see what is available at Makie’s color documentation page. Try changing these. There are also ways of creating custom colormaps.

Section 14.9 Contour Plots

As mentioned in Chapter 13, a contour plot is generally used for functions of two variable, like \(f(x,y)\) and the plot is curves of constant function value or \(f(x,y)=C\) for various values of \(C\text{.}\) Using the function in (14.1), the following code will produce a contour plot of the function:
x = y = LinRange(0,pi,101)
fig = contour(x, y, f)
which results in the plot:
(for accessibility)
Figure 14.29.
And recall that a contour plot is basically like a topographical map if you have ever used one of those. The concentric circles are either a hill (maximum) or a depression (minimum) and unless we know what function values, we’re not sure which is why. To help with this we will add labels to the contours and increase the number of contours used with the levels attribute.
x = y = LinRange(0,pi,101)
fig = contour(x, y, f, labels = true, levels = 11)
and this results in
(for accessibility)
Figure 14.30.
and you can see from the values of the contours that there is a minimum near \((1,2)\) and a maximum near \((2.5,0.8)\)
Another related plot is that of a filled contour plot in which the regions between contours are filled with colors. This is more of a visually nice feature rather than an important distinction over the previous contour plot. A filled contour plot can be created with the contourf plotting command as in this example:
x = y = LinRange(0,pi,101)
fig = contourf( x, y, f, levels = 11)
resulting in
(for accessibility)
Figure 14.31.
And since the colors play an important role in a filled contour plot, it is helpful to know the function values for a give color and using a colorbar is a way to do this. We can add a colorbar with the following code:
x = y = LinRange(0,pi,101)
fig = Figure()
ax = Axis(fig[1,1])
contourf!(ax, x, y, f, levels = 11)
Colorbar(fig[1,2])
fig
where we have used the layout methods described in Section 14.4 because we need to specify where the colorbar goes. The result of this is
(for accessibility)
Figure 14.32.

Check Your Understanding 14.33.

Note that the plotting range is \([0,\pi]\) in both \(x\) and \(y\) for all of these plots. Use the methods from above to 1) make the aspect ratio 1 and 2) change the tick marks to multiples of \(\pi\text{.}\)

Section 14.10 Vector Field and Stream plots

There are a number of types of plots that display the direction of flow of a function. This section goes over a few of these.
First, consider a vector field which is is a pair of functions of \(x\) and \(y\) often written as \(\vec{v} = \langle F(x,y), G(x,y) \rangle\text{.}\) For any point in the plane \((x,y)\text{,}\) the vector \(\vec{v}\) is a vector. For example, consider \(v=\langle y, -x \rangle\text{.}\) We first start with the arrows2d method:
xs = ys = LinRange(-3, 3, 11)
u = [y for x in xs, y in ys]
v = [-x for x in xs, y in ys]
arrows2d(xs, ys, u, v)
results in the following plot:
(for accessibility)
Figure 14.34.
This is a bit hard to read because the arrows overlap. This is mainly because the arrow length are exactly the size of the vector field at the point. For example at \((1,2)\text{,}\) the vector is \(\vec{v} = \langle 2, -1 \rangle\) and the length of this is \(\sqrt{5}\approx 2.23.\text{,}\) which overlaps nearby arrows. One inital way to address this is to set the lengthscale attribute. Also, in my opinion the arrows seem a bit heavy and we can change this with the shaftwidth and tipwidth options as follows:
arrows2d(xs, ys, u, v, lengthscale = 0.25, shaftwidth = 2, tipwidth = 8)
which creates the following plot:
(for accessibility)
Figure 14.35.
Another way to handle this is to produce a direction field which normalizes all of the arrows to make them the same length to do this. There is a option called normalize that does this as in the following:
arrows2d(xs, ys, u, v, normalize = true, lengthscale = 0.5, shaftwidth = 2, tipwidth = 8)
which produces the plot:
(for accessibility)
Figure 14.36.
Since Makie is very good with color, there are some options to make this a bit more colorful. The arrowcolor and linecolor can be used with the str variable to give each arrow a color. The following:
strength = vec(sqrt.(u .^ 2 .+ v .^ 2))
arrows2d(xs, ys, u, v, normalize = true, lengthscale = 0.4, shaftwidth = 2, tipwidth = 8, color = strength)
will produce the following plot:
(for accessibility)
Figure 14.37.
Note that the strength variable is a Matrix and both arrowcolor and linecolor can take a color, but also a vector of values. This is why the str variable is wrapped in the vec method.
A streamplot is related to a vector field plot (arrow plot) in that the arrows follow along continuous curves that are also plotted. A difference for plotting these in Makie is that instead of building the vector field, that the function is given and then plotted on the given plotting domain. We will plot the same field above with:
streamplot(x->Point2f(x[2], -x[1]), -2..2, -2..2)
which produces the following:
(for accessibility)
Figure 14.38.
Note that the first argument of the streamplot is a function of x a vector to a Point2f object. For the vector field plots above using the arrows2d function, we created a grid of points and notice that streamplot does not. This looks more like a function plot with the a..b notation. This is due to the fact that the streams are continuous functions—the plot above are circles.

Section 14.11 Updating axis elements in a shorthand manner

As we have seen above, updating information from an axis requires setting options on the axis object. We have accomplished this by first making a Figure and then an Axis object and finally adding plots to the axis. This is sometimes overkill. In this section, we will see an alternative if the options are short.
For example, let’s produce a function plot and put a title on it. For example,
fig = Figure()
ax = Axis(fig[1,1], title = L"A graph of $x^2$")
lines!(ax, -2..2, x -> x^2)
fig
which produces the plot
(for accessibility)
Figure 14.39.
Alternatively, one can add an axis attribute to the lines method to do the same as in
lines(-2..2,x -> x^2, axis = (title = L"A plot of $x^2$",))
which produces the same plot as above.

Note 14.40.

An astute eye notices the comma after the string that is the title option. This is not a typo. Try removing it and you’ll see an error. Why is that needed then?
The axis keyword option to the lines function needs to be a named tuple. Without the comma, try to create a named tuple with one element with
(a = "string")
the output is "string", it doesn’t appear to be a tuple. What the above has done is just assign the string "string" to the variable a. To create this as a tuple a comma is needed as in (a = "string",) and the result is the desired output.

Section 14.12 Backends for Makie

As described in Section 13.5, Makie is a set of high level plotting commands. The hard work of drawing lines, circles and regions on the screen is done with a backend and the idea is to be able to switch backends easily without changing the high-level code to produce a plot. Makie has four such options currently: CairoMakie, GLMakie, WGLMakie and RPRMakie and you should have seen the first two appear above in the plotting code.
CairoMakie
CairoMakie uses the Cairo drawing engine underneath and excels at high-quality 2D drawings that are non-interactive. The output in generally either an SVG or PDF and since these are vector-based drawing formats, these will produce high-quality graphs for print (and the screen).
GLMakie
GLMakie is the native, desktop-based backend, and is the most feature-complete. It requires an OpenGL enabled graphics card with OpenGL version 3.3 or higher.
It appears that almost all graphics cards support OpenGL and thus GLMakie should work for nearly all computers.
RPRMakie
According to the RPRMakie page:
Experimental ray tracing backend using AMDs RadeonProRender. While it’s created by AMD and tailored to Radeon GPUs, it still works just as well for NVidia and Intel GPUs using OpenCL. It also works on the CPU and even has a hybrid modus to use GPUs and CPUs in tandem to render images.
WGLMakie
According to the WGLMakie page:
WGLMakie is the web-based backend, which is mostly implemented in Julia right now. WGLMakie uses Bonito to generate the HTML and JavaScript for displaying the plots. On the JavaScript side, we use ThreeJS and WebGL to render the plots. Moving more of the implementation to JavaScript is currently the goal and will give us a better JavaScript API, and more interaction without a running Julia server.