In this tutorial, we’ll explore different ways to customize your plots with AoG.jl. Some of these customizations will be directed towards Makie.jl, AoG.jl’s backend.
First, we’ll learn more about the syntax that we can use inside the mapping() function, along with some handy AoG.jl’s helper functions that can be also used inside mapping(). To conclude, we’ll take a dive into in-depth customizations of the following features:
Axis: subplots inside the plot.
Figure: general plot customizations.
Legend: legend positioning and customizations.
Colorbar: tweak colorbar’s position and appearance.
:column_name => "My Custom New Label": This is what we call a noop (no operation), it simply renames a column.
:column_name => function(): This is an operation being applied to the column, but with no renaming.
column_name => function() => "My Custom New Label": This is a mix of the previous two, i.e. an operation applied to a column along with renaming.
Tip
The function() inside the mapping() pair specification must have eitherzero arguments and no parentheses, such as :col => mean for example; or, in the case of arguments, be an anonymous function, e.g. col => (x -> round(x; digits = 2)). For more on Julia functions, don’t forget to check our Data Wrangling Tutorials, specifically Functions.
To begin, like before, let’s load AoG.jl, the data wrangling libraries, and the DataFrame we’ve used previously:
Now let’s us apply some operations inside mapping():
# Age in Monthsdata(df) *mapping(:AGE => (x -> x *12)) *histogram() |> draw
The last plot works best with also a renaming:
# Much Betterdata(df) *mapping(:AGE => (x -> x *12) =>"Age in Months") *histogram() |> draw
Here is a more advanced example where we are calculating the ratio for :AGE / :WEIGHT, just to show that you can stick a function with two or more column arguments inside mapping(). Just pass the columns as a tuple (between parentheses):
# a simple function just to showcaseratio(x, y) = x / y
ratio (generic function with 1 method)
data(df) *mapping((:AGE, :WEIGHT) => ratio =>"My Ratio") *histogram() |> draw
2 🦮 Helper functions
AoG.jl has some helper functions provided for the most data wrangling stuff you need to do inside a mapping() call within the pair syntax. They are:
renamer(): rename unique values.
sorter(): sort unique values.
nonnumeric(): treat values as categorial (i.e. factors or discrete variables)
Let’s cover renamer() first. We use renamer() whenever we want to rename values of a categorical column. It works right out of the bat inside a mapping() call using the pair syntax.
Let’s make a simple change in the unique values of the column :WEIGHT_cat:
renamer accepts either a sequence or a vector of pairs in the following convention:
"old value"=>"new value"
sorter() works by passing either a sequence or vector of strings which will be used to reorder the unique values in the desired column. The ordering will be done by following the sequence of arguments inside sorter().
In a histogram above that we plotted using :AGE as the variable and facetting with :SEX, the first value (to the right) was female and the second (to the left) was male. We can change that with sorter():
Sometimes, our dataset has integers to specify categories. AoG.jl will probably error on most of the operations that expects a categorical variable (String or CategoricalArray) as an input column.
For example, using the column :ISMALE which is filled with either 0 or 1 (integer types) fails if you use it in a “categorical” setting:
To fix that you need to pass the nonnumeric() helper function. nonnumeric() tells AoG.jl that despite the column being “numeric” we do not want to use it in a numeric fashion, but instead in a discrete/categorical fashion. It takes no arguments and you can easily insert in a mapping() call within the pair syntax:
data(df) *mapping(:AGE; layout =:ISMALE => nonnumeric) *# now it works!histogram() |> draw
3 📈 Axis customization
Now we will delve into the thin line between AoG.jl and its backend Makie.jl. Since AoG.jl uses Makie.jl as a backend, some of the finer details we can only customize using Makie.jl keywords arguments. One of such finer customizations is the Axis customization, that controls the majority of customizations available in a plot.
Remember that pipe syntax that we were using almost exclusively to plot our AoG.jl visualizations? Let us refresh your memory. This one:
data(...) *mapping(...) *visual(...) |> draw
All of the customizations that we will cover in the remainder of this tutorial will need to be passed as keyword arguments to draw(). So this makes the piping operation to draw() inconvenient. Thus, we will be doing the following syntax now:
Note that we used the NamedTuple syntax with a leading semicolon to pass axis keywords, this is useful because it protects us from a common bug. That bug happens if you only want to pass one keyword, axis = (; a = 1) creates a NamedTuple but axis = (a = 1) creates a local variable a and your code will fail with a cryptic error. (For multi-element NamedTuples, however, it is allowed to leave out the semicolon.)
Let us define first a base plot for us to customize:
The first thing we’ll cover in Axis tweaking is the aspect ratio of our plots. If you want “instagram” like plots you can fix your aspect ratio to 1:
draw(plt; axis = (; aspect =1))
Tip
One worthy mention is the DataAspect() which makes all plots in your AoG.jl visualization have the same aspect ratio as their x/y limits (this means the same distance along each axis is equivalent to the same distance in data space):
draw(plt; axis = (; aspect =DataAspect()))
If you want a title to be on your plot you can do so with title as a keyword argument to Axis:
draw(plt; axis = (; title ="My Plot"))
There’s also titlealign, titlecolor, titlefont, titlegap and titlesize:
draw( plt; axis = (; title ="My Plot", titlealign =:left, # using Makie.jl's symbols titlecolor =:blue, # using Makie.jl's symbols titlefont ="DejaVu Sans Mono", titlegap =30, # the gap between title and the plot titlesize =32, # title's font size ),)
Sometimes we want to override the default resolution of the x- or y-axis ticks. This can be done with xticks and yticksAxis’ keyword arguments. It accepts a vector or a range:
draw(plt; axis = (; xticks =20:5:80))
This is similar to ggplot2’s xlim(), ylim() and lims(). limits takes a tuple with 2 elements:
x-axis limits: another tuple of (lower, upper).
y-axis limits: another tuple of (lower, upper).
So, if you want to override x-axis limits to something between 0 and 2 and the y-axis limits to something between 10 and 20, you can with:
draw(...; axis = (; limits = ((0, 2), (10, 20))))
Caution
Watch out! This is a “nested” tuple: a tuple inside a tuple.
If you only want to specify either one of the x- or y-axis you can just input nothing to leave it unchanged. Thus, to only alter the y-axis limits you can use nothing as the first value in the tuple to represent the x-axis unchanged limits, and then you can pass a tuple which represents the y-axis limits:
The next finer customizations available in the interface between AoG.jl and Makie.jl is the Figure customizations. These are customizations that impact the whole visualization “figure”.
To pass keyword arguments to customize Figure’s attributes, you need to pass a NamedTuple of the desired keyword arguments to draw() via:
The first Figure customization is the resolution. This is probably the most used Figure customization. It accepts a tuple with 2 elements. The first element is the Figure’s width in pixels. And the second element is the Figure’s height in pixels.
So, for example a 600x400 custom visualization can be specified as:
draw(plt; figure = (; resolution = (600, 400)))
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/run/_work/PumasTutorials.jl/PumasTutorials.jl/custom_julia_depot/packages/Makie/6c4lt/src/scenes.jl:229
Or an Ultra HD 1920x1080 visualization:
draw(plt; figure = (; resolution = (1920, 1080)))
┌ Warning: Found `resolution` in the theme when creating a `Scene`. The `resolution` keyword for `Scene`s and `Figure`s has been deprecated. Use `Figure(; size = ...` or `Scene(; size = ...)` instead, which better reflects that this is a unitless size and not a pixel resolution. The key could also come from `set_theme!` calls or related theming functions.
└ @ Makie ~/run/_work/PumasTutorials.jl/PumasTutorials.jl/custom_julia_depot/packages/Makie/6c4lt/src/scenes.jl:229
Tip
If you specify a high resolution like 1920x1080, you’ll probably need to scale the plot attributes up accordingly. However, you can also simply scale up the output resolution of bitmap saved from the same figure by specifying a px_per_unit value higher than 1.
For example you can save a 1920x1080 pixel bitmap from a 960x540 figure fig by doing save(fig, px_per_unit = 2). You can also set this value for all inline output with CairoMakie.activate!(px_per_unit = 2).
We can increase or decrease the padding of a Figure with figure_padding:
draw(plt; figure = (; figure_padding =0)) # NO padding
draw(plt; figure = (; figure_padding =100)) # a LOT of padding
By default, a visualization’s background color is always white. You can change this with backgroundcolor:
The first keyword argument that we’ll cover in legend tweaking is the position. By default it has the :right as value. We can specify some other Makie.jl symbols:
:top.
:bottom.
:left.
:right.
draw(plt_legend; legend = (; position =:top))
Next, we can also tweak the legend’s title position with the titleposition keyword argument with the same symbols as before:
draw(plt_legend; legend = (; position =:top, titleposition =:left))
We can also remove the frame that borders the legend with framevisible=false:
draw(plt_legend; legend = (; position =:top, titleposition =:left, framevisible =false))
Finally, like Figure, we can also increase or decrease the padding of a legend with padding:
draw( plt_legend; legend = (; position =:top, titleposition =:left, framevisible =true, padding =0), # NO padding!)
draw( plt_legend; legend = (; position =:top, titleposition =:left, framevisible =true, padding =50), # LOTS of padding!)
6 🖌️ Colorbar customizations
Our final fine tune customization is the Colorbar customizations. These are controlled with the colorbar keyword argument inside draw(). To pass keyword arguments to customize Colorbar’s attributes, you need to pass a NamedTuple of the desired keyword arguments to draw() via:
The first tweak that we can do in a colorbar is with respect to its positioning. The **keyword argument is position and it takes the same Makie.jl symbols we saw above:
:top.
:bottom.
:left.
:right (default).
draw(plt_colorbar; colorbar = (; position =:top))
We can also customize the size of a colorbar (the size is height for horizontal and width for vertical colorbars). You can alternatively set height and width directly:
draw(plt_colorbar; colorbar = (; position =:top, size =30))
draw(plt_colorbar; colorbar = (; position =:top, height =10, width =Relative(0.5)))
This is similar to the ticks in an axis. You can also specify which ticks are visible in a colorbar with the ticks keyword.
Our previous colorbar visualizations had ticks at multiples of 25, starting from 25 to 125. For example, we can tweak that to multiples of 10:
draw(plt_colorbar; colorbar = (; position =:top, height =50, ticks =20:10:120))
Tip
Like the xticks and yticksAxis customizations, colorbar’s ticks accepts either a vector or range.
7 🎨 Using themes
Most of the visual customizations you have seen above can be themed directly in Makie. This way, you don’t have to pass the same keyword arguments over and over again.
You can either use set_theme!() to set a theme that persists until set_theme!() is called again, or you use with_theme() which executes one function with a specific theme which is then reset.
Here are a couple of examples using with_theme() which apply analogously to set_theme!(). The themes used are Makie presets, which you can find out about in the Makie docs.
In this tutorial, we showcase how to fine-tune and customize your AoG.jl visualization. Please notice that most of these customizations call Makie.jl under the hood. We highly recommend browsing Makie.jl’s documentation. It is a rich source of references on anything “customizable” in AoG.jl.