Skip to content

Makie interactivity - #514

Open
Micki-D wants to merge 141 commits into
makie-core-fixesfrom
makie_recipies
Open

Micki-D wants to merge 141 commits into
makie-core-fixesfrom
makie_recipies

Conversation

@Micki-D

@Micki-D Micki-D commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

[Experimental][WIP] Add an extension for Makie.jl plotting

This is based on PR #477 using @philippeller 's custom Makie plotting but with dedicated BAT.jl infrastructure for handling the marginalization of samples.

This implements an extension module with reactive Makie.jl recipies that offer more flexible visualization and enable live plotting of MCMC data during sampling.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an experimental Makie.jl-based plotting/visualization extension to BAT, including a new BATVisualizer infrastructure that can be wired into MCMC sampling to enable live/interactive plotting.

Changes:

  • Introduces BATVisualizer / BATVisBackend and integrates it into BATContext, plus adds visualizer update hooks to the MCMC iteration loop.
  • Adds the BATMakieExt package extension and Makie “recipes” implemented via Makie’s ComputeGraph + SpecApi to render corner-style plots and overlays.
  • Adds helper utilities for marginalization/index selection and plumbs Makie extension debug logging.

Reviewed changes

Copilot reviewed 19 out of 23 changed files in this pull request and generated 24 comments.

Show a summary per file
File Description
src/utils/error_log.jl Adds BATMakieExt to debug logging module set; minor formatting.
src/samplers/mcmc/multi_cycle_burnin.jl Passes callback through to mcmc_iterate!! during burn-in cycles.
src/samplers/mcmc/mcmc_state.jl Mostly formatting/whitespace; no functional changes noted.
src/samplers/mcmc/mcmc_sample.jl Initializes/upgrades visualizer integration during sampling; adds output merge/append helpers.
src/samplers/mcmc/mcmc_algorithm.jl Adds update_visualizer + callback kwargs to mcmc_iterate!! and invokes them each step.
src/samplers/mcmc/chain_pool_init.jl Keyword formatting changes; no functional changes noted.
src/plotting/vsel_processing.jl Formatting changes; marginalization utilities unchanged logically.
src/plotting/valueshapes_utils_internal.jl Minor signature formatting; adjusts unshaped error message (currently buggy).
src/extdefs/makie_defs.jl Adds Makie-related public type/function stubs for the extension.
src/extdefs/extdefs.jl Includes makie_defs.jl.
src/algotypes/bat_visualizer.jl Introduces BATVisualizer and backend abstractions.
src/algotypes/bat_context.jl Adds visualizer::BATVisualizer to BATContext and updates constructors/helpers.
src/algotypes/algotypes.jl Includes new bat_visualizer.jl.
Project.toml Adds Makie as a weak dep + extension entry.
ext/BATMakieExt.jl New Makie extension module wiring in Makie impl files and defining extension entrypoint.
ext/makie_impl/makie_plotting.jl Includes Makie implementation files and imports Makie.
ext/makie_impl/bat_makie_recipe.jl Defines recipe/cell status machinery and generic API hooks.
ext/makie_impl/makie_visualizer.jl Implements the live Makie visualizer using ComputeGraph and async updates.
ext/makie_impl/makie_stats.jl Implements stats overlay recipes (mean/std/cov/errorbars/pdf) for Makie.
ext/makie_impl/makie_scatter.jl Implements scatter recipe.
ext/makie_impl/makie_kde.jl Implements KDE + quantile KDE recipes.
ext/makie_impl/makie_hist.jl Implements histogram + quantile histogram + hexbin recipes.
ext/makie_impl/makie_plot_samples.jl Adds a Makie recipe (convert_arguments) and a bat_makie_plot helper for samples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/samplers/mcmc/mcmc_sample.jl Resolved
Comment thread ext/makie_impl/makie_scatter.jl Resolved
Comment thread ext/makie_impl/makie_hist.jl Resolved
Comment thread ext/makie_impl/makie_hist.jl Resolved
Comment thread ext/makie_impl/makie_visualizer.jl Resolved
Comment thread ext/makie_impl/makie_plot_samples.jl Resolved
Comment thread ext/makie_impl/makie_plot_samples.jl Resolved
Comment thread src/samplers/mcmc/mcmc_sample.jl Resolved
Comment thread ext/makie_impl/makie_stats.jl Resolved
@codecov

