MixedModelsMakie.jl API

Coefficient Plots

MixedModelsMakie.coefplot — Function
coefplot(xs::Union{MixedModel,MixedModelBootstrap}...; kwargs...)::Figure
coefplot!(fig::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, xs::Union{MixedModel,MixedModelBootstrap}...;
          show_legend=length(xs) > 1, legend_attributes=(;), kwargs...)
coefplot!(ax::Axis, xs::Union{MixedModel,MixedModelBootstrap}...;
          conf_level=0.95, vline_at_zero=true, show_intercept=true,
          ptype=nothing,
          scatter_attributes=(;),
          errorbars_attributes=(;),
          show_legend=length(xs) > 1,
          legend_attributes=(;),
          labels=string.(1:length(xs)),
          attributes...)

Create a coefficient plot of the requested parameters and associated confidence intervals. When multiple models are supplied, they are overlaid on the same axes for comparison; all models must share the same coefficient names.

For a MixedModelBootstrap, ptype selects which parameters to plot: :β (fixed effects, default), :σ, :ρ, or :θ (see ridgeplot for details; the ASCII aliases :sigma, :rho, :theta are also accepted). ptype is not supported for a plain MixedModel.

group restricts ptype ∈ (:σ, :ρ) to a single grouping factor, e.g. group=:subj. It is not supported for :β/:θ or for a plain MixedModel.

attributes are passed onto both scatter! and errorbars!, while scatter_attributes and errorbars_attributes are passed only onto scatter! and errorbars!, respectively. (Starting with Makie 0.21, unsupported attributes for a given plottype are no longer silently ignored, so it's necessary to separate out the attributes that are only valid for a single plot type.)

labels controls the legend entry for each model (defaults to "1", "2", ...).

show_legend controls placement of the legend. Accepted values:

  • false: no legend
  • true or :bottom: horizontal legend below the axis (default for multi-model figures)
  • :top: horizontal legend above the axis
  • :left: vertical legend to the left of the axis
  • :right: vertical legend to the right of the axis
  • :axis: legend embedded inside the axis via axislegend

legend_attributes is a named tuple of keyword arguments forwarded to the Makie Legend (or axislegend) constructor.

The mutating methods return the original object.

Note

Inestimable coefficients (coefficients removed by pivoting in the rank deficient case) are excluded. When multiple models are provided, they must have the same coefficient names after dropping inestimable coefficients.

source
using CairoMakie
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie
using Random

verbagg = MixedModels.dataset(:verbagg)

gm1 = fit(MixedModel,
          @formula(r2 ~ 1 + anger + gender + btype + situ + (1|subj) + (1|item)),
          verbagg,
          Bernoulli();
          progress=false)

coefplot(gm1)
Example block output
sleepstudy = MixedModels.dataset(:sleepstudy)

fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days|subj)), sleepstudy; progress=false)
boot = parametricbootstrap(MersenneTwister(42), 1000, fm1)

coefplot(boot; conf_level=0.999, title="Custom Title")
Example block output

Ridge Plots

MixedModelsMakie.ridgeplot — Function
ridgeplot(xs::MixedModelBootstrap...; kwargs...)::Figure
ridgeplot!(fig::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, xs::MixedModelBootstrap...;
           show_legend=length(xs) > 1, legend_attributes=(;), kwargs...)
ridgeplot!(ax::Axis, xs::MixedModelBootstrap...;
           conf_level=0.95, vline_at_zero=true, show_intercept=true,
           ptype=:β,
           scatter_attributes=(;),
           errorbars_attributes=(;),
           band_attributes=(;),
           lines_attributes=(;),
           show_legend=length(xs) > 1,
           legend_attributes=(;),
           labels=string.(1:length(xs)),
           attributes...)

Create a ridge plot for the bootstrap samples of the requested parameters. When multiple bootstrap objects are supplied, they are overlaid on the same axes for comparison; all inputs must share the same coefficient names.

ptype selects which bootstrap parameters to plot: :β (fixed effects, default), :σ (random-effect standard deviations, including the residual), :ρ (random-effect correlations), or :θ (the unconstrained Cholesky parameterization, labeled positionally as θ01, θ02, ... since these lack a natural per-group name). The ASCII aliases :sigma, :rho, :theta are also accepted. show_intercept only applies to :β; it is a no-op for :σ/:ρ/:θ.

group restricts ptype ∈ (:σ, :ρ) to a single grouping factor, e.g. group=:subj. It is not supported for :β/:θ.

Densities are normalized so that the maximum density is always 1. For bounded parameters (:σ ≥ 0, :ρ ∈ [-1, 1], :θ per-element via lowerbd), the density curve is truncated to the parameter's valid range, since kernel smoothing can otherwise leak density past a hard boundary.

Setting histogram=true plots a histogram instead of a KDE for each row (counts normalized the same way). A histogram respects a parameter's bounds by construction, and can show a genuine spike where many bootstrap draws land on a boundary (e.g. a singular fit) — something a smoothed KDE cannot represent. bins is forwarded to StatsBase.fit(Histogram, ...; nbins=bins) when histogram=true; otherwise StatsBase's automatic bin selection is used.

The highest density interval corresponding to conf_level is marked with a bar at the bottom of each density. Setting conf_level=missing removes the markings for the highest density interval.

attributes are passed onto coefplot, band! and lines!. scatter_attributes and errorbars_attributes are passed only onto coefplot. band_attributes and lines_attributes are passed only onto band! and lines!, respectively. (Starting with Makie 0.21, unsupported attributes for a given plottype are no longer silently ignored, so it's necessary to separate out the attributes that are only valid for a single plot type.)

labels controls the legend entry for each model (defaults to "1", "2", ...).

show_legend controls placement of the legend. Accepted values:

  • false: no legend
  • true or :bottom: horizontal legend below the axis (default for multi-model figures)
  • :top: horizontal legend above the axis
  • :left: vertical legend to the left of the axis
  • :right: vertical legend to the right of the axis
  • :axis: legend embedded inside the axis via axislegend

legend_attributes is a named tuple of keyword arguments forwarded to the Makie Legend (or axislegend) constructor.

The mutating methods return the original object.

Note

Inestimable coefficients (coefficients removed by pivoting in the rank deficient case) are excluded.

source
ridgeplot(boot)
Example block output

Ridge 2D Plots

MixedModelsMakie.ridge2d — Function
ridge2d(bs::MixedModelBootstrap; ptype=:β, kwargs...)
ridge2d!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, bs::MixedModelBootstrap; ptype=:β)

