Skip to content

Plotting

Plots.jl

Visually, PlotlyJS produces the most appealing plots (for me). But it does not install on my system (1.5).

When a plotting related library is not found (as in “error compiling display”), try ]build Plots.

Defaults are set with the defaults command.

Axis labels

bar tends to have too small default margins for axis labels to show (at least in subplots). Try

using Plots.PlotMeasures

Colors

Saturation is given by a number between 0 and 1 as in color = (:blue, 0.2).

Legends

The label is set when each series is plotted. If labels are set when the plot is created (before the series are plotted), the entries are ignored.

Bar graphs

Switch off lines around bars with linealpha = 0.

Default arguments

Make a Dict with default arguments for each plot type, such as:

bar_defaults() = Dict([:leg => :bottom, :linecolor => :black]);

Make a function for each plot type, such as:

function bar_graph(groupLabelV, dataV; kwargs...)
    args = merge(bar_defaults(), kwargs);
    p = bar(groupLabelV, dataV;  args...);
    return p
end

Now any default arguments can be overridden and bar_graph is called exactly as bar would be.

Makie.jl

Subplots

It helps to write plotting functions that take a Figure as an input:

# Make a stand-alone figure. Could be omitted.
function myplot(x, y; kwargs...)
   fig = Figure();
   myplot!(f, x, y; kwargs...)
   return fig
end

# Plot into existing Figure.
function myplot!(fig :: Figure, x, y; pos = (1,1), kwargs...)
   ax = fig[pos...] = Axis(fig; xlabel = "x");
   myplot!(ax, x, y; kwargs...);
   return ax
end

# Plot into existing Axis
function myplot!(ax :: Axis, x, y; kwargs...)
   lines!(ax, x, y; kwargs...);
end

# Now we can make a stand-alone figure with
fig = Figure();
myplot!(fig, x, y);
# Or we can make a subplot with
fig = Figure();
myplot!(fig, x, y; pos = (2,1));

Limitations: The kwargs cannot be used to create the axis.

Looping over axes

One way of creating a figure with subplots is:

fig = Figure();
nr = 2; nc = 3;
for ir = 1:nr, ic = 1:nc
   ax = fig[ir, ic] = Axis(fig);
end

This fixes the layout. Now we can iterate over the subplots with

ind2sub(j, sz) = Tuple(CartesianIndices(sz)[j]);
for j = 1 : (nr * nc)
    fig[ind2sub(j, (nr,nc))...]
end

The roundabout way is necessary because Figure does not support linear or cartesian indexing.

Grouped bar graphs

Building up a grouped bar graph by plotting each series one at a time does not work. The first series bar is too wide (it covers the width of the entire group of bars). One could set it by hand, but it is not clear how.

axislegend does not work for grouped bar graphs (lacking labels).

Keyword arguments

Makie ignores invalid keyword arguments. This makes it possible to "flatten" keyword arguments; i.e., one can provide that Axis arguments in the same list as the series arguments. For example, this works:

lines(x, y; xlabel = "x");

But

lines!(ax, x, y; xlabel = "x");

ignores the xlabel.

nothing works with keyword arguments such as title.

Themes

update_theme!(thm, Lines = (linewidth = 4,)) creates a new "section" thm.Lines that applies to lines.

update_theme!(thm, Lines = (linestyle = :dash,)) merges the new information into the existing Lines section. It does not replace previous content.

Text sizes are determined by separate attributes for all elements; e.g., xticklabelsize.

Setting line colors from the theme's colormap:

thm = theme_dark();
update_theme!(thm; colormap = ColorSchemes.leonardo);
function make_figure()
   fig = Figure();
   ax = fig[1,1] = Axis(fig);
   for j = 1 : 4; 
      lines!(ax, 1:10, (1:10) .^ (1/j); color = fill(j, 10), colorrange = (1,4)); 
   end
   return fig
end
fig = with_theme(make_figure, thm);

Errors in theme settings cause merge! errors when plotting that bear no obvious relationship to themes.

Saving data with plots

VegaLite does this natively.

with Plots.jl one can use hdf5plot_write to write an entire plot, including the data, to an hdf5 file.

This means that each plot has to be generated twice; once with whatever backend is used to generate PDF files; and then again with hdf5. In particular, one cannot first plot with another backend and then save the resulting plot object to hdf5.

The approach is then to first save the plot to hdf5, then load it and save it with another backend.

Note: In my current (v.1.3) installation, hdf5plot_write generates a bunch or warnings followed by a crash due to world age problems.