codecov Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.35683% with 245 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (makie-core-fixes@1e6ddfa). Learn more about missing BASE report.

Files with missing lines Patch % Lines
ext/makie_impl/makie_render_utils.jl 28.34% 134 Missing ⚠️
src/samplers/mcmc/mcmc_sample.jl 64.61% 23 Missing ⚠️
ext/makie_impl/makie_live_lifecycle.jl 95.71% 16 Missing ⚠️
ext/makie_impl/makie_visualizer.jl 95.69% 12 Missing ⚠️
src/samplers/mcmc/mcmc_algorithm.jl 76.59% 11 Missing ⚠️
ext/makie_impl/makie_stats.jl 96.06% 10 Missing ⚠️
ext/makie_impl/makie_hist.jl 98.35% 5 Missing ⚠️
ext/makie_impl/makie_controls_panel.jl 98.75% 4 Missing ⚠️
ext/makie_impl/makie_live_view.jl 97.98% 4 Missing ⚠️
ext/makie_impl/makie_plot_samples.jl 95.18% 4 Missing ⚠️
... and 10 more
Additional details and impacted files
@@                 Coverage Diff                 @@
##             makie-core-fixes     #514   +/-   ##
===================================================
  Coverage                    ?   81.28%           
===================================================
  Files                       ?      144           
  Lines                       ?    11206           
  Branches                    ?        0           
===================================================
  Hits                        ?     9109           
  Misses                      ?     2097           
  Partials                    ?        0           

☔ View full report in Codecov by Harness.
📢 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.

Rebuild owned cell plots when polygon content changes so fills cannot be appended above reused statistical overlays. Add shared Cairo and native GL window regressions, and declare all direct optional-test imports.

Validated against the exact committed source: 59 primary cases, 12 selected floor cases, and native GL plus active live-publication checks on both pins. The restored baseline reuse rule is rejected by the new regression.

@BJMCox BJMCox left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 50ec5352 against 3647462b. Six reproducible findings are attached to the relevant changed lines, each with its MRE and proposed fix.

The full core suites pass on Julia 1.13.3: base 1,240 tests, head 105,706 tests. The MREs expose failures outside that coverage. Plotting checks used CairoMakie. Native GL was not exercised. The x86 finding uses current CI evidence.

I recommend addressing these six findings before merging. Non-blocking improvements are in a separate review comment.

Comment thread src/samplers/mcmc/mcmc_stats.jl Resolved
Comment thread ext/makie_impl/makie_stats.jl Resolved
Comment thread src/samplers/mcmc/multi_cycle_burnin.jl Resolved
Comment on lines +548 to +552
new_vars = _vsel_after_toggle(active_vars[], i, j, is_on)

if is_on && length(new_vars) > N_max
updating_programmatically[] = true
cb.checked[] = false

@BJMCox BJMCox Oct 26, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The picker shows only the first ten variables but retains the full initial selection. With valid vsel=[11] and N_max=1, variable 11 consumes the only slot and has no checkbox to remove it.

This capacity check then rejects every visible replacement. In the MRE, selecting variable 1 resets its checkbox to false and leaves the axis at $v_11$. None of the 55 checkboxes represents variable 11.

Make every selected variable removable. A clear-selection control or visible slots for selected high indices can preserve the compact picker.

Reproduced through the public plotting entry point at 50ec5352, using headless CairoMakie 0.15.16 and Makie 0.24.16.

MRE: an 11-dimensional sample and one available plot slot
using BAT, CairoMakie, Makie

function main()
    samples = DensitySampleVector(
        v = [Float64.(1:11), Float64.(2:12)],
        logd = zeros(2),
    )
    recipes = (upper = Hist2D, diagonal = Hist1D, lower = Hist2D)
    fig = bat_makie_plot(samples, recipes, [11], 1; display = false)
    try
        axis = only(filter(x -> x isa Axis, fig.content))
        first_visible = first(filter(x -> x isa Checkbox, fig.content)) # variable 1
        before = String(axis.xlabel[])
        first_visible.checked[] = true # request variable 1
        @show before String(axis.xlabel[]) first_visible.checked[]
    finally
        empty!(fig)
    end