Plot pairwise bivariate scatter plots with overlain densities for a bootstrap sample.

ptype specifies the set of parameters to examine, e.g. :β, :σ, :ρ, :θ (the ASCII aliases :sigma, :rho, :theta are also accepted).

The mutating methods return the original object.

source
ridge2d(boot)
Example block output

Random effects and group-level predictions

Caterpillar Plots

MixedModelsMakie.RanefInfo — Type
RanefInfo

Information on random effects conditional modes/means, variances, etc.

Used for creating caterpillar plots.

Fields

  • cnames::Vector{String}: Column names, i.e. predictor coefficient names

  • levels::Vector: Levels of the random effect, i.e. group names

  • ranef::Matrix{T} where T<:AbstractFloat: Conditional modes (or means) of the random effects

  • stddev::Matrix{T} where T<:AbstractFloat: Conditional standard deviations of the random effects

source
MixedModelsMakie.ranefinfo — Function
ranefinfo(m::MixedModel)

Return a NamedTuple{fnames(m), NTuple{k, RanefInfo}} from model m

source
ranefinfo(m::LinearMixedModel, gf::Symbol, re=ranef(m))

Return a RanefInfo corresponding to the grouping variable gf in model m.

The optional re argument is a precomputed ranef(m) result, used to avoid recomputation.

source
MixedModelsMakie.ranefinfotable — Function
ranefinfotable(ri::RanefInfo)
ranefinfotable(ris::NamedTuple)
ranefinfotable(m::MixedModel, args...; kwargs...)

Return the information in ri (or derived from m) as a column table (NamedTuple of Vectors)

The columns are

  • name: name of the random effect
  • level: level of the grouping factor
  • cmode: conditional mode of the random effect
  • cstddev: conditional standard deviation of the random effect

When called with a NamedTuple (as returned by ranefinfo(m::MixedModel)), a group column is prepended containing the grouping factor name for each row.

The MixedModel method is a convenience wrapper equivalent to ranefinfotable(ranefinfo(m, args...; kwargs...)).

source
MixedModelsMakie.caterpillar — Function
caterpillar(m::MixedModel, gf::Symbol=first(fnames(m)); kwargs...)::Figure
caterpillar!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::MixedModel,
             gf::Symbol=first(fnames(m)); kwargs...)
caterpillar!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, r::RanefInfo;
            orderby=1, cols::Union{Nothing,AbstractVector}=nothing,
            dotcolor=(:red, 0.2), barcolor=:black,
            vline_at_zero::Bool=false)

Create a "caterpillar plot" of the random-effects conditional means and prediction intervals.

A "caterpillar plot" is a horizontal error-bar plot of conditional means and standard deviations of the random effects.

When passing a MixedModel, gf specifies which grouping variable is displayed. Alternatively, ranefinfo may be used to construct the RanefInfo object directly. Constructing RanefInfo directly can be used to avoid re-computing the conditional variances.

The order of the levels on the vertical axes is increasing orderby column of r.ranef, usually the (Intercept) random effects. orderby can be an integer column index, a column name (as a Symbol or String), or nothing to disable sorting. Setting orderby=nothing returns the levels in the order they are stored in.

The display can be restricted to a subset of random effects associated with a grouping variable by specifying cols, either by indices or term names.

The mutating methods return the original object.

Note

Even when not sorting the levels, they might have already been sorted during model matrix construction. If you want impose a particular ordering on the levels, then you must sort the relevant fields in the RanefInfo object before calling caterpillar!.

Note

When orderby is specified as a column name (Symbol or String), it refers to a column within those specified by cols, not the full set of random effects coefficients.

source
using CairoMakie
CairoMakie.activate!(type = "svg")
using MixedModels
using MixedModelsMakie
sleepstudy = MixedModels.dataset(:sleepstudy)
verbagg = MixedModels.dataset(:verbagg)

fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days|subj)), sleepstudy; progress=false)
gm0 = fit(MixedModel,
          @formula(r2 ~ 1 + anger + gender + btype + situ + (1|subj) + (1|item)),
          verbagg,
          Bernoulli();
          progress=false)

subjre = ranefinfo(fm1)[:subj]

caterpillar!(Figure(; size=(800,600)), subjre)
Example block output
caterpillar!(Figure(; size=(800,600)), subjre; orderby=2)
Example block output
caterpillar!(Figure(; size=(800,600)), subjre; orderby=nothing)
Example block output
caterpillar(gm0, :item)
Example block output
MixedModelsMakie.qqcaterpillar — Function
qqcaterpillar(m::MixedModel, gf::Symbol=first(fnames(m)); kwargs...)::Figure
qqcaterpillar!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::MixedModel,
               gf::Symbol=first(fnames(m)); kwargs...)
qqcaterpillar!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, r::RanefInfo;
               cols::Union{Nothing,AbstractVector}=nothing,
               dotcolor=(:red, 0.2), barcolor=:black,
               vline_at_zero::Bool=false)

Create a caterpillar plot with the vertical axis on the Normal() quantile scale.

When passing a MixedModel, gf specifies which grouping variable is displayed. Alternatively, ranefinfo may be used to construct the RanefInfo object directly. Constructing RanefInfo directly can be used to avoid re-computing the conditional variances.

The display can be restricted to a subset of random effects associated with a grouping variable by specifying cols, either by indices or term names.

The order of the levels on the vertical axes is increasing orderby column of r.ranef, usually the (Intercept) random effects. Setting orderby=nothing will disable sorting, i.e. return the levels in the order they are stored in.

The mutating methods return the original object.

source
qqcaterpillar(fm1)
Example block output
qqcaterpillar(gm0, :item)
Example block output
qqcaterpillar!(Figure(; size=(400,300)), subjre; cols=[1])
Example block output
qqcaterpillar!(Figure(; size=(400,300)), subjre; cols=[:days])
Example block output

Shrinkage Plots

MixedModelsMakie.ShrinkageInfo — Type
ShrinkageInfo

