Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 4

Publication-Quality Plots with Julia

Recommended resources

Welcome to our next lesson. In our previous session, we delved into SparseArrays.jl, uncovering how to represent and manipulate the enormous yet structured Hamiltonians that arise in many-body physics. You learned that by exploiting the locality of interactions, we can overcome the "curse of dimensionality" and compute properties of systems far larger than dense matrices would allow.

Now that we have the tools to generate data from these complex simulations, the next crucial step is to understand and communicate our results. This lesson is dedicated to the art and science of data visualization. We will learn how to transform raw numerical output into clear, informative, and publication-quality figures. Specifically, we'll focus on creating line plots, heatmaps, and multi-panel figures using Makie.jl, a powerful and modern plotting ecosystem in Julia perfectly suited for the demands of scientific research.

Why Makie.jl?

Julia's ecosystem offers several excellent plotting libraries, with Plots.jl and Makie.jl being the most prominent. Plots.jl is a valuable meta-package that provides a unified interface to many different plotting backends. However, for creating highly customized, complex, and performant visualizations suitable for academic publications, Makie.jl often has the edge. It was designed from the ground up for high performance and offers a more granular and powerful layout engine.

Introduction to Makie.jl

This article provides a concise rationale for choosing Makie.jl for academic work.

Read the brief sections About Makie and Reasons for Selection to understand the philosophy behind the package and why its popularity has grown, particularly for producing figures for journal papers.

The Makie ecosystem is composed of a main package, Makie.jl, which defines the plotting logic, and several backends for rendering.

The Best Package to Plot in Julia

This video by Numeryst gives a quick and clear overview of the Makie ecosystem.

Watch the first minute, from the beginning of the video, to understand the roles of the three main backends: CairoMakie for high-quality static 2D images (like PDFs for papers), GLMakie for interactive 3D/2D desktop windows, and WGLMakie for web-based interactive plots. For this course, we will primarily use CairoMakie.

To get started, you'll need to install CairoMakie. You only need to do this once.

import Pkg
Pkg.add("CairoMakie")

Then, in each session, you'll bring it into scope with using CairoMakie.


The Anatomy of a Makie Plot: Figures and Axes

The key to unlocking Makie's power is understanding its fundamental structure. A visualization is built from a hierarchy of objects, primarily the Figure and the Axis.

  • A Figure is the top-level container, the canvas on which everything is drawn.
  • An Axis is a component of the figure that contains a single plot (like a line plot or a scatter plot) with its own ticks, labels, and limits.

Makie offers two ways to create a plot, a simple "implicit" syntax and a more powerful "explicit" one. While the simple syntax is quick for initial exploration, the explicit syntax gives you the fine-grained control necessary for complex, publication-ready figures.

Introduction to Makie.jl

This section of the "Introduction to Makie.jl" article clearly explains the two syntaxes.

Please read the section titled Two Syntaxes. It is crucial to grasp the difference between the simple lines(...) approach and the Figure/Axis/lines!(...) approach. We will be using the latter for most of this lesson.

Let's put this into practice. The explicit approach looks like this:

using CairoMakie




# 1. Create a Figure object. We can set global properties here.
fig = Figure(fontsize = 22)




# 2. Create an Axis object within the figure's layout.
# The syntax `fig[1, 1]` places this axis in the first row, first column.
ax = Axis(fig[1, 1],
    xlabel = "x",
    ylabel = "f(x)",
    title = "Simple Harmonic Functions"
)




# 3. Plot data into the axis using a mutating function (ending in !).
x = 0:0.1:4π
lines!(ax, x, sin.(x), label = L"\sin(x)", linewidth=3)
lines!(ax, x, cos.(x), label = L"\cos(x)", linestyle=:dash, linewidth=3)




# 4. Add a legend to the axis.
axislegend(ax)




# 5. Display/save the figure.
fig

Notice the use of L"..." from the LaTeXStrings.jl package (which you may need to Pkg.add) to render mathematical symbols in labels—an essential feature for scientific plots.


Exploring Plot Types

Makie supports a vast range of plot types, catering to virtually any scientific visualization need.

This cheat sheet provides a quick visual reference to the many plotting functions available in Makie. It's a useful resource to keep handy as you explore the package.

We will focus on the two types you'll use most frequently in physics: line plots (which we've already seen) and heatmaps for 2D data.


Visualizing 2D Data: Heatmaps

In your research, you will constantly encounter 2D data arrays: the spatial distribution of a physical field, the elements of a matrix, or the dependence of a quantity on two parameters. Heatmaps are the perfect tool for visualizing this data.

Consider the output of a 2D hydrodynamic simulation, which might track quantities like fluid density (), velocity components (), and pressure () on a grid.

A typical multi-panel figure from a computational physics paper. This example shows the state of a 2D system at a specific time, with each panel visualizing a different physical quantity as a heatmap. This is the kind of figure we will learn to create.

Let's create a single heatmap. We'll generate some data representing a 2D Gaussian peak.