end

main()

Comment thread src/statistics/onlineuvstats.jl Resolved
Comment thread test/statistics/test_ks_test.jl Resolved

@BJMCox BJMCox left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate non-blocking suggestions for 50ec5352:

  1. Keep the weight checks and reduce allocation when no rows are removed. The new guards protect against invalid mass and overflow. With one million uniform weights, drop_low_weight_samples still returns the original object but allocates 8,143,008 bytes at head versus zero at base. Each warmed result repeated three times. Validate the weights, then return early when their extrema prove that no filtering is needed. See weight normalization and the caller. This probe measures allocation, not throughput.
Allocation MRE: run at base 3647462 and head 50ec535
using BAT

function filter_identity_allocations(n)
    samples = DensitySampleVector(v=fill([0.0], n), logd=zeros(n), weight=ones(n))
    BAT.drop_low_weight_samples(samples) # Compile before measuring.
    bytes = [@allocated(BAT.drop_low_weight_samples(samples)) for _ in 1:3]
    @assert BAT.drop_low_weight_samples(samples) === samples
    return (rows=n, allocated_bytes=bytes)
end

results = filter_identity_allocations.((1_000, 100_000, 1_000_000))
foreach(println, results)
results
  1. Skip timing storage when timing is absent. Shared static setup is useful. However, _setup_static_graph creates one empty timing vector per row even when step_intervals=nothing. It groups those vectors, then supplies sample_timing=nothing. Gate that construction on available timing. This observation follows from the source. No whole-figure speedup was measured.

  2. Connect the numerical tests to public behavior. The independent HDR, KDE scaling, KS, and bias-correction oracles are strong. Keep short public tests for disabled overlays, zero-weight recording, and constant log-density offsets. The inline MREs provide those cases. In the precompile workload tests, retain process isolation and cleanup assertions. Trim exact private-call counts where they constrain implementation without protecting supported behavior.

  3. Make coverage match the optional tests that run. The bounded subprocess runner and separate optional jobs are useful. The Makie and Plots jobs currently omit coverage collection and upload. Enable both, including child Julia commands. Zero reported coverage does not mean those tests are absent. Keep the Cairo-only scope explicit and record native GL and real process-interruption checks separately. The latest Makie jobs took about 50–53 minutes against a 60-minute limit. Preserve isolation for lifecycle cases, and consider grouping deterministic numerical cases where isolation is unnecessary.

  4. Use one credible-level policy across recipes. Histograms accept probability one and reject invalid levels. KDE recipes silently discard levels outside 0 < p < 1. Share validation and endpoint handling, or document the KDE restriction. The probe below returns zero filled polygons for levels=[1.0], despite producing 2,048 curve points. This is an interface consistency suggestion. The current validation promise is specific to histograms.

MRE: KDE credible-level endpoint
using BAT, CairoMakie

ext = Base.get_extension(BAT, :BATMakieExt)
x = reshape([0., 1., 2., 3.], 1, :)
w = ones(4)
cfg = merge(BAT._default_makie_diagonal_config(), (levels=[1.0],))
result = ext.compute_plotting_primitives(
    view(x, :, :), view(w, :), BAT.QuantileKDE1D(),
    ext.LiveRecipe(), ext.LiveCell(), cfg)
@show length(result.polys) length(result.full_line)
  1. Add a Makie release note under an unreleased heading. The experimental plotting and live visualization features deserve an entry. The current new fixes sit under v5.0.0, although the file already contains v5.1.0 and v5.2.0. Place these changes under the intended next release.

  2. Narrow the new coordinate promise or complete its handling. The new documentation permits nonfinite coordinates where weight is zero. Automatic MarginalDist edges still inspect those rows. Positive mass at 5 plus a zero-weight Inf row causes an empty fallback histogram and an error. This edge-selection behavior exists at the base, so it is excluded from the introduced functional findings. Clarify the new promise or derive automatic edges from positive-weight rows. Preserve explicit-edge behavior.

MRE: the new documented coordinate rule and automatic bins
using BAT

samples(x, w) = DensitySampleVector([[v] for v in x], zeros(length(x)); weight=w)

positive_only = samples([5.0], [1.0])
with_zero_weight_row = samples([5.0, Inf], [1.0, 0.0])

@assert BAT.MarginalDist(positive_only, 1; bins=4) isa BAT.MarginalDist

try
    BAT.MarginalDist(with_zero_weight_row, 1; bins=4)
    println("The zero-weight row was accepted")
catch err
    println("Actual: ", sprint(showerror, err))
end

println("Expected under the new documented coordinate rule: the zero-weight row does not make the marginal distribution fail")
  1. Remove two trailing blank lines. git diff --check 3647462b...50ec5352 reports new EOF blank lines in makie_hist.jl and makie_plot_samples.jl.

@BJMCox BJMCox left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Five further reproduced issues at 50ec5352, with standalone MREs and proposed fixes attached to the relevant lines. Plotting checks used CairoMakie. The sample-filter regression and plain transformed-posterior control were also checked against exact base 3647462b.

Comment thread ext/makie_impl/makie_compute_graph.jl Resolved
Comment thread ext/makie_impl/makie_scatter.jl Resolved
Comment thread src/variates/plot_weight_utils.jl Resolved
Comment on lines +98 to +99
vals, vecs = eigen(Σ)
stds = sqrt.(clamp.(vals, 0, Inf))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This eigendecomposition can lose a positive eigenvalue, but the subsequent checks accept it as a genuinely singular direction. The resulting covariance ellipse silently understates spread.

The MRE uses four corners (±a,±b), with a=2^500, b=2^-500, and weights [3,1,1,3]. Its exact mean is zero and its covariance is [a² 1/2; 1/2 b²]. The correlation determinant is 3/4, so the population is nonsingular. Every coordinate and covariance entry is finite and normal in Float64.

The dense solver returns [0,a²]. The zero standard deviation bypasses the collapsed-axis check at line 111. The public figure renders successfully, but one axis becomes (0,0)-(0,0) and the small-coordinate half-extent becomes 0.49998442344707816*b instead of b. The curve's discretization error is below 0.013%, which cannot explain the roughly 50% error.

The eigensolver's range limitation is upstream. BAT should detect the lost covariance before displaying it, consistent with the overlay admission policy. Please verify the decomposition in each coordinate's scale, or use a stable scaled construction. Preserve genuine singular covariance. A whole-matrix relative norm can hide the small coordinate.

Reproduced through bat_makie_plot and its statistics toggle on Julia 1.13.3, OpenBLAS 0.3.30, Makie 0.24.16, and CairoMakie 0.15.16. The same weighted corners in unit coordinates give the correct ellipse.

MRE
using BAT, Makie, CairoMakie, LinearAlgebra, Test

function covariance_axis_loss()
    a, b = 2.0^500, 2.0^-500
    coordinates = [a -a a -a; b b -b -b]
    source = DensitySampleVector([collect(v) for v in eachcol(coordinates)],
        zeros(4); weight=[3.0, 1.0, 1.0, 3.0])
    recipes = (upper=QuantileHist2D, diagonal=QuantileHist1D, lower=QuantileHist2D)
    figure = bat_makie_plot(source, recipes, [1, 2], 2; display=false)
    try
        first(filter(x -> x isa Toggle, figure.content)).active[] = true
        axis = only(filter(x -> x isa Axis, contents(figure[1, 1][1, 2])))
        ellipse = only(filter(x -> x isa Makie.Lines, axis.scene.plots))[1][]
        principal_axes = only(filter(x -> x isa Makie.LineSegments, axis.scene.plots))[1][]
        image = Makie.colorbuffer(figure) # The public figure renders successfully.

        # Population oracle: exact represented inputs and weights give mean 0,
        # variances a^2 and b^2, and covariance a*b/2 == 1/2. Thus the true
        # ellipse has horizontal half-extent b in this transposed upper cell.
        # Its correlation determinant is 1 - (1/2)^2 == 3/4 > 0.
        expected_covariance = [a^2 0.5; 0.5 b^2]
        observed_ratio = maximum(abs, first.(ellipse)) / b
        evidence = (; expected_covariance,
            eigenvalues=eigvals(expected_covariance), principal_axes,
            expected_small_coordinate_extent=b,
            observed_small_coordinate_extent=maximum(abs, first.(ellipse)),
            observed_ratio, rendered_size=size(image))
        @show evidence
        # Two hundred circle nodes imply <0.00013 relative discretization error.
        # The reviewed head returns 0.49998442344707816, with one axis (0,0)-(0,0).
        @test isapprox(observed_ratio, 1.0; rtol=0.001)
        return evidence
    finally
        empty!(figure)
    end