Information on random effects compared to pseudo-OLS estimates.

Used for creating shrinkage caterpillar plots.

Fields

  • cnames::Vector{String}: Column names, i.e. predictor coefficient names

  • levels::Vector: Levels of the random effect, i.e. group names

  • blups::Matrix{T} where T<:AbstractFloat: The conditional modes of the random effects

  • blimps::Matrix{T} where T<:AbstractFloat: The 'reference' mode of the random effect, corresponding to the conditional mode evaluated at the reference value of θ. Typically, this approximates the value you would get without any shrinkage, e.g. from classical within-groups (non-mixed) regression

  • λ::Matrix{T} where T<:AbstractFloat: The (lower-triangular) relative covariance factor of the random effects for this grouping factor, such that the covariance matrix is proportional to λλ'. Shared across all levels. Used for constructing correlation ellipses in shrinkage plots.
source
MixedModelsMakie.shrinkageinfo — Function
shrinkageinfo(m::MixedModel, θref::Vector{<:AbstractFloat}=_ref_theta(m))

Return a NamedTuple{fnames(m), NTuple{k, ShrinkageInfo}} from model m

The optional θref argument is the θ vector at which to compute the reference (unshrunken) estimates; it defaults to _ref_theta(m).

source
shrinkageinfo(m::MixedModel, gf::Symbol, θref::Vector{<:AbstractFloat}=_ref_theta(m))

Return a ShrinkageInfo corresponding to the grouping variable gf in model m.

The optional θref argument is the θ vector at which to compute the reference (unshrunken) estimates; it defaults to _ref_theta(m).

source
MixedModelsMakie.shrinkageinfotable — Function
shrinkageinfotable(si::ShrinkageInfo)
shrinkageinfotable(sis::NamedTuple)
shrinkageinfotable(m::MixedModel, args...; kwargs...)

Return the information in si (or derived from m) as a column table (NamedTuple of Vectors)

The columns are

  • name: name of the random effect
  • level: level of the grouping factor
  • cmode: conditional mode of the random effect
  • rmode: reference mode of the random effect, corresponding to the conditional mode evaluated at the reference value of θ. Typically, this approximates the value you would get without any shrinkage, e.g. from classical within-groups (non-mixed) regression

When called with a NamedTuple (as returned by shrinkageinfo(m::MixedModel)), a group column is prepended containing the grouping factor name for each row.

The MixedModel method is a convenience wrapper equivalent to shrinkageinfotable(shrinkageinfo(m, args...; kwargs...)).

source
MixedModelsMakie.shrinkagedot — Function

No documentation found for public binding MixedModelsMakie.shrinkagedot.

MixedModelsMakie.shrinkagedot is a Function.

# 2 methods for generic function "shrinkagedot" from MixedModelsMakie:
 [1] shrinkagedot(m::MixedModels.MixedModel, gf::Symbol; kwargs...)
     @ ~/work/MixedModelsMakie.jl/MixedModelsMakie.jl/src/shrinkage.jl:419
 [2] shrinkagedot(m::MixedModels.MixedModel; ...)
     @ ~/work/MixedModelsMakie.jl/MixedModelsMakie.jl/src/shrinkage.jl:419
source
MixedModelsMakie.shrinkageplot — Function
shrinkageplot(m::MixedModel, gf::Symbol=first(fnames(m)), θref=_ref_theta(m); kwargs...)::Figure
shrinkageplot!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::MixedModel,
               gf::Symbol=first(fnames(m)), θref=_ref_theta(m); kwargs...)
shrinkageplot!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, si::ShrinkageInfo;
               ellipse=false, ellipse_scale=1, n_ellipse=5,
               cols::Union{Nothing,AbstractVector}=nothing,
               shrunk_dotcolor=(:blue, 0.25), ref_dotcolor=(:red, 0.25),
               ellipse_color=:green, ellipse_linestyle=:dash,
               labels::Union{Bool,Symbol,AbstractVector}=false,
               labelcolor=:black, labelsize=10, n_labels::Integer=5)

Create a scatter-plot matrix of the conditional means, b, of the random effects for grouping factor gf.

Two sets of conditional means are plotted: those at the estimated parameter values and those at θref. The default θref results in Λ being a very large multiple of the identity. The corresponding conditional means can be regarded as unpenalized.

The display can be restricted to a subset of random effects associated with a grouping variable by specifying cols, either by indices or term names.

The reference (unshrunk) points can be labeled with the levels of gf by passing labels=true (label every level), a vector of level names/indices (label only that subset), or labels=:auto (automatically pick the n_labels "most interesting" levels). labelcolor and labelsize control the appearance of the labels; n_labels only applies to labels=:auto and defaults to a small number so the plot doesn't get overcrowded.

Correlation ellipses can be added with ellipse=true, with the number of ellipses controlled by n_ellipse. The ellipses are equally spaced between the outer ellipse and the origin (center). The scaling of the ellipses can be adjusted with the multiplicative ellipse_scale. If you are unable to see the ellipses, try increasing ellipse_scale.

The mutating methods return the original object.

See also shrinkagedot.

Note

For degenerate (singular) models, the correlation ellipse will also be degenerate, i.e., collapse to a point or line.

source
using CairoMakie
# The SVG sometimes renders incorrectly,
# so you may want to use PNG here
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie
sleepstudy = MixedModels.dataset(:sleepstudy)
verbagg = MixedModels.dataset(:verbagg)

fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days|subj)), sleepstudy; progress=false)
shrinkageplot(fm1; labels=true)
Example block output
shrinkageplot(fm1; ellipse=true)
Example block output
shrinkageplot!(Figure(; size=(400,400)), fm1; labels=:auto)
Example block output
shrinkagedot(fm1; ordertype=:shrunk)
Example block output
shrinkagedot(fm1; ordertype=:ref)
Example block output
gm1 = fit(MixedModel,
          @formula(r2 ~ 1 + anger + gender + btype + situ + (1|subj) + (1+gender|item)),
          verbagg,
          Bernoulli();
          progress=false)
shrinkageplot(gm1, :item)
Example block output

Diagnostics

We have also provided a few useful plot recipes for common plot types applied to mixed models. These are especially useful for diagnostics and model checking.

QQ Plots

