Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add more flexibility to visualize.pulls #342

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

andrzejnovak
Copy link
Member

  • feat: show unconstrained directly in pulls, add exclude_by_type
  • fix: leave redundant styling to style sheets
  • fix: pull display order
  • feat: add pull(exclude=... fnmatch, fix docs

@andrzejnovak andrzejnovak changed the title pulls feat: add more flexibility to visualize.pulls Jun 9, 2022
@andrzejnovak andrzejnovak force-pushed the pulls branch 3 times, most recently from ee35ef3 to d91baf0 Compare June 9, 2022 12:12
@codecov
Copy link

codecov bot commented Jun 9, 2022

Codecov Report

Merging #342 (fc3d344) into master (fce7208) will decrease coverage by 0.47%.
The diff coverage is 82.00%.

❗ Current head fc3d344 differs from pull request most recent head f5bd953. Consider uploading reports for the commit f5bd953 to get more accurate results

@@             Coverage Diff             @@
##            master     #342      +/-   ##
===========================================
- Coverage   100.00%   99.52%   -0.48%     
===========================================
  Files           23       23              
  Lines         1878     1911      +33     
  Branches       299      311      +12     
===========================================
+ Hits          1878     1902      +24     
- Misses           0        4       +4     
- Partials         0        5       +5     
Impacted Files Coverage Δ
src/cabinetry/visualize/plot_result.py 95.94% <60.00%> (-4.06%) ⬇️
src/cabinetry/visualize/utils.py 90.90% <82.35%> (-9.10%) ⬇️
src/cabinetry/fit/__init__.py 100.00% <100.00%> (ø)
src/cabinetry/fit/results_containers.py 100.00% <100.00%> (ø)
src/cabinetry/model_utils.py 100.00% <100.00%> (ø)
src/cabinetry/visualize/__init__.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fce7208...f5bd953. Read the comment docs.

@andrzejnovak
Copy link
Member Author

@alexander-held ready for review

@alexander-held alexander-held self-requested a review June 9, 2022 17:22
Comment on lines +524 to +527
labels = model.config.par_names()
_mod_dict = dict(model.config.modifiers)
_clean_labels = [re.sub(r"\[.*\]", "", label) for label in labels]
types = [_mod_dict[n] if n in _mod_dict else None for n in _clean_labels]
Copy link
Member

Choose a reason for hiding this comment

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

I am wondering whether we should extract and save the information about the constraint term (none, Gaussian, Poisson) instead of the modifier types. The problem with the types is that a parameter may control multiple modifiers (e.g. a normsys plus a shapesys). For the purpose of plotting pulls, the constraint term type is all that is needed to decide the handling.

We could get the constraint term types like this:

constraint_terms = []
for parameter in model.config.par_order:
    if not model.config.param_set(parameter).constrained:
        # normfactor / shapefactor
        constraint_terms += [None] * model.config.param_set(parameter).n_parameters
    else:
        # remaining modifiers with Gaussian or Poisson constraints
        constraint_terms += [
            model.config.param_set("staterror_Signal_region").pdf_type
        ] * model.config.param_set("staterror_Signal_region").n_parameters

Going one step further, we could also save the .width() information to evaluate constraints for Poisson-constrained parameters (since the pre-fit uncertainty for those varies per parameter).

For other use cases (like #332) it might be useful to also know all the modifier types.

While it is currently possible to determine the constraint term type from knowing the modifier, that will change when constraint terms become configurable in the future with pyhf. So perhaps it is best to store constraint term information directly, and optionally add another field in the future to also keep track of the modifier types?

Copy link
Member

Choose a reason for hiding this comment

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

I am remembering now where the idea of storing the modifier types come from: that allows to exclude by type in the plot, like excluding staterror. The constraint term type does not help there. It seems more likely that users would want to exclude by modifier type than by constraint term type, so perhaps it is best to stick with the implemented approach. The only thing that would need to be generalized is matching multiple modifier types.

Copy link
Member

Choose a reason for hiding this comment

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

Something like the following could help simplify things by using more of the pyhf API:

modifier_types = []
for parameter in model.config.par_order:
    modifier_types += [
        [
            mod_type
            for par_name, mod_type in model.config.modifiers
            if par_name == parameter
        ]
    ] * model.config.param_set(parameter).n_parameters

ax.fill_between([-2, 2], -0.5, len(bestfit) - 0.5, color="yellow")
ax.fill_between([-1, 1], -0.5, len(bestfit) - 0.5, color="limegreen")
ax.vlines(0, -0.5, len(bestfit) - 0.5, linestyles="dotted", color="black")
fig, ax = plt.subplots()
Copy link
Member

Choose a reason for hiding this comment

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

Let's keep the figsize=(6, 1 + num_pars / 4) scaling unless there's a strong reason not to, as that allows the spacing in the plot to be fairly consistent across a wide range of numbers of parameters.

Comment on lines -106 to -109
ax.xaxis.set_minor_locator(mpl.ticker.AutoMinorLocator()) # minor ticks
ax.tick_params(axis="both", which="major", pad=8)
ax.tick_params(direction="in", top=True, right=True, which="both")
fig.set_tight_layout(True)
Copy link
Member

Choose a reason for hiding this comment

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

I believe this removal is related to making figure customization easier via style sheets? If so, could we split that out into a separate PR? I'd like things to be more easily configurable, but I also do think the minor ticks help with legibility of constraints. Is there a way to move this into a default style sheet that users could override?

mod_type
for par_name, mod_type in model.config.modifiers
if par_name == parameter
][:1]
Copy link
Member Author

Choose a reason for hiding this comment

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

so for some modifiers in the example.py this returns ['histosys', 'normsys'] so then best_fit and types would have different length, it's unclear to me why some parameters have more types?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

A parameter can control multiple modifiers, and in some specific cases a parameter can also control modifiers of different types if they have the same constraint terms. When building models, cabinetry implements systematic uncertainties that change both shape and normalization via two correlated modifiers (normsys and histosys) which are controlled by the same parameter. For pulls to +/- 1 sigma this results in an equivalent model prediction to what a single histosys modifier can provide. The split of overall normalization changes across a channel into a correlated normsys helps protect the model predictions from becoming negative due to the exponential extrapolation used with normsys modifiers (while histosys is linear).

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