Skip to content
This repository was archived by the owner on May 21, 2024. It is now read-only.
This repository was archived by the owner on May 21, 2024. It is now read-only.

More flexible plotting #80

@alexpearce

Description

@alexpearce

Plotting fits is very nice right now, as long as you're happy using something like BinnedLH.draw. If you want to go beyond that, things start to become painful.

This begins when you want want to modify the .draw methods in any way, like changing line colours, as you need to copy-paste to format of the returned tuple:

likelihood = minuit.fcn
(
    (data_edges, data_y),
    (errorp,errorm),
    (total_pdf_x, total_pdf_y),
    parts
) = likelihood.draw(minuit, parts=True, no_plot=True)

Things get considerably worse when you have components PDFs which themselves have components. Consider:

import matplotlib.pyplot as plt
import probfit

bounds = (0, 10)

sig_pdf1 = probfit.rename(probfit.pdf.gaussian, ('x', 'mu', 'sigma1'))
sig_pdf2 = probfit.rename(probfit.pdf.gaussian, ('x', 'mu', 'sigma2'))
sig_pdf = probfit.AddPdfNorm(sig_pdf1, sig_pdf2, facname=['f0'])
sig_pdf = probfit.Extended(probfit.Normalized(sig_pdf, bounds), extname='Nsig')

bkg_pdf = probfit.rename(probfit.pdf.linear, ('x', 'm', 'c'))
bkg_pdf = probfit.Extended(probfit.Normalized(bkg_pdf, bounds), extname='Nbkg')

tot_pdf = probfit.AddPdf(sig_pdf, bkg_pdf)

# In the order of probfit.describe(tot_pdf)
# Would normally get these values from Minuit after the fit
initial_values = (5, 1, 0.3, 0.5, 10, 0.5, 1, 10)
probfit.plotting.draw_pdf(tot_pdf, initial_values, bounds, label='Total PDF')
probfit.plotting.draw_pdf(tot_pdf.parts()[0], initial_values, bounds, label='Signal PDF')
probfit.plotting.draw_pdf(tot_pdf.parts()[1], initial_values, bounds, label='Background PDF')
plt.legend();

Gives you this:

Pretty.

But what if I also want to visualise the components of sig_pdf, i.e. the two Gaussians? I think this is a common requirement. (Bonus: this is without data; things get more complicated then.)

Right now, I don't think there's a way to access either of the two components of sig_pdf from the total PDF object. This is because AddPdf turns its components into MinimalFuncCode object and FakeFunc objects (which admittedly I don't really understand), and these don't expose any sub-PDFs.

>>> type(tot_pdf.func_code)
probfit.funcutil.MinimalFuncCode
>>> tot_pdf.parts()
[<probfit.funcutil.FakeFunc at 0x7f371c159b40>,
 <probfit.funcutil.FakeFunc at 0x7f371c159a68>]
>>> tot_pdf.parts()[0].parts()
...
AttributeError: 'probfit.funcutil.FakeFunc' object has no attribute 'parts'

Similar issues exist with the residual plotting methods, but there I'd argue it's actually harder to customise those.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions