Skip to content

Makie.jl

Documentation for Makie.jl ↗

FlexiChains provides a number of functions to visualise chains using the Makie plotting library.

Parts of the Makie integration in FlexiChains are heavily lifted from the (unreleased) ChainsMakie.jl package, although there have also been further modifications made since then. This includes some custom code to generate (e.g.) shared legends, which leads to slightly nicer plots than for Plots.jl (on top of Makie generally yielding nicer plots out of the box).

Note

You can also use Makie as a backend to make pair / corner plots! This requires loading a Makie backend as well as PairPlots.jl. Please see the PairPlots.jl integration section for more details.

General interface

For all functions plotfunc shown in the table of the plotting page, you can use the following invocation: 2. Generate an entire Makie.Figure. This automatically generates a complete plot for you, including a legend.

julia
plotfunc(
    chn,
    param_or_params;
    figure=(;),
    axis=(;),
    legend=(;),
    legend_position=:bottom,
    kwargs...,
)

param_or_params can be anything used to index into a chain (single parameters are also accepted). It can also be omitted, in which case all parameters in the chain will be plotted. Most keyword arguments are passed to the underlying Makie plotting functions, but there are some special ones which are handled by FlexiChains. For more information about these, see the customisation section below.

For functions which create only a single plot per parameter (e.g. density, or traceplot), the following options are also available. The intention is to allow you to build more complex figures using these as building blocks: 2. Plot a single parameter onto an existing Makie.Axis object: this uses the 'mutating' version with an exclamation mark. If ax is not specified, uses the current axis. Colours are handled the same way as above. param must be a single parameter.

julia
plotfunc!([ax]chn, param; kwargs...)
  1. Plot a single parameter onto a Makie grid position. This constructs a Makie.Axis for you, and as before you can pass options via the axis keyword argument. Colours are handled the same way as above. param must be a single parameter.
julia
f = Figure()
gp = f[1, 1]
plotfunc!(gp, chn, param; axis=(;), kwargs...)

Setup

Here, we create a model with different types of parameters (continuous, discrete, and vector-valued). This is the same model as used on the Plots.jl documentation page.

julia
using FlexiChains, CairoMakie, Turing

import FlexiChains.Makie as FM # For the plotting functions.

@model function f()
    x ~ Normal()
    y ~ Poisson(3)
    z ~ MvNormal(zeros(2), I)
end

chn = sample(
    f(),
    MH(),
    MCMCThreads(),
    1000,
    3;
    discard_initial=100,
    chain_type=VNChain,
    progress=false,
)
╭─FlexiChain (1000 iterations, 3 chains) ──────────────────────────────────────
 ↓ iter  = 101:1100
 → chain = 1:3

 Parameters (3) ── VarName
  Float64          x                                                          
  Int64            y                                                          
  Vector{Float64}  z (2,)

 Extras (4)
  Bool     accepted                                                           
  Float64  logprior, loglikelihood, logjoint                                  
╰──────────────────────────────────────────────────────────────────────────────╯

Default plot

Calling Makie.plot(chn) produces a trace plot and mixed density side-by-side for each parameter.

Makie.plot Function
julia
Makie.plot(
    chn::FC.FlexiChain,
    param_or_params = FC.Parameter.(FC.parameters(chn));
    kwargs...,
)

