Plotting
Use sample_array()
to convert target chain samples into a format that can then be consumed by third party plotting packages such as MCMCChains.jl and PairPlots.jl.
See below for examples of posterior densities and trace plots.
Posterior densities and trace plots
Make sure to have the third party DynamicPPL
, MCMCChains
, and StatsPlots
packages installed via
using Pkg; Pkg.add("DynamicPPL", "MCMCChains", "StatsPlots")
Then use the following:
using DynamicPPL
using Pigeons
using MCMCChains
using StatsPlots
plotlyjs()
# example target: Binomial likelihood with parameter p = p1 * p2
an_unidentifiable_model = Pigeons.toy_turing_unid_target(100, 50)
pt = pigeons(target = an_unidentifiable_model,
n_rounds = 12,
# make sure to record the trace:
record = [traces; round_trip; record_default()])
# collect the statistics and convert to MCMCChains' Chains
# to have axes labels matching variable names in Turing and Stan
samples = Chains(sample_array(pt), sample_names(pt))
# since the above line is frequently needed, Pigeons includes
# an MCMCChains extension allowinging you to use the shorter form:
samples = Chains(pt)
# create the trace plots
my_plot = StatsPlots.plot(samples)
StatsPlots.savefig(my_plot, "posterior_densities_and_traces.html");
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
scans restarts Λ time(s) allc(B) log(Z₁/Z₀) min(α) mean(α) min(αₑ) mean(αₑ)
────────── ────────── ────────── ────────── ────────── ────────── ────────── ────────── ────────── ──────────
2 0 3.24 0.00147 1.07e+06 -8.14 0.00178 0.64 1 1
4 0 1.64 0.00297 2.1e+06 -5.04 0.0352 0.818 1 1
8 0 1.17 0.0348 4.11e+06 -4.42 0.708 0.871 1 1
16 1 1.2 0.00798 8.67e+06 -4.03 0.549 0.867 1 1
32 6 1.11 0.0155 1.7e+07 -4.77 0.754 0.877 1 1
64 11 1.35 0.0313 3.41e+07 -4.79 0.698 0.85 1 1
128 25 1.6 0.0652 6.75e+07 -4.97 0.725 0.823 1 1
256 43 1.51 0.175 1.33e+08 -4.92 0.758 0.832 1 1
512 92 1.46 0.298 2.69e+08 -5 0.806 0.838 1 1
1.02e+03 188 1.49 0.623 5.39e+08 -4.92 0.798 0.834 1 1
2.05e+03 384 1.5 1.23 1.08e+09 -4.96 0.811 0.834 1 1
4.1e+03 748 1.48 2.46 2.15e+09 -4.94 0.826 0.835 1 1
─────────────────────────────────────────────────────────────────────────────────────────────────────────────
Monitoring the log density
The value of the log density is appended to each sample. Continuing the above example, this can be seen from the variable names indexing the flattened vector created by sample_array()
:
sample_names(pt)
3-element Vector{Symbol}:
:p1
:p2
:log_density
When using the Chains(pt)
constructor as shown above, the un-normalized log density is stored inside MCMCChains' "internal" storage so will not appear in plots by default. To show it, use the following:
params, internals = MCMCChains.get_sections(samples)
my_plot = StatsPlots.plot(internals)
StatsPlots.savefig(my_plot, "logdensity.html");
Posterior pair plots
The code snippet in this section only works with Julia 1.9. See https://sefffal.github.io/PairPlots.jl/dev/chains/ for a workaround.
Make sure to have the third party packages DynamicPPL
, MCMCChains
, CairoMakie
, and PairPlots
installed via
using Pkg; Pkg.add("DynamicPPL", "MCMCChains", "CairoMakie", "PairPlots")
using DynamicPPL
using Pigeons
using MCMCChains
using CairoMakie
using PairPlots
# same examples as last section
an_unidentifiable_model = Pigeons.toy_turing_unid_target(100, 50)
pt = pigeons(target = an_unidentifiable_model,
n_rounds = 12,
# make sure to record the trace:
record = [traces; round_trip; record_default()])
samples = Chains(pt)
# Warning: the line below only works for Julia 1.9
# see https://sefffal.github.io/PairPlots.jl/dev/chains/ for a workaround
my_plot = PairPlots.pairplot(samples)
CairoMakie.save("pair_plot.svg", my_plot)
nothing # hide