The methods for qqnorm and qqplot are implemented using Makie recipes. In other words, these are convenience wrappers for calling the relevant plotting methods on residuals(model).

Specify the type of line on the QQ plots with the qqline keyword-argument. The default for qqnorm is :fitrobust, which delivers an R-style line connecting the first and third quartiles. The default for qqplot is :identity, which plots the line with slope = 1 and intercept = 0. The final possibility is :fit, which plots the line of best fit (i.e. regressing the quantiles of the residuals onto the quantiles of the reference distribution).

The reference distribution for qqnorm is the standard normal, which differs from the behavior in previous versions of Makie.

Compat

The options and associated names for the qqline keyword argument changed in Makie 0.16.3 (and were broken in Makie 0.16.0-0.16.2). The equivalent to qqline=:R is qqline=:fitrobust. qqline=:R will be supported for backwards compatibility only until the next breaking release.

using CairoMakie
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie

sleepstudy = MixedModels.dataset(:sleepstudy)

fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days|subj)), sleepstudy; progress=false)
qqnorm(fm1; qqline=:fitrobust)
Example block output
# the residuals should have mean 0
# and standard deviation equal to the residual standard deviation
qqplot(Normal(0, fm1.σ), fm1)
Example block output

Profile Plots

Requires MixedModels 4.14 or above.

using CairoMakie
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie

sleepstudy = MixedModels.dataset(:sleepstudy)
fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days|subj)), sleepstudy; progress=false)
pr1 = profile(fm1)
zetaplot(pr1)
Example block output
# show zeta on the absolute value scale with coverage intervals
zetaplot(pr1; absv=true)
Example block output
# show zeta for the variance components
zetaplot(pr1; absv=true, ptyp='θ')
Example block output
profiledensity(pr1)
Example block output
profiledensity(pr1; share_y_scale=false)
Example block output
profiledensity(pr1; ptyp='σ')
Example block output

UpSet Plots

UpSet plots[upset] visualize the intersection structure of categorical conditions, showing which combinations of condition levels co-occur in the data and how many observations (or grouping-factor levels) fall in each combination.

Evolving design

The visual design of UpSet plots (e.g. colors, markers, and how marginal/collapsed cells are distinguished from true intersections) is still being refined. Such visual changes may land in minor releases without being treated as breaking.

Sets are the individual levels of each categorical predictor (e.g., "gender: M", "gender: F", "btype: curse"). Columns of the combination matrix are the full factorial cells (every combination of each level per predictor) plus marginal cells where all levels of a single predictor are simultaneously active (showing whether that predictor is within-subjects or between-subjects). A filled circle means that condition level is active in that column; a connecting line spans the active conditions within each column. The top bars show counts per column; the left bars show counts per individual condition level.

A column in which only within-subjects predictors are collapsed will have non-zero counts; a column where a between-subjects predictor is collapsed will be empty because no single unit can appear in all levels of a between-subjects factor.

MixedModelsMakie.upsetplot! — Method
upsetplot(m::MixedModel,
          gf::Union{Symbol,Nothing}=first(fnames(m)); kwargs...)::Figure
upsetplot!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::MixedModel,
           gf::Union{Symbol,Nothing}=first(fnames(m));
           sortby::Symbol=:count,
           show_empty::Bool=true,
           orientation::Symbol=:horizontal,
           show_setsize::Bool=true,
           intersection_pos::Symbol=...,
           setsize_pos::Symbol=...,
           filled_color=:black,
           empty_color=:lightgray,
           bar_color=:steelblue,
           union_color=:gray30,
           dot_size=12)

Create an UpSet plot showing which levels of grouping factor gf appear in which categorical fixed-effect conditions.

Pass gf=nothing to count observations instead of grouping-factor levels.

Predictor names, levels, and per-observation values are recovered from the model's formula, design matrix, and contrast coding — no original data frame is needed.

Evolving design

The visual design of UpSet plots (e.g. colors, markers, and how marginal/collapsed cells are distinguished from true intersections) is still being refined. Such visual changes may land in minor releases without being treated as breaking.

Layout keywords:

  • orientation: :horizontal (default — combinations as columns, sets as rows) or :vertical (combinations as rows, sets as columns).
  • show_setsize: show the set-size bar chart (true by default).
  • intersection_pos: where the intersection-size bars go relative to the incidence matrix — :top/:bottom (horizontal) or :left/:right (vertical).
  • setsize_pos: where the set-size bars go — :left/:right (horizontal) or :top/:bottom (vertical).

Marginal cells (which collapse one predictor, leaving all of its levels active) get an "or" bracket drawn around that predictor's sibling dots, since lighting up every level of a predictor represents "not constrained on this predictor" (a union), not an intersection like the solid line connecting the rest of the dots.

The mutating method returns the original object.

source
MixedModelsMakie.upsetplot! — Method
upsetplot(data; cols=All(), gf::Union{Symbol,Nothing}=nothing, kwargs...)::Figure
upsetplot!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, data;
           cols=All(),
           gf::Union{Symbol,Nothing}=nothing,
           sortby::Symbol=:count,
           show_empty::Bool=true,
           orientation::Symbol=:horizontal,
           show_setsize::Bool=true,
           intersection_pos::Symbol=...,
           setsize_pos::Symbol=...,
           filled_color=:black,
           empty_color=:lightgray,
           bar_color=:steelblue,
           union_color=:gray30,
           dot_size=12)

Create an UpSet plot directly from a Tables.jl-compatible table.

Non-numeric columns (optionally restricted by cols) become the sets. Pass gf=:col to count unique values of that column per cell instead of observations.

Evolving design

The visual design of UpSet plots (e.g. colors, markers, and how marginal/collapsed cells are distinguished from true intersections) is still being refined. Such visual changes may land in minor releases without being treated as breaking.

See upsetplot!(::Indexable, ::MixedModel) for layout keyword details.

The mutating method returns the original object.

source
using CairoMakie
CairoMakie.activate!(; type="svg")
using DataFrames: Not
using MixedModels
using MixedModelsMakie

verbagg = MixedModels.dataset(:verbagg)

gm1 = fit(MixedModel,
          @formula(r2 ~ 1 + anger + gender + btype + situ + (1|subj) + (1+gender|item)),
          verbagg, Bernoulli(); progress=false)

