Plotting in Julia#
There are a number of popular plotting libraries for Julia, each with their own tradeoffs. Here we’ll give a brief overview of one of the most popular - Plots.jl - as it is the easiest to pick up, and is very flexible.
We’d also recommend installing LaTeXStrings.jl as well, which provides a special L”” string format that parses LaTeX markup inside the string, as it makes titles etc. for plots much more professional.
As always, we need to load the library first:
using Plots, LaTeXStrings #if you didn't install it already, you would need to use Pkg to add Plots first
[ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]
Basic Plots#
The plotting functions provided take arrays of points, so lets make a set of 100 points from 0 to 2π, and then evaluate sin and cos for them:
x = [i*π/50 for i = 0:100]
y = sin.(x)
y2 = cos.(x);
The basic plot is then easy (and should be reminiscent of matplotlib). Note that the Arrays used to provide multiple series must be column vectors - Plots assumes points in a series are in the row direction.
p = plot(x,[y y2], title=L"Plots of $\sin(x)$ and $\cos(x)$ for $x$ from $0$ to $\pi$", label=[L"\sin(x)" L"\cos(x)"])
#storing the plot reference in a var is optional if we only want to modify the current plot
We can easily modify a plot object to add new graphs. As always, Julia convention is that a function that modifies existing state has a !
at the end - in this case, we’re explicitly specifying the plot to alter as the first argument, but Julia’s multiple dispatch allows us to also omit the plot (and thus alter the active - usually the most recent - plot implicitly).
We’re also demonstrating Plots’ support for interpolating functions - here we’re passing the function cos2
to plot, and it evaluates it at all the points it needs to plot the series.
cos2(x) = cos(x)^2
plot!(p, x, cos2, label=L"\cos^2(x)")
#or plot!(x, y.^2, label=L"\cos^2(x)") since this is the "active" plot
Plot Properties#
Plot takes the usual options to specify properties of the plot, as you will have seen above.
Some of these have special functions to allow us to quickly modify only them in a plot (without needing a whole plot! function call):
title!(L"$\sin$, $\cos$, $\cos^2$ from $0$ to $2\pi$")
We can select different plot types by setting the seriestype
property for a given series, even when modifying an existing plot.
plot!(x, y2, seriestype=:scatter, label="scatter cos")
Or, equivalently, by using a function with the same name as the seriestype
we want (line
is the default plot type) - here we’re also setting the colour and shape for the markers plotted.
scatter!(x, y, label="scatter plot sin", markercolor=:red, markershape=:hexagon)
Layout and Subfigures#
Plots also supports more advanced options like layout for subfigures, and so on - here layout
distributes the two series into separate subfigures - the tuple’s geometry is (vertical , horizontal) subdivisions, but we could also just let it know the number of subplots we want, and let it pick a good arrangement by providing just a number.
plot(x, [y y2], layout=(2,1), seriestype=[:line :histogram])
For more complex set-ups, the @layout
macro can make a layout from a nested 2d Array, which it maps to the plots left-to-right, top-to-bottom within sub-figures.
plot
itself also has an alternate form which takes existing plots as the first inputs, allowing you to easily combine a complex layout with individual control of each plot after the fact - again, here, multiple dispatch allows the correct version of plot to be called naturally so we don’t have to remember many different functions.
two_and_two = @layout [ a{0.5w} [ b ; c ] ] #a,b,c are arbitrary placeholders for a plot position
p2 = plot(x, (x->x^2).(x), label=L"x^2")
p3 = plot(x, (x->exp(x)).(x), label=L"e^x")
plot(p,p2,p3, layout=two_and_two)
Multidimensional Plots#
Plots also, of course, supports multidimensional data, for example via contour or surface plots:
heights = ( (x,y) -> sin(x)*cos(y) ).(x',x)
cont_p = contour(x,x,heights, fill=true) #or plot(x, x, heights, seriestype=:contour, fill=true)
threeD_p = surface(x,x,heights, c=:Pastel1_3)
plot(cont_p, threeD_p, layout=2, size=(1200,400))