Plot the parameters in a FlexiChain using Makie. For each parameter, a trace plot and a density plot are created.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with Makie.plot(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
julia
Makie.plot(chn)

Trace plots

FlexiChains.Makie.traceplot Function
julia
FlexiChains.Makie.traceplot(
    chn::FC.FlexiChain[, param_or_params];
    kwargs...,
)

Create trace plots for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.traceplot(chn, :).

Keyword arguments

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.traceplot! Function
julia
FlexiChains.Makie.traceplot!

Mutating version of FlexiChains.Makie.traceplot, for use with existing Makie.Axis objects.

source
julia
FM.traceplot(chn)

Density plots

Makie.density Function
julia
Makie.density(
    chn::FC.FlexiChain[, param_or_params];
    pool_chains::Bool=false,
    kwargs...,
)

Create density plots for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with Makie.density(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
julia
Makie.density(chn)

Histograms

Makie.hist Function
julia
Makie.hist(
    chn::FC.FlexiChain[, param_or_params];
    pool_chains::Bool=false,
    kwargs...,
)

Create histograms for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with Makie.hist(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
Makie.stephist Function
julia
Makie.stephist(
    chn::FC.FlexiChain[, param_or_params];
    pool_chains::Bool=false,
    kwargs...,
)

Create a step histogram for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with Makie.stephist(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
julia
Makie.hist(chn)

Mixed density plots

FlexiChains.Makie.mixeddensity Function
julia
FlexiChains.Makie.mixeddensity(
    chn::FC.FlexiChain[, param_or_params];
    pool_chains::Bool=false,
    kwargs...,
)

Create mixed density plots (i.e., density plots for continuous parameters and histograms for discrete parameters) for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.mixeddensity(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.mixeddensity! Function
julia
FlexiChains.Makie.mixeddensity!

Mutating version of FlexiChains.Makie.mixeddensity, for use with existing Makie.Axis objects.

source
julia
FM.mixeddensity(chn)

Running mean plots

FlexiChains.Makie.meanplot Function
julia
FlexiChains.Makie.meanplot(
    chn::FC.FlexiChain[, param_or_params];
    kwargs...,
)

Plot the running mean of the specified parameter(s) in the given FlexiChain using Makie.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.meanplot(chn, :).

Keyword arguments

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.meanplot! Function
julia
FlexiChains.Makie.meanplot!

Mutating version of FlexiChains.Makie.meanplot, for use with existing Makie.Axis objects.

source
julia
FM.meanplot(chn)

Autocorrelation plots

FlexiChains.Makie.autocorplot Function
julia
FlexiChains.Makie.autocorplot(
    chn::FC.FlexiChain[, param_or_params];
    lags=FlexiChains.PlotUtils.default_lags(chn),
    demean=true,
    kwargs...,
)

Plot the autocorrelation of the specified parameter(s) in the given FlexiChain using Makie.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.autocorplot(chn, :).

Keyword arguments

  • lags: the lags at which to compute the autocorrelation. Defaults to 1:min(niters-1, round(Int, 10*log10(niters))).

  • demean: whether to subtract the mean before computing the autocorrelation. Defaults to true.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.autocorplot! Function
julia
FlexiChains.Makie.autocorplot!

Mutating version of FlexiChains.Makie.autocorplot, for use with existing Makie.Axis objects.

source
julia
FM.autocorplot(chn)

Rank plots

FlexiChains.Makie.rankplot Function
julia
FlexiChains.Makie.rankplot(
    chn::FC.FlexiChain[, param_or_params];
    overlay::Bool=false,
    kwargs...,
)

Create rank plots for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.rankplot(chn, :).

Keyword arguments

  • overlay::Bool: whether to overlay the histograms for all chains on the same axis, or to plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.rankplot! Function
julia
FlexiChains.Makie.rankplot!

Mutating version of FlexiChains.Makie.rankplot, for use with existing Makie.Axis objects.

source
julia
FM.rankplot(chn)

Violin plots

Makie.violin Function
julia
Makie.violin(
    chn::FC.FlexiChain[, param_or_params];
    pool_chains::Bool=false,
    with_box::Bool=false,
    box_kwargs::NamedTuple=(;),
    kwargs...,
)

Create violin plots for the specified parameters in the chain.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with Makie.violin(chn, :).

Keyword arguments

  • pool_chains::Bool: whether to pool data from all chains into a single plot, or to plot each chain separately. Defaults to false.

  • with_box::Bool: whether to overlay a box plot on each violin plot. Defaults to false.

  • box_kwargs::NamedTuple: keyword arguments passed to Makie.boxplot! when with_box=true. FlexiChains has a set of default boxplot kwargs that are always used, but they can be overridden by passing box_kwargs.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
julia
Makie.violin(chn; with_box=true)

Forest plots

Half-eye plots

To get a 'half-eye' look similar to R's ggdist package, you can compose forestplot! and ridgeline!. See e.g. the example here.

FlexiChains.Makie.forestplot Function
julia
FlexiChains.Makie.forestplot(
    chn::FC.FlexiChain[, param_or_params];
    point::Symbol=:median,
    interval::Symbol=:quantile,
    hdi_method::Symbol=:unimodal,
    levels::Tuple=(0.66, 0.95),
    pool_chains::Bool=false,
    kwargs...,
)

Create a forest (caterpillar) plot for the specified parameters in the chain. Each parameter is shown as a point estimate with one or more credible interval bars.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.forestplot(chn, :).

Keyword arguments

  • point::Symbol: the point estimate to use. Must be :mean or :median. Defaults to :median.

  • interval::Symbol: the method to use for computing credible intervals. Must be :quantile or :hdi. Defaults to :quantile. Note that to use :hdi you must have PosteriorStats.jl loaded.

  • hdi_method::Symbol: if interval=:hdi, the method to use for computing HDIs. Defaults to :unimodal; please see the PosteriorStats.jl documentation for details.

  • levels: a tuple of credible interval widths, e.g. (0.5, 0.94) for 50% and 94% intervals. Wider intervals are drawn with thinner lines.

  • pool_chains::Bool: whether to pool data from all chains or plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.forestplot! Function
julia
FlexiChains.Makie.forestplot!

Mutating version of FlexiChains.Makie.forestplot, for use with existing Makie.Axis objects.

source
julia
FM.forestplot(chn)

Ridgeline plots

Half-eye plots

To get a 'half-eye' look similar to R's ggdist package, you can compose forestplot! and ridgeline!. See e.g. the example here.

FlexiChains.Makie.ridgeline Function
julia
FlexiChains.Makie.ridgeline(
    chn::FC.FlexiChain[, param_or_params];
    scale::Float64=0.8,
    pool_chains::Bool=false,
    kwargs...,
)

Create a ridgeline (density ridge) plot for the specified parameters in the chain. Each parameter is shown as a filled kernel density estimate stacked vertically.

If no parameters are specified, this will plot all parameters in the chain. Note that non-parameter, i.e. Extra, keys are excluded by default. If you want to plot all keys, you can explicitly pass all keys with FlexiChains.Makie.ridgeline(chn, :).

Keyword arguments

  • scale::Float64: height of each ridge relative to the spacing between parameters. Values greater than 1.0 cause ridges to overlap. Defaults to 0.8.

  • pool_chains::Bool: whether to pool data from all chains or plot each chain separately. Defaults to false.

  • figure::NamedTuple: Additional keyword arguments passed to the Makie.Figure constructor.

  • axis::NamedTuple: Additional keyword arguments passed to the Makie.Axis constructor for each subplot.

  • legend::NamedTuple: Additional keyword arguments passed to the Makie.Legend constructor, if the legend is added.

  • legend_position::Symbol: Position of the legend. This can be either :right, :bottom or :none for no legend.

  • layout: either nothing (the default), or a tuple of (nrows, ncols) specifying the grid layout for the subplots.

All other keyword arguments are passed to the original Makie plotting function.

source
FlexiChains.Makie.ridgeline! Function
julia
FlexiChains.Makie.ridgeline!

Mutating version of FlexiChains.Makie.ridgeline, for use with existing Makie.Axis objects.

source
julia
FM.ridgeline(chn)

Pushforward plots

These plots are based on Michael Betancourt's mcmc_visualization_tools. We include a worked example to motivate and demonstrate the use of these plots.

Example

A pushforward distribution is obtained by mapping a function over a distribution: specifically, if some random variable θ has distribution p(θ), then the pushforward of θ through a function f is the distribution of Y = f(θ).

In Bayesian inference, we're often interested in taking posterior draws θ ~ p(θ | D) (as represented in a chain) and pushing this through some function f to obtain a new distribution. For example, f may be the function which generates posterior predictive draws, in which case the pushforward distribution is the posterior predictive distribution.

Each parameter draw θ yields a different draw of f, so the spread of f inherits posterior uncertainty. The pushforward plots in this section visualise that uncertainty as nested quantile bands, displayed as either a fitted curve (pushforward_continuous), per-group summaries (pushforward_discrete), or predictive histograms (pushforward_hist).

We'll concoct an example with the Palmer penguins dataset to show how these plots can be used.

julia
using Turing, DataFrames, PalmerPenguins, CairoMakie
import FlexiChains.Makie as FM
using StatsBase: denserank, fit, ZScoreTransform, reconstruct

# Load data
penguins = DataFrame(PalmerPenguins.load())

# Drop missing values first (this ensures that standardisation doesn't trip over)
dropmissing!(penguins)

# Fit standardisation transforms so we can unstandardise predictions later
bill_zs = fit(ZScoreTransform, Float64.(penguins.bill_length_mm))
mass_zs = fit(ZScoreTransform, Float64.(penguins.body_mass_g))

# Tidy up the data
standardize(x) = (x .- mean(x)) ./ std(x)
transform!(penguins, names(penguins, Real) .=> standardize => identity)
transform!(penguins, :species => denserank => :species_idx)

# Save the mapping from species index (integer) to species name (string)
species_names = sort(unique(penguins[!, [:species, :species_idx]]), :species_idx).species

# Define a model for penguin bill length as a function of species and body mass
@model function bill_model(species, body_mass)
    n_species = length(unique(species))
    beta1 ~ filldist(Normal(0, 1), n_species)
    beta2 ~ Normal(0, 1)
    beta3 ~ filldist(Normal(0, 1), n_species)
    sigma ~ Exponential(1)
    mu = @. beta1[species] + beta2 * body_mass + beta3[species] * body_mass
    bill_length_mm ~ MvNormal(mu, sigma)
end

We model a penguin's bill length as a function of its species (beta1), its body mass (beta2), and the interaction between them (beta3), i.e., we ask "does the effect of body mass vary by species?".

Next, we condition the model on the observed data and run MCMC.

julia
prior_model = bill_model(penguins.species_idx, penguins.body_mass_g)
cond_model = prior_model | (; bill_length_mm=penguins.bill_length_mm)
chain = sample(cond_model, NUTS(0.8), MCMCThreads(), 1000, 4; progress=false)
Warning: Only a single thread available: MCMC chains are not sampled in parallel
@ AbstractMCMC ~/.julia/packages/AbstractMCMC/NK6XN/src/sample.jl:544
Info: Found initial step size
  ϵ = 0.05
Info: Found initial step size
  ϵ = 0.025
Info: Found initial step size
  ϵ = 0.025
Info: Found initial step size
  ϵ = 0.025

A common starting point is to plot the posterior predictive distribution (see also the Turing.jl docs on this); it can help us (at least superficially) test if the model captured basic patterns in the input data. We can plot a summary histogram with uncertainty bands using pushforward_hist. By specifying the observed keyword argument we can also overlay the observed data so that we can visually compare the two distributions.

Before plotting, we can use transform_values to unstandardise the predictions back to physical units (see Modifying data for more details).

julia
# Note that we pass the `prior_model` here, not the conditioned model, so that
# we can sample new draws for the conditioned variables (i.e., bill length).
# This is explained in the Turing docs linked above.
ppd = predict(prior_model, chain)

# Unstandardise the predicted and observed bill lengths
using FlexiChains: transform_values
ppd = transform_values(ppd, :bill_length_mm => (v -> reconstruct(bill_zs, v)))
observed = reconstruct(bill_zs, penguins.bill_length_mm)

FM.pushforward_hist(
    ppd,
    @varname(bill_length_mm);
    observed=observed,
    axis=(; xlabel="bill length (mm)"),
)

We may also be interested in how predicted bill length changes with increasing body mass, and how this varies by species. For this, we can make use of pushforward_continuous by feeding it a grid of body mass values.

In the example below, we have set sigma = 0 to drop the predictive uncertainty; we're interested only in the uncertainty of the means here.

julia
# Set up the grid of body mass values and species indices
pred_body_mass = repeat(range(-3, 3, length=50), outer=3)
pred_species = repeat(1:3, inner=50)

# For each draw of the parameters in the chain, compute the predicted
# bill length for each combination of species and body mass.
pred_model = fix(bill_model(pred_species, pred_body_mass), (; sigma=0))
pred = predict(pred_model, chain)

# Unstandardise the predicted means
using FlexiChains: transform_values
pred = transform_values(pred, :bill_length_mm => (v -> reconstruct(bill_zs, v)))

# Plot the predicted means with uncertainty bands, coloured by species.
fig = Figure()
ax = Axis(fig[1, 1]; xlabel="body mass (g)", ylabel="bill length (mm)")
colors = Makie.wong_colors()[1:3]
for (s, color) in enumerate(colors)
    ix = findall(==(s), pred_species)
    x_grid = reconstruct(mass_zs, pred_body_mass[ix])
    FM.pushforward_continuous!(
        ax,
        pred,
        @varname(bill_length_mm[ix]);
        x_grid=x_grid,
        color=color,
    )
end
axislegend(ax, [PolyElement(; color=c) for c in colors], species_names; position=:lt)

fig

Finally, if we want to examine the distributions of discrete parameters, such as the main or interaction effect of species, we can use pushforward_discrete. Here, we'll look at the interaction effect to see if there's any evidence for the effect of body mass varying by species.

julia
FM.pushforward_discrete(chain, @varname(beta3))

FlexiChains.Makie.pushforward_continuous Function
julia
FlexiChains.Makie.pushforward_continuous(chn, param_or_params; x_grid=nothing; kwargs...)

Plot the marginal posterior of each component of an array parameter as a quantile ribbon, forming a "function envelope" over x_grid. Useful for visualising how a functional quantity (e.g. a fitted curve or spectrum) varies with posterior uncertainty.

This is a port of Michael Betancourt's plot_conn_pushforward_quantiles.

Keyword arguments

  • x_grid: the x-values to plot against. Defaults to 1:N, where N is the number of components being plotted.

  • quantiles: odd-length vector of levels in 0–1. Defaults to [0.1, 0.2, ..., 0.9].

  • baseline: length-N vector overlaid as a reference line.

  • residual: if true, subtract baseline before banding (requires baseline).

  • figure, axis: NamedTuples forwarded to Makie.Figure / Makie.Axis.

source
FlexiChains.Makie.pushforward_continuous! Function

Mutating version of FlexiChains.Makie.pushforward_continuous.

source
FlexiChains.Makie.pushforward_discrete Function
julia
FlexiChains.Makie.pushforward_discrete(chn, param_or_params; vertical=true, kwargs...)

Plot each component of an array parameter as an independent quantile bar, with nested intervals shown as stacked bands. Unlike pushforward_continuous, components are not connected; each bar is separated from its neighbours , making this appropriate when the components have no natural ordering or functional relationship (e.g. group-level intercepts in a hierarchical model).

This function is a port of Michael Betancourt's plot_disc_pushforward_quantiles.

Keyword arguments


  • vertical: if true, bars are vertical; otherwise horizontal. Defaults to true.

  • quantiles: odd-length vector of levels in 0–1. Defaults to [0.1, 0.2, ..., 0.9].

  • baseline: length-N vector overlaid per index.

  • residual: if true, subtract baseline before banding (requires baseline).

  • figure, axis: NamedTuples forwarded to Makie.Figure / Makie.Axis.

source
FlexiChains.Makie.pushforward_discrete! Function

Mutating version of FlexiChains.Makie.pushforward_discrete.

source
FlexiChains.Makie.pushforward_hist Function
julia
FlexiChains.Makie.pushforward_hist(chn, param_or_params; observed=nothing, nbins=25, kwargs...)

Posterior predictive check via histograms. For each posterior draw, the predictive values are binned into a histogram; the resulting per-bin count distributions are summarised as nested quantile ribbons. Overlaying observed data shows whether the model's predictive distribution is consistent with the observations.

This function is a port of Michael Betancourt's plot_hist_quantiles.

Keyword arguments

  • observed: vector of observed values; its histogram (same bins) is overlaid as a line.

  • nbins: number of equal-width bins. Defaults to 25.

  • quantiles: odd-length vector of levels in 0–1. Defaults to [0.1, 0.2, ..., 0.9].

  • figure, axis: NamedTuples forwarded to Makie.Figure / Makie.Axis.

source
FlexiChains.Makie.pushforward_hist! Function

Mutating version of FlexiChains.Makie.pushforward_hist.

source

Customisation

As described in the general interface section above, all of the above functions accept keyword arguments to control the appearance of the plot.

The figure, axis, and legend arguments (which can be, e.g., NamedTuples) allow you to pass extra keyword arguments to the Figure, Axis, and Legend constructors. Then, most other keyword arguments are forwarded to the underlying Makie plotting functions; please refer to the Makie documentation for more details on these.

Finally, there are also some special keyword arguments which are handled by FlexiChains. Here are some examples of these in action.

Custom layout

By default, plots are arranged with one parameter per row. You can pass a tuple of (nrows, ncols) as the layout keyword argument to change this:

julia
Makie.density(chn; layout=(2, 2))

Custom colours

Pass a vector of colours (one per chain) via the color keyword, or a categorical colormap via colormap:

julia
FM.traceplot(
    chn,
    [@varname(x), @varname(y)];
    color=[(:red, 0.6), (:blue, 0.6), (:green, 0.6)],
    # or e.g. colormap=:tab10
)

Note

To get the best effects with colormap, you should pass a categorical colormap such as :tab10. Continuous colormaps like :viridis will give poor results since it will use the first n colours of the colormap, which are all very similar!

Legend position

Use legend_position to move the legend (:bottom, :right, or :none):

julia
FM.traceplot(chn; legend_position=:right)