# gender is between-subjects; btype and situ are within-subjects.
# Marginal cells that collapse gender are empty (no subject has both genders),
# while marginals that collapse btype or situ are non-empty.
upsetplot(gm1, :subj, show_empty=false)
Example block output
# Observation counts instead of subject counts
upsetplot(gm1, nothing, show_empty=false)
Example block output
# Table-based: no model required — non-numeric columns are detected automatically.
# Numeric columns (anger) and explicit exclusions (subj, item, r2) are dropped.
upsetplot(verbagg; cols=Not([:subj, :item, :r2]), gf=:subj, show_empty=false)
Example block output
# Sort by degree (full factorial cells first, then marginals) rather than by count
upsetplot(gm1, :subj, sortby=:degree, show_empty=false)
Example block output

The same incidence data drawn by upsetplot can be pulled out as a table with upsettable, for cases where you want to filter, sort, or re-analyze it directly rather than (or in addition to) plotting it:

MixedModelsMakie.upsettable — Function
upsettable(m::MixedModel, gf::Union{Symbol,Nothing}=first(fnames(m)))

Return the incidence table underlying upsetplot!: one row per combination cell (every full factorial cell of the categorical fixed-effect predictors, plus marginal cells that collapse a single predictor), with:

  • cell: a label for the combination
  • degree: the number of predictors involved (one fewer for marginal cells)
  • count: the number of observations (or grouping-factor levels, if gf is given) falling in the cell
  • one Bool column per set (an individual condition level, e.g. "gender: M") indicating whether that set is active in the cell

Pass gf=nothing to count observations instead of grouping-factor levels, matching upsetplot!.

source
upsettable(data; cols=All(), gf::Union{Symbol,Nothing}=nothing)

Return the incidence table underlying upsetplot!, built directly from a Tables.jl-compatible table. See upsetplot! for the meaning of cols and gf.

source
first(upsettable(gm1, :subj), 10)
10×10 DataFrame
Rowcelldegreecountgender: Fgender: Mbtype: cursebtype: scoldbtype: shoutsitu: othersitu: self
StringInt64Int64BoolBoolBoolBoolBoolBoolBool
1gender: F & btype: curse & situ: other3243truefalsetruefalsefalsetruefalse
2gender: M & btype: curse & situ: other373falsetruetruefalsefalsetruefalse
3gender: F & btype: scold & situ: other3243truefalsefalsetruefalsetruefalse
4gender: M & btype: scold & situ: other373falsetruefalsetruefalsetruefalse
5gender: F & btype: shout & situ: other3243truefalsefalsefalsetruetruefalse
6gender: M & btype: shout & situ: other373falsetruefalsefalsetruetruefalse
7gender: F & btype: curse & situ: self3243truefalsetruefalsefalsefalsetrue
8gender: M & btype: curse & situ: self373falsetruetruefalsefalsefalsetrue
9gender: F & btype: scold & situ: self3243truefalsefalsetruefalsefalsetrue
10gender: M & btype: scold & situ: self373falsetruefalsetruefalsefalsetrue

Nesting/Crossing Plots

Grouping factors in a mixed model (e.g. subj, item, school, class) can be nested (every level of one occurs with exactly one level of another, as with students nested within classrooms in a single year) or crossed (levels of both factors co-occur relatively freely, as with subjects and items in a repeated-measures design). nestingplot shows this structure for every pair of grouping factors in a model.

The plot is laid out like a correlation matrix:

  • diagonal: each grouping factor's name and number of levels.
  • lower triangle: a heatmap of the co-occurrence contingency table between the row and column factor. Levels are reordered (for display only) to group each level with its most common partner, so nested structure appears as a block-diagonal pattern and crossed structure appears as a dense or scattered rectangle.
  • upper triangle: a text badge classifying the same pair — one factor nested in the other (A ⊂ B), identical (the two names partition observations the same way, e.g. two labels for one grouping factor), or crossed, further split into complete (every combination of levels is observed) and partial (only some combinations are, with the observed density reported). This split matters in practice: a completely-crossed subject × item design supports estimating both by-subject and by-item slopes for every condition, while a partially crossed (e.g. Latin-square) design may not.

Pass swap_triangles=true to swap which triangle shows which — heatmaps in the upper triangle and text badges in the lower.

MixedModelsMakie.nestingplot — Function
nestingplot(m::MixedModel, gfs::Union{Symbol,AbstractString,Integer}...;
            colormap=:Blues, fontsize::Real=20, swap_triangles::Bool=false)::Figure
nestingplot!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::MixedModel,
             gfs::Union{Symbol,AbstractString,Integer}...;
             colormap=:Blues, fontsize::Real=20, swap_triangles::Bool=false)

Create a nesting/crossing matrix for the grouping factors of m.

Each distinct grouping factor (e.g. subj, item) becomes one row/column of a matrix, laid out like a correlation-matrix plot:

  • diagonal: factor name and number of levels
  • lower triangle (upper if swap_triangles=true): a heatmap of the co-occurrence contingency table between the row and column factor. Rows and columns are reordered (for display only) to group each level with its most common partner, so that nested structure appears as a block-diagonal pattern and crossed structure appears as a dense or scattered rectangle.
  • upper triangle (lower if swap_triangles=true): a text badge classifying the same pair as one factor nested in the other (A ⊂ B), identical (the two names partition observations the same way), or crossed — complete if every combination of levels is observed, partial (with the observed density) otherwise.

gfs, if given, restricts and orders which grouping factors to show (by name or index); otherwise all distinct grouping factors are shown, in the order they first appear in the model.

The classification only depends on the grouping factors' level assignments (ReMat.refs), not on the original data, matching the model-based approach used by upsetplot!.

The mutating method returns the original object.

source
using CairoMakie
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie

kb07 = MixedModels.dataset(:kb07)
gm2 = fit(MixedModel,
          @formula(rt_trunc ~ 1 + spkr * prec * load +
                              (1 + spkr + prec + load | subj) +
                              (1 + spkr | item)),
          kb07; progress=false)

# subj and item are nearly (but not perfectly) crossed in this design
nestingplot(gm2)
Example block output