Introduction to Makie.jl

This resource provides the basic syntax for several plot types.

Focus on the subsection on heatmaps. Notice how you can pass either a 2D array directly or specify the x/y coordinates along with the 2D array of values.

To create a heatmap with a colorbar, the workflow is slightly different. The heatmap function returns the plot object itself, which we need to pass to the Colorbar.




# Generate some 2D data
x = -5:0.1:5
y = -5:0.1:5
f(x, y) = exp(-(x^2 + y^2) / 4)
z = [f(i, j) for i in x, j in y]

fig = Figure()
ax = Axis(fig[1, 1], aspect = DataAspect(), xlabel="x", ylabel="y")
hm = heatmap!(ax, x, y, z)




# Create a colorbar and link it to the heatmap object
Colorbar(fig[1, 2], hm, label = "Intensity")

fig

The aspect = DataAspect() argument ensures that the scaling of the x and y axes are equal, so our circular Gaussian doesn't appear as an ellipse.


Assembling Multi-Panel Figures

The true power of Makie's layout engine shines when creating multi-panel figures, like the one shown above. The fig[row, col] syntax makes this remarkably intuitive.

Introduction to Makie.jl

The layout section of the guide demonstrates how to arrange plots.

Read the subsection on arranging graphs. This shows how to place multiple Axis objects into a Figure grid.

Let's use this to create a 2x2 layout that mimics the structure of the simulation output figure. We'll populate it with a few different plot types.

fig = Figure(resolution = (800, 600))




# Top-left: A line plot
ax11 = Axis(fig[1, 1], title = "Decay")
lines!(ax11, 0:0.1:10, exp.(-(0:0.1:10)))




# Top-right: A scatter plot
ax12 = Axis(fig[1, 2], title = "Noisy Data")
scatter!(ax12, randn(100), randn(100))




# Bottom-left: A heatmap
x = -5:0.1:5; y = -5:0.1:5
z = [exp(-(i^2 + j^2) / 4) for i in x, j in y]
ax21 = Axis(fig[2, 1], title = "2D Gaussian", aspect=DataAspect())
hm = heatmap!(ax21, x, y, z)
Colorbar(fig[2, 2], hm) # Place colorbar next to it




# Bottom-right: An empty axis
ax22 = Axis(fig[2, 2], title = "Placeholder")

fig

Notice how we placed the Colorbar at fig[2, 2], next to the heatmap at fig[2, 1]. Makie's layout manager automatically handles the alignment and spacing, which is a significant advantage when constructing complex figures. For even more advanced arrangements, Makie's layout has powerful concepts like "protrusions".

A deep dive into MakieLayout | Julius Krumbiegel | JuliaCon 2021

This talk by Julius Krumbiegel, a primary developer of Makie, gives a deep dive into the layout system. It's advanced, but a short segment can provide powerful intuition.

Watch the section from 4:00 to 5:12. This introduces the concept of protrusions: the parts of a plot that "stick out", like titles and axis labels. Understanding that Makie aligns the inner content of plots is key to grasping why it so effectively creates tidy, professional-looking figures, even with complex layouts.


Saving Your Figures for Publication

Once you have crafted the perfect figure, you need to save it in a suitable format. For inclusion in papers (typically written in LaTeX or a similar system), a vector format like PDF is ideal as it can be scaled to any size without losing quality.

Introduction to Makie.jl

This final section covers the practicalities of getting your plot from Julia into a document.

Read the short sections on Saving and Using in Papers. This confirms the simple save() workflow and provides the recommendation to use PDF for LaTeX documents.

The process is straightforward:




# Assuming 'fig' is your Figure object from the previous example
save("my_multipanel_figure.pdf", fig)
save("my_multipanel_figure.png", fig, px_per_unit=2) # Higher resolution PNG

The save function automatically determines the file type from the extension. For raster formats like PNG, you can increase the resolution with px_per_unit.



Key Takeaways

  • Makie.jl is a powerful, modern plotting library ideal for creating publication-quality figures in Julia. We use the CairoMakie backend for static vector graphics.
  • The fundamental structure of a Makie plot is a Figure containing one or more Axis objects. Using the explicit fig = Figure(), ax = Axis(fig[...]), plot!(ax, ...) workflow gives you maximum control.
  • Makie provides a rich set of plotting functions (lines!, scatter!, heatmap!, etc.) for different data types.
  • Complex multi-panel figures are created by placing Axis objects into a grid layout on the Figure using fig[row, col] indexing.
  • Customization is done via keyword arguments to Axis and the plotting functions. Use L"..." strings for LaTeX labels.
  • Save figures using save("filename.pdf", fig). PDF is the preferred format for academic papers.

In our next lesson, we will address a crucial aspect of scientific computing: performance analysis. Having learned to write vectorized and sparse code, and now to visualize its output, you will learn how to use tools like @time and BenchmarkTools.jl to precisely measure your code's execution speed and identify any performance bottlenecks.