end

covariance_axis_loss()

Comment on lines +23 to +25
lo, hi = Float64(rawlo), Float64(rawhi)
((isfinite(rawlo) && !isfinite(lo)) || (isfinite(rawhi) && !isfinite(hi))) &&
throw(ArgumentError("KDE support bounds must be representable as Float64"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converting support bounds here can round them inward before membership is checked against the original observations. A valid BigFloat boundary observation then gets rejected as outside its own declared support.

In the MRE, support equals the first and last BigFloat observations, parsed from 0.1 and 0.3. Float64 0.1 exceeds the original lower endpoint, while Float64 0.3 lies below the original upper endpoint. The later membership check compares the original values against that smaller interval. The public graph also stores the narrowed bounds.

The public call throws KDE positive-weight coordinates must be finite and inside hard support. Keeping the original observations and widening only the numerical bounds by one Float64 ULP succeeds and renders. These bounds are far from Float64's range limits.

Please validate original coordinates against original bounds, then convert validated coordinates and bounds consistently for grid construction. Retain conversion checks and rejection of points truly outside the original support. Expanding the membership interval alone would weaken that guarantee.

The MRE proves original membership, checks the direction of rounding, and renders the nearby control through CairoMakie.

MRE
using BAT, Makie, CairoMakie, Test

function kde_support_rounding()
    values = parse.(BigFloat, ["0.1", "0.15", "0.2", "0.25", "0.3"])
    support = (first(values), last(values))
    @assert all(x -> support[1] <= x <= support[2], values)
    @assert Float64(support[1]) > support[1]
    @assert Float64(support[2]) < support[2]
    source = DensitySampleVector([[x] for x in values], zeros(length(values)))
    recipes = (upper=Scatter2D, diagonal=KDE1D, lower=Scatter2D)

    failure = try
        figure = bat_makie_plot(source, recipes, [1], 1;
            support=[support], display=false)
        empty!(figure)
        nothing
    catch err
        err
    end

    # The original BigFloat coordinates pass all other numerical admission and
    # render successfully when only the bounds expand by one Float64 ULP.
    control_support = (prevfloat(Float64(support[1])), nextfloat(Float64(support[2])))
    control = bat_makie_plot(source, recipes, [1], 1;
        support=[control_support], display=false)
    control_size = try
        size(Makie.colorbuffer(control))
    finally
        empty!(control)
    end
    error_message = isnothing(failure) ? nothing :
        last(split(sprint(showerror, failure), '\n'))
    @show (all_observations_inside_original_support=true,
        converted_support=Float64.(support), error_message, control_size)

    # Valid boundary observations must not become outside-support observations
    # solely because the renderer needs Float64 endpoints.
    @test isnothing(failure)
end

kde_support_rounding()

Skip exactly zero-weight mean contributions before multiplying nonfinite log
densities. Admit finite, nonvanishing subnormal MCMC score moments while
preserving strict parameter and weight checks and failure atomicity.

Review: #514 (comment)

Both reviewer reproducers and 81,930 assertions across seven selected
statistics/sampler test files pass on Julia 1.13.2 and 1.10.12.
Include statistics visibility in graph dependencies and activate statistics
only for a directly selected recipe or a visible overlay. Preserve numerical
checks for requested statistics and cover static and live update paths.

Addresses PR #514, R1-02:
#514 (comment)

Validation: 1,512 assertions pass on each of Julia 1.13.2 and 1.10.12.
Stream observations and enroll cancellation independently of output storage.
Preserve outputs=nothing when stabilization samples are discarded.

Addresses PR #514 R1-03:
#514 (comment)

Validated with the reviewer memory probe on Julia 1.13.2 and 1.10.12,
seven core test files and two headless Makie cases on both pinned lanes.
Add Clear selection so coordinates outside the capped picker can be removed
and replaced. Share checkbox selection updates and lifecycle ownership.

Addresses PR #514 R1-04:
#514 (comment)

Validated with 1,502 focused assertions per pinned Julia/Makie lane, plus
the amended public reproducer and rendered figure checks on both lanes.
Add the canonical Internal API entry required by the strict documentation build.

Review: #514 (comment)
Keep positive counts within native Int limits, retain wider positive cases on 64-bit Julia, and check individual and aggregate count overflow.

Review: #514 (comment)
Use InitFromTarget with the private display RNG when a pushforward source has no direct sampler. Preserve directly sampleable sources and display coordinates, with domain and live sampling parity regressions.

Review: #514 (comment)
Handle zero mass before the uniform-weight marker-size shortcut shared by Scatter2D and ChainScatter2D. Cover direct zero-mass populations and Apply/All transitions through both public plotting paths.

Addresses R2-02: #514 (comment)
Avoid fixed-width rational intermediate overflow in plotting normalization while retaining validation, original-weight cutoff ties and logarithmic normalization. Cover the reviewer example and plotting consumers.

Addresses R2-03: #514 (comment)
Verify the reconstructed covariance in each coordinate’s marginal scale before drawing geometry. Preserve genuine singular populations and cover public overlay admission with the reviewer example.

Addresses R2-04: #514 (comment)
Validate observations against original support before converting validated
bounds and coordinates to Float64 for numerical grid construction.
Preserve explicit and inferred support precision through graph setup.

Review: #514 (comment)

@BJMCox BJMCox left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked bd2a6b0. All eleven findings from the 26 October reviews are addressed. The covariance fix now explicitly rejects inaccurate ellipses.

Local Julia 1.13.3 validation passed 105,935 core checks and 828 focused Makie assertions. Plotting checks used CairoMakie.

The remaining x86 statistics failure has four failed assertions and two errors. The inline comments identify three test expectations and one range-construction problem. These predate the latest fix batch.

Comment thread test/plotting/test_histogram_weights.jl Resolved
Comment thread test/plotting/test_binned_moments.jl Resolved
Comment thread test/plotting/test_histogram_regions.jl Resolved
Comment thread src/plotting/MarginalDist.jl Resolved

@BJMCox BJMCox left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remaining coverage suggestion is attached separately to the optional Makie job.

Comment thread .github/workflows/CI.yml Resolved
@Micki-D

Micki-D commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator Author

Apart from the new visualization functionality, several sites in the core package have been altered in the course of the live visualization changes and the numerical hardening.
These may arguably be split into their own PR, or go beyond the scope of this project.

Here is a list of these debatable changes.

At e32f5030, all 44 [PR checks](https://github.com/bat/BAT.jl/pull/514/checks) pass. Focused regression diffs cover reweighting, KS comparisons, tuner lifecycles, histogram/interval arithmetic, and successful-run sampler parity.

  1. Shared weight arithmetic — weight utilities and histogram normalization. Normalize relative weights before unsafe summation, preserve absolute-count semantics, and validate representability. Justification: finite weights can have an overflowing sum even when their relative probabilities are valid. This also fixes filtering/reporting paths. Unsupported counts or lost positive mass now fail explicitly.

  2. Marginal-distribution construction — bin edges and cached moments. Add safe automatic-edge fallback and validate the binned dependency's normalization and cached moments. Justification: unresolved bins can cause excessive edge construction; coordinate arithmetic can produce incorrect means/covariances. Review the conservative rejection policy and additional construction overhead; some mathematically valid inputs are rejected at numerical limits.

  3. Histogram regions and legacy Plots behavior — region calculations, 1D rendering, 2D rendering and overlays. Separate density ranking from integrated bin mass, include threshold ties, preserve original bin geometry, and calculate contour thresholds from the displayed field. Bound smoothing resources and compute only requested overlays. Justification: unequal bins, ties and smoothing could misrepresent probability content. Region boundaries, labels and accepted smoothing requests intentionally change.

  4. Sample-based credible intervals — sample adapter. Pass original masses into the existing exact-arithmetic algorithm and remove zero-weight observations. Justification: constructing a weight wrapper first could overflow before that algorithm ran; zero-mass coordinates should not affect intervals. The estimator itself is retained.

  5. Weighted KS comparisons — ksstats / bat_compare. Process complete coordinate ties, use each population's own length, preserve coordinate comparisons, and validate weight/count arithmetic. Justification: identical singleton populations could yield distance 1 instead of 0, and unequal population lengths were reported incorrectly. Corrected p-values and stricter count validation are observable changes; the asymptotic reference distribution is retained.

  6. Online statistics and reweighting — univariate, multivariate and MCMC statistics. Correct first-moment/squared-weight scaling and zero-factor resets; validate components before mutation. Justification: previous scaling changed means incorrectly and corrupted variance correction/reset state. Checked scaling requires parameter moments and weight accumulators to remain normal or zero; auxiliary log-density moments may remain subnormal. Zero-weight rows are excluded from moment accumulation but still affect diagnostics. Adaptation results can change.

  7. Stan-like and composite tuning — Stan-like tuner and MultiTrafo storage. Validate adaptation windows, avoid integer overflow/non-advancing schedules, clear statistics on explicit initialization, and validate covariance factors. Permit replacement component-tuner types. Justification: prevents hangs, stale-window contamination and storage-type failures. Review changed reset behavior and rejection of invalid configurations/geometries.

  8. MCMC proposal-buffer initialization — chain state. Copy corresponding current buffers when constructing proposal buffers. Justification: preserves concrete sample-storage types and independent writable storage across supported nested, matrix and view-backed representations. Regression tests cover MH/HMC initialization and subsequent sampling.

  9. MCMC worker cleanup — multi-chain iteration. Strengthen cancellation and joining after sampling-owner failures, including partial worker launch and repeated interrupts. Justification: cleanup must retain responsibility for all launched workers and preserve the primary exception. This also affects sampling without visualization. Review exception propagation and cooperative shutdown; an in-progress numerical step or user hook must finish before its worker can stop.

  10. Generic density errors and differentiation — density evaluation. Allow EvalException to retain generic densities, support general variates in diagnostics, and make Zygote shape preflight conditional on available metadata. Justification: error reporting could mask the original failure, and valid densities without shape metadata could fail differentiation. Applicable metadata errors still propagate.

  11. Small configuration/diagnostic corrections — set_batcontext rejects unknown keywords instead of silently discarding them; parameter-name diagnostics no longer reference an undefined variable. Justification: makes invalid configuration and lookup failures explicit. Keyword rejection is intentionally stricter behavior.

  12. Binned-sampling dependency floor — Project.toml raises the minimum supported EmpiricalDistributions 0.3-series version from 0.3.4 to 0.3.9. Justification: obtains the explicit-RNG correction for binned sampling. Previously affected seeded sequences can change; regression tests exercise explicit RNG ownership through BAT's sampling API.

Make the extracted core-fixes branch an ancestor so PR #514 can review visualization changes against it. Preserve the existing Makie implementation and bring in the verified marginal-domain and uniform-filter corrections.
@BJMCox
BJMCox changed the base branch from main to makie-core-fixes October 30, 2026 11:39
@BJMCox

BJMCox commented Oct 30, 2026

Copy link
Copy Markdown
Member

I’ve moved the shared core changes into makie-core-fixes and retargeted this PR to that branch. I merged the core branch into makie_recipies, preserving the existing commit history.

The core branch contains the statistical and numerical fixes, density/AD changes, transform execution, and nonvisual sampler cleanup. These affect BAT without Makie, so the split lets us review them separately from the visualization APIs and live-display hooks.

I also fixed two issues there:

Both full suites passed locally on Julia 1.13.3: 105,636 checks for the core branch and 105,946 for this PR. The 451 Plots checks, four selected Makie cases, and native interruption checks also passed.

This branch has not been deployed

No deployments
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.

3 participants