As with upsetplot, the data underlying nestingplot is available as tables. nestingtable gives the raw co-occurrence counts in long format, with one row per pair of levels — including zero-count rows for combinations that never co-occur, since those absences are exactly what reveal nesting or partial crossing:

MixedModelsMakie.nestingtable — Function
nestingtable(m::MixedModel, gfs::Union{Symbol,AbstractString,Integer}...)

Return the co-occurrence table underlying nestingplot, in long format: one row per combination of a level of grouping factor A and a level of grouping factor B, for every pair of distinct grouping factors in m (restricted/ordered by gfs, as in nestingplot). Columns:

  • factor_a, level_a, factor_b, level_b: the pair of levels
  • count: the number of observations sharing that pair of levels (0 for combinations that never co-occur — these absences are what reveal nesting or partial crossing)

See nestingstructure for the pairwise nested/crossed classification instead of the raw counts.

source
first(nestingtable(gm2), 10)
10×5 DataFrame
Rowfactor_alevel_afactor_blevel_bcount
StringStringStringStringInt64
1itemI01subjS0301
2itemI01subjS0311
3itemI01subjS0341
4itemI01subjS0351
5itemI01subjS0361
6itemI01subjS0371
7itemI01subjS0381
8itemI01subjS0391
9itemI01subjS0411
10itemI01subjS0421

Filtering to count == 0 finds specific missing combinations, e.g. the subjects who never saw a particular item:

filter(:count => iszero, nestingtable(gm2))
3×5 DataFrame
Rowfactor_alevel_afactor_blevel_bcount
StringStringStringStringInt64
1itemI05subjS0860
2itemI23subjS0820
3itemI24subjS1020

nestingstructure gives the pairwise nested/crossed classification and density shown in nestingplot's upper-triangle badges. This results in one row per pair of grouping factors, rather than one row per pair of levels:

MixedModelsMakie.nestingstructure — Function
nestingstructure(m::MixedModel, gfs::Union{Symbol,AbstractString,Integer}...)

Return the pairwise nested/crossed classification underlying nestingplot's upper-triangle badges: one row per pair of distinct grouping factors in m (restricted/ordered by gfs, as in nestingplot), with:

  • factor_a, factor_b: the pair of grouping factors
  • n_levels_a, n_levels_b: their numbers of levels
  • relationship: one of :identical, :a_nested_in_b, :b_nested_in_a, :complete_crossing, or :partial_crossing
  • density: the fraction of the n_levels_a × n_levels_b grid of combinations that is actually observed (1.0 for :complete_crossing)

See nestingtable for the raw per-level co-occurrence counts instead of this per-pair summary.

source
nestingstructure(gm2)
1×6 DataFrame
Rowfactor_afactor_bn_levels_an_levels_brelationshipdensity
StringStringInt64Int64SymbolFloat64
1itemsubj3256partial_crossing0.998326

Facet Regression Plots

facetregression draws a Cleveland-trellis-style small-multiples display: one panel per level of a grouping column, each showing a scatter of a response against a predictor plus that group's own OLS regression line. Panels share linked axes so slopes remain visually comparable across groups; by default the shared y-range is chosen so that the mean of the per-group slopes appears at 45° on screen ("banking to 45°"), which is where slope differences are easiest to compare visually (Cleveland, W. S. (1993), Visualizing Data, Hobart Press).

MixedModelsMakie.FacetRegressionInfo — Type
FacetRegressionInfo

Per-group data and within-unit OLS fits underlying facetregression!.

Fields

  • group::Symbol: Name of the grouping variable/factor

  • predictor::Symbol: Name of the predictor (x) variable

  • response::Symbol: Name of the response (y) variable

  • labels::Vector: Group levels, in encounter order

  • x::Array{Vector{T}, 1} where T<:AbstractFloat: Per-group predictor values

  • y::Array{Vector{T}, 1} where T<:AbstractFloat: Per-group response values

  • n::Vector{Int64}: Per-group observation counts

  • intercept::Vector{T} where T<:AbstractFloat: Per-group within-unit OLS intercept

  • slope::Vector{T} where T<:AbstractFloat: Per-group within-unit OLS slope

  • xrange::Tuple{T, T} where T<:AbstractFloat: (min, max) of the predictor across all groups

  • yrange::Tuple{T, T} where T<:AbstractFloat: (min, max) of the response across all groups

  • fixef::Union{Nothing, Tuple{T, T}} where T<:AbstractFloat: Population fixed-effects (intercept, slope); nothing for the table-based constructor

  • shrunken_intercept::Union{Nothing, Vector{T}} where T<:AbstractFloat: Per-group shrunken/BLUP intercept; nothing for the table-based constructor

  • shrunken_slope::Union{Nothing, Vector{T}} where T<:AbstractFloat: Per-group shrunken/BLUP slope; nothing for the table-based constructor

source
MixedModelsMakie.facetregressioninfo — Function
facetregressioninfo(data, response, predictor, group)::FacetRegressionInfo

Compute the per-group data and within-unit OLS fits underlying facetregression! from a Tables.jl-compatible data source.

response, predictor, and group are Symbol or AbstractString column names. fixef, shrunken_intercept, and shrunken_slope are nothing for this table-based method (there is no model to derive them from).

source
facetregressioninfo(m::LinearMixedModel, predictor, group=first(fnames(m)))::FacetRegressionInfo
facetregressioninfo(m::LinearMixedModel; group=first(fnames(m)))::FacetRegressionInfo

Compute the per-group data and within-unit OLS fits underlying facetregression! from a fitted LinearMixedModel, sourced entirely from the model's own matrices (m.X, m.y, m.reterms) rather than a raw data table – see ranefinfo (caterpillar.jl) and the co-occurrence extraction in nesting.jl for the precedent of using only ReMat.refs/.levels this way. Also populates fixef (the population intercept/slope) and, per group, shrunken_intercept/shrunken_slope (fixed effects + that group's conditional modes from ranef(m)).

predictor may be omitted, in which case it defaults to the model's only non-intercept fixed-effect term – this throws an ArgumentError if the model has more than one such term.

source
MixedModelsMakie.facetregression! — Function
facetregression(data, response, predictor, group; kwargs...)::Figure
facetregression!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, data, response, predictor, group; kwargs...)
facetregression(m::LinearMixedModel, predictor, group=first(fnames(m)); kwargs...)::Figure
facetregression!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::LinearMixedModel, predictor,
                 group=first(fnames(m)); kwargs...)
