-
Notifications
You must be signed in to change notification settings - Fork 25
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
Allow for irregular bin widths in hist.plot.plot_pull_array
#369
base: main
Are you sure you want to change the base?
Allow for irregular bin widths in hist.plot.plot_pull_array
#369
Conversation
Assuming the axis has an `edges` attribute, I assume it should also have a `widths` attribute, so I thought we can just use that for the pull bar widths instead of calculating our own assuming a regular spacing (which might not be true). For the patch-width, we just use `right_edge - left_edge`, instead of what was done before, which dividing this difference by the number of pulls and then multiplying them again with the same number.
Now I looked at the file again and Line 428 in 06a4859
I didn't use that function and am not sure how it's used and if possibly the ratio doesn't make sense with irregular binnings 🤷 But if you say it's safe I might also change that. I noticed that when I saw the |
CC @matthewfeickert, IIRC, on that one? |
I'll try to take a look at this before EOD on Monday. |
Thanks. Before merging I would also update the changelog, I was just waiting for feedback to my above comment, depending on which I might add further changes. |
That's what I'm waiting on feedback for, @matthewfeickert added it, IIRC. I think the answer is yes, that these were both added without realizing that axes had edges and such. Even if the calculation doesn't handle irregular bin widths, I still think it's not "wrong" to use the correct edges attributes to compute it (it would just need a check and error in that case). |
I'll be trying to get a release out today, FYI. |
Once I'm out of my meeting I'll go through this before lunch. |
Thanks for the PR @meliache and sorry for letting it get buried in notifications.
Yeah, I think that's fine. In PR #161 I was indeed making the assumption that the bin widths are constant.
Nothing should explicitly depend on this, so I would agree that this can be propagated everywhere. Beyond using the suggested behavior of your PR everywhere, can you also add a test that uses irregular binning?
@henryiii As I was slow and it is already evening for @meliache I doubt this would be ready to go into a new release today (I have other work that I need to get done before this afternoon as well). I can help @meliache with finishing this tonight or tomorrow if they'd like it, so given the "Hist Serialization and Interactivity" fellow project that you're going to be mentoring will probably have some new releases coming out soon what do you think about getting this PR into a following release, so that I don't slow you down here? |
Following release would be fine. Maybe even this one, since scikit-hep/boost-histogram#708 is a serious regression and hist will have to wait till after bh gets fixed. 😞 |
Ah very sorry to hear it. :( Hopefully, while serious, it isn't too much of a pain to patch. But sounds good RE: either this release or the next. @meliache I like your plan, and if you'd like me to help add contributions if you're currently busy I'm happy to do so given that I delayed you here. Of course I'm happy to answer any questions you have and let you finish this one off yourself. 👍 |
Thanks for considering my time zone, evening is good as I don't have any meeting or other work to do, so I can add a couple of things like adapting
Good idea, a test would make me more comfortable merging this. The question is what to test. I would assume
I just took a look at your tests directory, probably it should go into |
You can use |
I just realized that Update: Untested hotfix in 37b6d3d |
Necessary when doing pull plots for histograms with an axis of type `hist.axis.Variable` with varying bin widths.
Co-authored-by: Henry Schreiner <[email protected]>
$ docker run --rm -v$PWD:/hist -w/hist -it quay.io/pypa/manylinux2014_x86_64
# pipx run nox -s regenerate It's easier to compare online, so I'm just pushing the result. |
(Sorry for the delay pushing, got nerd-sniped) Looks like this messes with the scaling - should this be normalized by the total width? |
Upps, I think I messed this up in 37b6d3d. I didn't test that and somehow assumed that it should be right at that time. Now I think it should work if I replace the h_values_width_corrected = histogram.values() / (bin_widths / np.mean(bin_widths)) In that case, in case of a regular binning, the hist values remain unchanged, but if a bin is e.g. twice the mean bin width, the value will be divided by half. Instead of Anyway, my local tests now fail again, but I think this is because you changed the baseline. Can I just revert that commit when I think I have fixed it? In case your rushing to review this PR to get it into the new release, I'm not sure I can propagate this all the way up, since this affects more functions that I expected (at least if we want to allow variable axes in general) and I'm still not sure how to best tackle the tests and getting good coverage might need some time for me (though I'd be glad if @matthewfeickert could help with that). Update: I see you already suggested a fix, thanks. And by the way, my mind was blown when I saw that github has image diffs. |
Co-authored-by: Henry Schreiner <[email protected]>
...eventually making my way back to this after getting some other reviews done. It looks like tests are currently passing (:+1:) but
I can help add some example tests to cover the cases of irregular binning. I think(?) that |
Sure, I'd be okay with Codecov. Is that the one that adds a comment to every PR? :/ |
Yeah. It updates it in place each time there is a coverage change. c.f. scikit-hep/pyhf#1809 (comment) Not sure if that's desirable or not in your mind. |
That's mildly annoying but not terrible. Though I'm guessing there's a way to avoid it: pypa/build#443 for example. |
To be honest I also got busy with other things, sorry for not replying this week earlier, but I could revisit the tests.
Thanks a lot. I think I got overwhelmed by open questions how exactly to do the tests. E.g. should I include asserts in with variable binnings into the existing test functions or create new test functions? What should I best do to avoid code duplication, because necessarily I will basically repeat existing tests with non-regular binnigngs? How fine-grained should the tests be? Should I just test non-crashing behaviour or also generate example images and if yes, I'm not sure what the best procedure is for that. But as always don't let perfection be the enemy of the good |
…egular-pull-widths
I add 2 tests - `test_image_plot_ratio_variable_axis_with_regular_bins`: Same as `test_image_plot_ratio_callable`, but use an `axis.Variable`, but set the bin edges to be regular, same as former test with `axis.Regular`. With this I just check that the plot doesn't depend on the axis type. For this we re-use the existing baseline plot. - `test_image_plot_ratio_callable_bayesian_blocks_bins`: Actually try the ratio plot with variable bin widths. For this I ran the bayesian blocks algorithm on 5000 random numbers. I used that instead of 1000 numbers because for 1000 the binning seemed very coarse for me and the fit plots just looked like a triangle. For this we create a new baseline plot. Also I added a helper function to create these `plot_ratio_callable` test for different axes/binnings in order to avoid code duplication. TODO: The baseline plots for `test_image_plot_ratio_callable_bayesian_blocks_bins` looks like something is off, the centre pull is much larger than the pull errorbars. I have to check that the bin widths are correctly taken into account in the errorbars and ratios.
I just add two tests:
Also I added a helper function to create these
|
Most tests use `np.random.seed(42)` to re-seed the global RNG. Initially I didn't follow this in my tests, because according to its documentation it is not best-practice and a legacy function. > The best practice is to not reseed a BitGenerator, rather to recreate a new > one. This method is here for legacy reasons. Instead, I created a custom RNG with a seed and used that to generate my random numbers. However, the tests failed and I noticed that the random seed not only affects the numbers to fill the histogram with, but also the fit, which I can't affect via a custom RNG, so I have to re-seed the global RNG. Therefore, I fall back to using `np.random.normal`.
Also update baseline with fix
Now I have arrived where I'm personally happy in this PR, I think I propagated my change up so that irregular bin widths should work for Coding-style wise I noticed that I now often repeat the same 2 to 3 lines to normalize the histogram values to the mean bin width. I think this could be factored out into a private helper function but for just 2 lines this doesn't really seam worth it, so I'm not sure. I'll leave it like it's now, except you think it's better to write a function for it. |
Thanks. I'll take a look at this tonight after I've finished Snowmass papers. But CI is passing and there are tests now, so my guess is that things are probably 👍. |
@@ -672,7 +690,7 @@ def _plot_ratiolike( | |||
|
|||
elif view == "pull": | |||
pulls: np.typing.NDArray[Any] = ( | |||
hist_values - compare_values | |||
hist_values_width_corrected - compare_values | |||
) / hist_values_uncert |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, hist_values_uncert
seems unbound if other
is not a callable or string but a histogram. This is not something I introduced in this PR so if I'm not mistaken this might warrant a separate issue.
The question would be whether we just want to use np.sqrt(self.variances())
or in case other
also has variances, if we want to statistically combine both somehow 🤷♂️
Assuming the axis has an
edges
attribute, I assume it should also have awidths
attribute, so I thought we can just use that for the pull bar widths instead of calculating our own assuming a regular spacing (which might not be true).For the patch-width, we just use
right_edge - left_edge
, instead of what was done before, which dividing this difference by the number of pulls and then multiplying them again with the same number.From git-blame it looks like @matthewfeickert had written the original function so I might mention him.
I should also mention I'm not using this function, I just looked at it because I was writing my own pull plot function and was considering adapting the code for the rectangular patches and then just wondered why
hist.axes[0].widths
isn't used. Thus, it would be good if this could be tested properly.ratio_plot
with variable binning are larger than their errorbars and fix this (see this plot)