Skip to content

Conversation

@philippeller
Copy link
Collaborator

@philippeller philippeller commented May 27, 2025

Overview

This PR is adding plotting functions to BAT for use with Makie.jl

Some basic plot types are implemented for 1d and 2d. The plotting is fully extensible by providing structs of abstract type plot_cfg_1d and plot_cfg_2d, respectively, together with corresponding function implementations:

function plot1d!(ax::Axis, cfg::plot_cfg_1d, x::AbstractArray, w::Union{Real, AbstractArray}=1)
    ...
end

or, respectively,

function plot2d!(ax::Axis, cfg::plot_cfg_2d, x::AbstractArray, y::AbstractArray, w::Union{Real, AbstractArray}=1)
    ...
end

Current recipes include:

1d plots:

  • hist1d : simple density hist
  • quantile_hist1d: density hist with colored quantiles
  • kde1d: KDE
  • quantile_kde1d: KDE with colored quantiles
  • mean1d: lines for mean values
  • std1d: lines for standard deviations
  • pdf1d: priors

2d plots:

  • hist2d: simple density hist
  • quantile_hist2d: 2d quantiles based on a histogram
  • kde2d: 2d KDE
  • quantile_kde2d: 2d quantiles based on a KDE
  • scatter2d: scatter plot
  • mean2d: lines for mean values
  • std2d: lines for standard deviations
  • cov2d: ellipse of 2d covariance
  • hexbin2d: hexbin density

Example usage:

using BAT
using MeasureBase
using DensityInterface
using Distributions
using LinearAlgebra

params = (a=1, b=1, c=1)
priors = (a=Normal(), b=Uniform(-2,2), c=Cauchy())

function fwd(a, b, c)
    return MvNormal([a,b,c], I(3))
end

likelihood = likelihoodof(splat(fwd), [0,0,0])