facetregression(m::LinearMixedModel; group=first(fnames(m)), kwargs...)::Figure
facetregression!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, m::LinearMixedModel;
                 group=first(fnames(m)), kwargs...)
facetregression(info::FacetRegressionInfo; kwargs...)::Figure
facetregression!(f::Union{GridLayoutBase.GridLayout, GridLayoutBase.GridPosition, GridLayoutBase.GridSubposition, Makie.Figure}, info::FacetRegressionInfo; kwargs...)

Create a Cleveland-trellis-style small-multiples display: one panel per level of group, each showing a scatter of response against predictor plus that group's own OLS regression line.

The table-based methods take response, predictor, and group as Symbol or AbstractString column names into any Tables.jl-compatible data.

The LinearMixedModel-based methods instead extract everything from the model's own matrices — no data table is needed. predictor must be the name of a continuous fixed-effect term (e.g. :days); group names a grouping factor and defaults to the first one (first(fnames(m))). Two extra reference lines are drawn in every panel: the population-level fixed-effects fit (show_fixef, the same line in every panel) and that group's own shrunken/BLUP fit (show_shrunken`).

predictor may be omitted entirely (note group then becomes keyword-only, to avoid ambiguity with the predictor positional argument), in which case it defaults to the model's only non-intercept fixed-effect term — this throws an ArgumentError if the model has more than one such term.

Alternatively, facetregressioninfo may be used to construct the FacetRegressionInfo object directly. Constructing it directly can be used to avoid re-computing the per-group OLS fits (and, for a model source, fixef/ ranef) when generating multiple plots (e.g. with different layout or bank45 settings) from the same data.

All panels share linked x/y axes (Cleveland-trellis convention), so slopes and scatter remain visually comparable across panels.

Evolving design

facetregression is still experimental. The keyword set (e.g. the LinearMixedModel overlay colors/lines, banking behavior) may change in minor releases without being treated as breaking.

Keywords

  • orderby::Union{Symbol,Nothing}=nothing panel order — nothing preserves the order groups are first encountered (not alphabetical), :intercept/:slope sort by the group's own within-unit OLS fit.
  • rev::Bool=false: reverse the panel order produced by orderby (applied after sorting, so it also reverses nothing's first-encountered order).
  • layout::Union{Nothing,Tuple{Union{Nothing,Int},Union{Nothing,Int}}}=nothing: (nrow, ncol) grid shape. nothing auto-computes a roughly square grid. Either element may be nothing to auto-compute just that one from the other (e.g. layout=(2, nothing) fixes 2 rows and picks enough columns to fit every group). If both are given and their product is smaller than the number of groups, the grid is used as given (never enlarged) and a warning reports how many trailing groups are left undisplayed.
  • bank45::Bool=true: shape the grid columns (via colsize! with a GridLayoutBase.Aspect size) so that a line with the mean of the per-group within-unit OLS slopes appears at 45° on screen ("banking", after Cleveland's trellis displays), easing visual comparison of slopes across panels. Full data is always shown — banking reshapes the panels, it never clips data. bank45=false leaves panels at their natural (roughly square) shape.
  • xlabel/ylabel: shared axis titles spanning the whole grid (default to the predictor/response names).
  • scattercolor, linecolor: per-panel scatter and within-unit regression-line colors.
  • show_fixef::Bool=true, fixefcolor=:black, fixeflinestyle=:dash: whether to draw the population fixed-effects line (LinearMixedModel source only).
  • show_shrunken::Bool=true, shrunkencolor=:green: whether to draw the per-group shrunken/BLUP line (LinearMixedModel source only).
  • labelcolor, labelsize: styling for the per-panel group-level corner label.

The mutating methods return the original object.

source
using CairoMakie
CairoMakie.activate!(; type="svg")
using MixedModels
using MixedModelsMakie

sleepstudy = MixedModels.dataset(:sleepstudy)

facetregression(sleepstudy, :reaction, :days, :subj)
Example block output
# order panels by slope instead of table order
facetregression(sleepstudy, :reaction, :days, :subj; orderby=:slope)
Example block output
# disable banking to compare against the natural data-range aspect
facetregression(sleepstudy, :reaction, :days, :subj; bank45=false)
Example block output

facetregression can also be built directly from a fitted LinearMixedModel, with no data table needed. This additionally overlays two reference lines in every panel: the population-level fixed-effects fit (black, dashed) and that group's shrunken/BLUP fit (green), alongside the within-unit OLS fit (red):

fm1 = fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days | subj)), sleepstudy;
          progress=false)
facetregression(fm1, :days)
Example block output

predictor may be omitted when the model has exactly one non-intercept fixed effect:

facetregression(fm1)
Example block output

Computing the per-group OLS fits (and, for a model, fixef/ranef) can be expensive to repeat, so facetregressioninfo can be called once and the resulting FacetRegressionInfo reused across multiple facetregression calls:

info = facetregressioninfo(fm1, :days)

facetregression(info)
Example block output
facetregression(info; bank45=false)
Example block output

The per-group fits are also available as a table via facetregressioninfotable:

MixedModelsMakie.facetregressioninfotable — Function
facetregressioninfotable(info::FacetRegressionInfo; orderby::Union{Symbol,Nothing}=nothing, rev::Bool=false)
facetregressioninfotable(data, response, predictor, group; orderby::Union{Symbol,Nothing}=nothing, rev::Bool=false)
facetregressioninfotable(m::LinearMixedModel, predictor, group=first(fnames(m));
                         orderby::SUnion{Symbol,Nothing}=nothing, rev::Bool=false)
facetregressioninfotable(m::LinearMixedModel; group=first(fnames(m)),
                         orderby::Union{Symbol,Nothing}=nothing, rev::Bool=false)

Return the per-group OLS fits in info (or derived from data/m) underlying facetregression! as a column table, one row per level of group, with columns:

  • group: the group level
  • n: number of observations in that group
  • intercept, slope: the group's within-unit OLS fit of response on predictor

As with facetregression!, predictor may be omitted for the LinearMixedModel methods (group then becomes keyword-only), defaulting to the model's only non-intercept fixed-effect term.

The LinearMixedModel-derived info additionally has:

  • fixef_intercept, fixef_slope: the population fixed-effects fit (same for every row)
  • shrunken_intercept, shrunken_slope: that group's shrunken/BLUP fit (fixed effects plus that group's conditional modes from ranef(m))

orderby and rev have the same meaning as in facetregression!.

The data/m-based methods are convenience wrappers equivalent to facetregressioninfotable(facetregressioninfo(data_or_m, args...); orderby, rev).

Evolving design

facetregression/facetregressioninfotable are still experimental and their design (e.g. the LinearMixedModel columns) may change in minor releases without being treated as breaking. Relatedly, the binding facetregressiontable is deprecated and may be removed in a future release without being considered breaking.

source
facetregressioninfotable(sleepstudy, :reaction, :days, :subj; orderby=:slope)
(group = ["S335", "S309", "S330", "S331", "S310", "S351", "S333", "S371", "S332", "S372", "S369", "S334", "S349", "S352", "S370", "S337", "S350", "S308"], n = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], intercept = [263.03469737659805, 205.05494440252136, 289.68509798916904, 285.7389703924006, 203.48422352183954, 261.14700899991124, 275.01910344904115, 253.6360368208452, 264.25161299272025, 267.04480535333806, 254.96814353249292, 240.16292197487567, 215.1117673006925, 276.3720753062856, 210.4490952925249, 290.1041281960228, 225.83460471413352, 244.19267134232956], slope = [-2.8810344349254366, 2.261785426284321, 3.0080716219815313, 5.26601710464015, 6.1148997913707275, 6.433497850822675, 9.142044529770361, 9.188445675011828, 9.56676700476443, 11.298072768702644, 11.348109759706436, 12.253140073834047, 13.493933845288817, 13.566547555634457, 18.056149939334745, 19.025972678444585, 19.504016945578833, 21.764700964725375])
facetregressioninfotable(fm1, :days; orderby=:slope)
(group = ["S335", "S309", "S330", "S331", "S310", "S351", "S333", "S371", "S332", "S372", "S369", "S334", "S349", "S352", "S370", "S337", "S350", "S308"], n = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], intercept = [263.03469737659805, 205.05494440252136, 289.68509798916904, 285.7389703924006, 203.48422352183954, 261.14700899991124, 275.01910344904115, 253.6360368208452, 264.25161299272025, 267.04480535333806, 254.96814353249292, 240.16292197487567, 215.1117673006925, 276.3720753062856, 210.4490952925249, 290.1041281960228, 225.83460471413352, 244.19267134232956], slope = [-2.8810344349254366, 2.261785426284321, 3.0080716219815313, 5.26601710464015, 6.1148997913707275, 6.433497850822675, 9.142044529770361, 9.188445675011828, 9.56676700476443, 11.298072768702644, 11.348109759706436, 12.253140073834047, 13.493933845288817, 13.566547555634457, 18.056149939334745, 19.025972678444585, 19.504016945578833, 21.764700964725375], fixef_intercept = [251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093, 251.4051060532093], fixef_slope = [10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485, 10.467285505609485], shrunken_intercept = [250.3674418963411, 211.35668964980192, 274.2371315591448, 272.954875422857, 212.97208811143793, 255.67906978575976, 267.84697165685594, 252.1283579763354, 260.2206227446339, 263.5239987305756, 254.66363623139867, 244.40846372149852, 226.8471416910777, 272.02726978239303, 226.69505976457546, 286.0713847623575, 239.07071702004563, 254.22098845065835], shrunken_slope = [-0.13212675748280844, 1.8231868995316258, 5.808582434814334, 7.522805054654685, 4.953868891044062, 7.511957723499471, 10.308485653239533, 9.49623460531637, 10.232089424740735, 11.777990014697734, 11.338998486208961, 11.500008033385004, 11.531648462975104, 14.02900794190443, 15.126970362404837, 19.099685773373505, 16.938951487110348, 19.542794609551635])

General plots

We also provide a splom or scatter-plot matrix plot for data frames with numeric columns (i.e. a matrix of all pairwise plots). These plots can be used to visualize the joint distribution of, say, the parameter estimates from a simulation.

MixedModelsMakie.splom! — Function
splom!(f::Indexable, df::DataFrame)

Create a scatter-plot matrix in f from the columns of df.

Non-numeric columns are ignored.

source
using CairoMakie
CairoMakie.activate!(; type="svg")
using DataFrames
using LinearAlgebra
using MixedModelsMakie

data = rmul!(randn(100, 3), LowerTriangular([+1 +0 +0;
                                             +1 +1 +0;
                                             -1 -1 +1]))
df = DataFrame(data, [:x, :y, :z])

splom!(Figure(; size=(800, 800)), df)
Example block output

Meanwhile, splomaxes! provides a lower-level backend for splom!

MixedModelsMakie.splomaxes! — Function
splomaxes!(f::Indexable, labels::AbstractVector{<:AbstractString},
           panel!::Function, args...;
           extraticks::Bool=false, kwargs...)

Populate f with a set of (k*(k-1))/2 axes in a lower triangle for all pairs of labels, where k is the length of labels. The panel! function should have the signature panel!(ax::Axis, i::Integer, j::Integer, args...; kwargs...) and should draw the [i,j] panel in ax.

source
using Statistics

mat = Array(df)
function pfunc(ax, i, j)
    # note that this references mat from the outer scope!
    # [j, i] because:
    # - i is the row in the figure, which corresponds to the y var in each panel
    # - j is the col in the figure, which corresponds to the x var in each panel
    v = view(mat, :, [j, i])
    scatter!(ax, v; color=(:blue, 0.2))
    cc = cor(eachcol(v)...)
    cc = round(cc; digits=2)
    text!(ax, "r=$(cc)")
    return ax
end
splomaxes!(Figure(; size=(800, 800)),
           names(df), pfunc)
Example block output
  • upsetLex, A., Gehlenborg, N., Strobelt, H., Vuillemot, R., & Pfister, H. (2014). UpSet: Visualization of Intersecting Sets. IEEE Transactions on Visualization and Computer Graphics, 20(12), 1983–1992. https://doi.org/10.1109/TVCG.2014.2346248