Tutorial: Making Plots with Julia

Overview

This tutorial will give some examples of plotting and plotting features in Julia, as well as providing references to some relevant resources. The main plotting library is Plots.jl, but there are some others that provide useful features.

Some Resources

Making a Basic Plot

Let’s walk through making a basic line or scatter plot in Julia, using Plots.jl1.

  • 1 There are some other plotting libraries in Julia, but Plots.jl is a standard starting point. Feel free to experiment, though!

  • Since we’ll be generating random numbers, let’s import Random.jl to let us set a seed to reproduce the same plot in addition to Plots.jl.

    using Plots
    using LaTeXStrings
    using Measures
    using Random
    Random.seed!(1);

    First, to generate a basic line plot, use plot():

    y = rand(5)
    plot(y, label="original data", legend=:topleft)

    We could also explicitly pass \(x\)-axis coordinates by passing an array with these coordinates first, as in plot(x, y, ...). If only one array is passed, Plots.jl will interpret the values as \(y\) coordinates and use their indices for the \(x\) positions.

    Notice the use of the label and legend keywords to label the plot element and position the legend. To not label a particular plotting element, use label=false, and to turn off any legend (including a colorbar) from the plot, use legend=false.

    Now we can add some other lines and point markers. We will use plot! and scatter! to add another line and some points.

    Mutating Function

    The exclamation mark says that plot!() is a mutating function, which changes an existing variable instead of creating a new one. In this case, these functions change or add to an existing plot, instead of creating a new one.

    Notice the arguments in plot!() and scatter!(), which let us set properties for the line and scatterplot markers.

    y2 = rand(5)
    y3 = rand(5)
    plot!(y2, color=:red, linewidth=2, linestyle=:dot, label="new data")
    scatter!(y3, markercolor=:black, markershape=:square, markersize=5, label="even more data")

    Let’s now add axis labels. We can use LaTeX syntax to add mathematical markup elements to labels (such as superscripts, subscripts, Greek letters, and mathematical symbols) using the LaTeXStrings.jl package. If we indicate that a string should be interpreted as a LaTeXString using the L"..." syntax, it will render content inside $..$ using LaTeX, as seen below.

    xlabel!("Regular String (days)")
    ylabel!(L"LaTeX String $x_2$ (m$^3$)")

    Removing Plot Elements

    Sometimes we want to remove legends, axes, grid lines, and/or ticks.

    plot!(legend=false, axis=false, grid=false, ticks=false)

    Notice that this unintentionally modified the image dimensions to move the axis labels off the page. If we wanted to keep them, we could modify the dimensions with plot!(size=...).

    plot!(size=(400, 400))

    The lesson is that sometimes the Plots.jl defaults don’t look ideal, and we need to adjust sizes and margins.

    Aspect Ratio

    If we want to have a square aspect ratio, use ratio = 1.

    v = rand(5)
    plot(v, ratio=1, legend=false)
    scatter!(v)

    Plot Demos

    This section includes some examples of how to make other types of plots.

    Heatmaps

    A heatmap is effectively a plotted matrix with colors chosen according to the values. Use clim to specify a fixed range for the color limits.

    A = rand(10, 10)
    heatmap(A, clim=(0, 1), ratio=1, legend=false, axis=false, ticks=false)
    M = [ 0 1 0; 0 0 0; 1 0 0]
    whiteblack = [RGBA(1,1,1,0), RGB(0,0,0)]
    heatmap(c=whiteblack, M, aspect_ratio = 1, ticks=.5:3.5, lims=(.5,3.5), gridalpha=1, legend=false, axis=false, ylabel="i", xlabel="j")

    Custom Colors

    using Colors
    
    mycolors = [colorant"lightslateblue",colorant"limegreen",colorant"red"]
    A = [i for i=50:300, j=1:100]
    heatmap(A, c=mycolors, clim=(1,300))

    Plotting Areas Under Curves

    We can plot the area between a curve and the \(x\)-axis using areaplot().

    x = -3:.01:3
    areaplot(x, exp.(-x.^2/2)/(2π),alpha=.25,legend=false)

    We can also use this functionality for stacked area plots.

    M = [1 2 3; 7 8 9; 4 5 6; 0 .5 1.5]
    areaplot(1:3, M, seriescolor = [:red :green :blue ], fillalpha = [0.2 0.3 0.4])

    The fillrange option lets us color the area between two arbitrary lines/curves if we only want to treat one of those curves as a boundary. fillcolor and fillalpha let you change the color and transparency of the filled area.

    y = rand(10)
    plot(y, fillrange= y.*0 .+ .5, label= "above/below 1/2", fillcolor=:red, legend =:top)
    x = LinRange(0,2,100)
    y1 = exp.(x)
    y2 = exp.(1.3 .* x)
    plot(x, y1, fillrange = y2, fillalpha = 0.35, c = 1, label = "Confidence band", legend = :topleft)

    We can also get more creative and color different parts of a curve differently. Here, we divide a normal distribution into 100 quantiles and alternate red and blue stripes. We’ll do this using the erfinv() function from SpecialFunctions.jl to calculate the quantiles using the inverse cumulative distribution function, but there are other approaches using Distributions.jl.

    using SpecialFunctions
    
    # write a function for the normal distribution density
    f = x -> exp(-x^2/2)/(2π)
    # get the edges of the quantiles
    δ = .01
    x =2 .* erfinv.(2 .*/2 : δ : 1) .- 1)
    # make the plot and draw the density line in black
    areaplot(x, f.(x), seriescolor=[ :red,:blue], legend=false)
    plot!(x, f.(x),c=:black)

    Plotting Shapes

    We can also draw shapes more directly, such as rectangles and circles.

    rectangle(w, h, x, y) = Shape(x .+ [0,w,w,0], y .+ [0,0,h,h])
    circle(r,x,y) == LinRange(0,2π,500); (x.+r.*cos.(θ), y.+r.*sin.(θ)))
    plot(circle(5,0,0), ratio=1, c=:red, fill=true)
    plot!(rectangle(5*2,5*2,-2.5*2,-2.5*2),c=:white,fill=true,legend=false)

    Plotting Distributions

    The StatsPlots.jl package is very useful for making various plots of probability distributions.

    using Distributions, StatsPlots
    plot(Normal(2, 5))
    scatter(LogNormal(0.8, 1.5))

    We can also use this functionality to plot distributions of data in tabular data structures like DataFrames.

    using DataFrames
    dat = DataFrame(a = 1:10, b = 10 .+ rand(10), c = 10 .* rand(10))
    @df dat density([:b :c], color=[:black :red])

    Log-Scaled Axes

    xx = .1:.1:10
    plot(xx.^2, xaxis=:log, yaxis=:log)
    plot(exp.(x), yaxis=:log)

    Editing Plots Manually

    pl = plot(1:4,[1, 4, 9, 16])
    pl.attr
    RecipesPipeline.DefaultsDict with 30 entries:
      :dpi                      => 96
      :background_color_outside => :match
      :plot_titlefontvalign     => :vcenter
      :warn_on_unsupported      => true
      :background_color         => RGBA{Float64}(1.0,1.0,1.0,1.0)
      :inset_subplots           => nothing
      :size                     => (672, 480)
      :display_type             => :auto
      :overwrite_figure         => true
      :html_output_format       => :svg
      :plot_titlefontfamily     => :match
      :plot_titleindex          => 0
      :foreground_color         => RGB{N0f8}(0.0,0.0,0.0)
      :window_title             => "Plots.jl"
      :plot_titlefontrotation   => 0.0
      :extra_plot_kwargs        => Dict{Any, Any}()
      :pos                      => (0, 0)
      :plot_titlefonthalign     => :hcenter
      :tex_output_standalone    => false
      :extra_kwargs             => :series
      :thickness_scaling        => 1
      :layout                   => 1
      :plot_titlelocation       => :center
      :plot_titlefontsize       => 16
      :plot_title               => ""
      ⋮                         => ⋮
    pl.series_list[1]
    Plots.Series(RecipesPipeline.DefaultsDict(:plot_object => Plot{Plots.GRBackend() n=1}, :subplot => Subplot{1}, :label => "y1", :fillalpha => nothing, :linealpha => nothing, :linecolor => RGBA{Float64}(0.0,0.6056031611752245,0.9786801175696073,1.0), :x_extrema => (NaN, NaN), :series_index => 1, :markerstrokealpha => nothing, :markeralpha => nothing…))
    pl[:size]=(300,200)
    (300, 200)
    pl