prior = distprod(;priors...)
posterior = PosteriorMeasure(likelihood, prior)
samples = bat_sample(posterior).result
[ Info: Setting new default BAT context BATContext{Float64}(Random123.Philox4x{UInt64, 10}(0x0e7baf8ab291ff8c, 0x5b0485835223e643, 0x64f865a9c835b39b, 0xcbdf37fe9c162917, 0xdbf6235e76e2b0ed, 0xca60cc8ac70af658, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0), HeterogeneousComputing.CPUnit(), BAT._NoADSelected())
┌ Info: Using sampling algorithm TransformedMCMC{RandomWalk{TDist{Float64}}, NoMCMCProposalTuning, PriorToNormal, BAT.TriangularAffineTransform, RAMTuning, BAT.NoMCMCTempering, MCMCChainPoolInit, MCMCMultiCycleBurnin, BrooksGelmanConvergence, RepetitionWeighting{Int64}, typeof(BAT.nop_func)}
│   proposal: RandomWalk{TDist{Float64}}
│   proposal_tuning: NoMCMCProposalTuning NoMCMCProposalTuning()
│   pretransform: PriorToNormal PriorToNormal()
│   adaptive_transform: BAT.TriangularAffineTransform BAT.TriangularAffineTransform()
│   transform_tuning: RAMTuning
│   tempering: BAT.NoMCMCTempering BAT.NoMCMCTempering()
│   nchains: Int64 4
│   nwalkers: Int64 1
│   nsteps: Int64 100000
│   init: MCMCChainPoolInit
│   burnin: MCMCMultiCycleBurnin
│   convergence: BrooksGelmanConvergence
│   strict: Bool true
│   store_burnin: Bool false
│   nonzero_weights: Bool true
│   sample_weighting: RepetitionWeighting{Int64} RepetitionWeighting{Int64}()
└   callback: nop_func (function of type typeof(BAT.nop_func))
[ Info: MCMCChainPoolInit: trying to generate 4 viable MCMC chain state(s).
[ Info: Selected 4 MCMC chain state(s).
[ Info: Begin tuning of 4 MCMC chain(s).
[ Info: MCMC Tuning cycle 1 finished, 4 chains, 4 tuned, 4 converged.
[ Info: MCMC tuning of 4 chains successful after 1 cycle(s).
[ Info: Running post-tuning stabilization steps for 4 MCMC chain(s).





DensitySampleVector, StructArray with 5 columns and 93711 rows:
      v                       logd      weight  info                    aux
    ┌──────────────────────────────────────────────────────────────────────────
 1  │ (a = -0.527213, b = -…  -8.00545  1       MCMCSampleID(2, 1, 5,…  nothing
 2  │ (a = -0.902307, b = 0…  -8.81496  1       MCMCSampleID(2, 1, 5,…  nothing
 3  │ (a = -0.419528, b = -…  -7.92013  5       MCMCSampleID(2, 1, 5,…  nothing
 4  │ (a = 1.27401, b = 0.4…  -8.05164  7       MCMCSampleID(2, 1, 5,…  nothing
 5  │ (a = 0.828691, b = 1.…  -7.77259  4       MCMCSampleID(2, 1, 5,…  nothing
 6  │ (a = -0.576574, b = 0…  -7.18844  13      MCMCSampleID(2, 1, 5,…  nothing
 7  │ (a = -1.73847, b = 0.…  -10.2505  12      MCMCSampleID(2, 1, 5,…  nothing
 8  │ (a = -1.44753, b = -0…  -9.62168  1       MCMCSampleID(2, 1, 5,…  nothing
 9  │ (a = -1.18581, b = -0…  -8.30775  4       MCMCSampleID(2, 1, 5,…  nothing
 10 │ (a = 0.272162, b = -0…  -6.90886  4       MCMCSampleID(2, 1, 5,…  nothing
 11 │ (a = -0.600647, b = 0…  -7.47888  2       MCMCSampleID(2, 1, 5,…  nothing
 12 │ (a = -0.17869, b = 0.…  -6.71362  2       MCMCSampleID(2, 1, 5,…  nothing
 13 │ (a = -0.183446, b = 1…  -6.8689   2       MCMCSampleID(2, 1, 5,…  nothing
 14 │ (a = -0.219895, b = 0…  -6.36154  10      MCMCSampleID(2, 1, 5,…  nothing
 15 │ (a = -1.70216, b = 0.…  -9.50329  2       MCMCSampleID(2, 1, 5,…  nothing
 16 │ (a = -2.36132, b = 0.…  -11.9043  1       MCMCSampleID(2, 1, 5,…  nothing
 17 │ (a = -1.82908, b = 0.…  -9.84521  2       MCMCSampleID(2, 1, 5,…  nothing
 18 │ (a = -0.703324, b = 0…  -7.07286  6       MCMCSampleID(2, 1, 5,…  nothing
 19 │ (a = 1.28891, b = 0.6…  -8.41924  16      MCMCSampleID(2, 1, 5,…  nothing
 20 │ (a = 1.00916, b = -0.…  -7.56799  6       MCMCSampleID(2, 1, 5,…  nothing
 21 │ (a = 1.10518, b = 0.0…  -7.75326  6       MCMCSampleID(2, 1, 5,…  nothing
 22 │ (a = -0.740396, b = 0…  -7.06155  3       MCMCSampleID(2, 1, 5,…  nothing
 23 │ (a = -0.653221, b = -…  -6.96074  2       MCMCSampleID(2, 1, 5,…  nothing
 ⋮  │           ⋮                ⋮        ⋮               ⋮                ⋮
using CairoMakie, DataStructures
plot(samples)

download

variables = OrderedDict("a" => "Var A (units)", "b"=>"Var B", "c"=>"Var C")
OrderedDict{String, String} with 3 entries:
  "a" => "Var A (units)"
  "b" => "Var B"
  "c" => "Var C"
fig = plot(samples, variables=variables, diagonal=quantile_kde1d(), lower_triangle=nothing, upper_triangle=scatter2d(size=0.5))
fig = plot!(fig, samples, variables=variables, lower_triangle=quantile_kde2d())
fig = plot!(fig, samples, variables=variables, lower_triangle=mean2d(color=:orange, linestyle=:solid), upper_triangle=mean2d(color=:black, linestyle=:solid, linewidth=1))
fig = plot!(fig, samples, variables=variables, upper_triangle=cov2d(linewidth=1.5))
fig = plot!(fig, samples, variables=variables, diagonal=mean1d(color=:orange, linestyle=:solid))
fig = plot!(fig, samples, variables=variables, diagonal=std1d(color=:orange, linestyle=:dash), lower_triangle=std2d(color=:orange, linestyle=:dash))
fig = plot!(fig, prior, variables=variables, diagonal=pdf1d(edgecolor=:magenta, color=:magenta, edge=true, filled=true, edgewidth=1, alpha=0.2))

download

@codecov
Copy link

codecov bot commented May 27, 2025

Codecov Report

Attention: Patch coverage is 0% with 264 lines in your changes missing coverage. Please review.

Project coverage is 48.20%. Comparing base (b08cff2) to head (6e54e1d).

Files with missing lines Patch % Lines
src/plotting/plotting_makie.jl 0.00% 264 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #477      +/-   ##
==========================================
- Coverage   50.34%   48.20%   -2.14%     
==========================================
  Files         121      122       +1     
  Lines        5961     6225     +264     
==========================================
  Hits         3001     3001              
- Misses       2960     3224     +264     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@philippeller
Copy link
Collaborator Author

ping @oschulz

@oschulz
Copy link
Member

oschulz commented Jul 7, 2025

Thanks for the reminder, I'll take a look later!

@philippeller
Copy link
Collaborator Author

@oschulz ?

@oschulz
Copy link
Member

oschulz commented Sep 9, 2025

I talked to some of the Makie developers at JuliaCon. They strongly discourage specializing Makie.plot and Makie.plot! to implement type-speficic plotting recipes. Instead, we're supposed to specialize Makie.convert_arguments and use Makie.PlotSpec when subplots are required (kinda like in https://github.com/JuliaHEP/HEPExampleProject.jl/blob/main/ext/HEPExampleProjectMakieExt.jl).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants