hist
hist copied to clipboard
Make it easier to plot ratio of multiple histograms [FEATURE]
In:
import matplotlib.pyplot as plt
import numpy
from hist import Hist
#------------------------------------------------------
def get_hist():
h = (
Hist.new
.Reg(10, -2 ,2, name='x', label='x-axis')
.Int64()
)
data=numpy.random.normal(size=10000)
h.fill(data)
return h
#------------------------------------------------------
def main():
h_1 = get_hist()
h_2 = get_hist()
h_3 = get_hist()
fig, (ax, rax) = plt.subplots(nrows=2, gridspec_kw={"height_ratios": (3, 1)})
axs = {"main_ax": ax, "ratio_ax": rax}
h_2.plot_ratio(h_1,
rp_ylabel ='Ratio',
rp_num_label ='data',
rp_denom_label ='sim 1',
rp_uncert_draw_type='bar',
ax_dict = axs,
)
h_3.plot_ratio(h_1,
rp_ylabel ='Ratio',
rp_num_label ='data',
rp_denom_label ='sim 2',
rp_uncert_draw_type='bar',
ax_dict = axs,
)
plt.show()
#------------------------------------------------------
if __name__ == '__main__':
main()
The code is unable to:
- Plot the ratio of data to both simulations and there is no easy way to make this work. I see repeated histograms.
- The axes are not aligned by default
- I do not see documentation (or at least it is not easy to find) fr the
rp_*
arguments.
Describe the feature you'd like
The user should be able to do:
h_1 = get_hist()
h_2 = get_hist()
h_3 = get_hist()
h_1.plot_ratio([h_2, h_3])
plt.show()
and we should get two figures, upper one with h_*
overlaid. Lower with two ratios, to h_2 and h_3. The axes should be aligned, the labels and legends should be taken from the histograms themselves and we should not have to do any manipulation of artists.
Describe alternatives, if any, you've considered
The way the code is implemented is bad, it's too complicated, and I do not have time to make it work the way I need to, so I am moving back to pure matplotlib. The plots I need do not need to be perfect and matplotlib is good enough for me. It would be nice if hist can do quickly what we need though.
Cheers.
Hi! Has there been any progress on this issue? I would also really appreciate a function that allows for ratio plots with more than two input histograms. I think the two problems labelled above as 1. and 2. are the main ones.
- In the above example,
h1
is plotted twice on the upper panel. - The axes are not "fused", meaning that there is empty space between the panel. The x-axis of the upper panel should ideally vanish and the lower end of the upper panel should be glued on top of the lower panel just as in https://hist.readthedocs.io/en/latest/user-guide/notebooks/Plots.html#Via-Plot-Ratio.
The user can actually manually solve 2. by specifying sharex=True
and plt.subplots_adjust(hspace=.0)
in their script. In my opinio, this should not be added to _plot_ratiolike
in src/hist/plot.py
so that users have more control over the spacing (if they desire to have non-standard spacing).
I think if one does not give axes to the first plot_ratio
, they are created first and fused correctly and this unwanted behaviour occurs when one always gives axes to plot_ratio
since they are just extracted from the dict in https://github.com/scikit-hep/hist/blob/cdfc4c3669af10515f2a9ec75835ccc608927dcf/src/hist/plot.py#L558 without further modifications.
There is one complication when using this solution to 2.: The ticks of the upper and the lower limit can overlap, which does not look too nice. The user can prune the ticks using something like ax2.yaxis.set_major_locator(MaxNLocator(nbins=nbins, prune='upper'))
with matplotlib.ticker.MaxNLocator
where nbins = len(ax1.get_xticklabels())
but of course this is some manual hassle again, sadly.
I see two options to solve problem 1, which would enter at https://github.com/scikit-hep/hist/blob/cdfc4c3669af10515f2a9ec75835ccc608927dcf/src/hist/plot.py#L654 (because I assume everybody wants to plot ratios with a common denominator...)
- Check if more than one "lines" object is on the upper panel already and if yes, do not histplot the denominator.
- Add an additional argument (boolean flag) and give control to the user if the denominator should be histplotted, defaulting to True. I am reluctant to directly propose any particular implementation to solve 1. but if you have a preference I could try myself.
Moving plot_ratio
to mplhep
might also be an option but I do not know if this is preferred long-term...?
Overall, development in this area would probably be really appreciated by the community because it would be so great to have an easy-to-use interface for flexible ratio plots!