Source code for gammapy.irf.rad_max
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import astropy.units as u
from astropy.visualization import quantity_support
import matplotlib.pyplot as plt
from matplotlib.ticker import FormatStrFormatter
from gammapy.maps.axes import UNIT_STRING_FORMAT
from .core import IRF
__all__ = [
"RadMax2D",
]
[docs]
class RadMax2D(IRF):
"""2D Rad Max table.
This is not directly a IRF component but is needed as additional information
for point-like IRF components when an energy or field of view
dependent directional cut has been applied.
Data format specification: :ref:`gadf:rad_max_2d`.
Parameters
----------
axes : list of `~gammapy.maps.MapAxis` or `~gammapy.maps.MapAxes`
Required axes (in the given order) are:
* energy (reconstructed energy axis)
* offset (field of view offset axis)
data : `~astropy.units.Quantity`
Applied directional cut.
meta : dict
Metadata dictionary.
"""
tag = "rad_max_2d"
required_axes = ["energy", "offset"]
default_unit = u.deg
[docs]
@classmethod
def from_irf(cls, irf):
"""Create a RadMax2D instance from another IRF component.
This reads the RAD_MAX metadata keyword from the IRF and creates
a RadMax2D with a single bin in energy and offset using the
ranges from the input IRF.
Parameters
----------
irf : `~gammapy.irf.EffectiveAreaTable2D` or `~gammapy.irf.EnergyDispersion2D`
IRF instance from which to read the RAD_MAX and limit information.
Returns
-------
rad_max : `RadMax2D`
`RadMax2D` object with a single bin corresponding to the fixed
RAD_MAX cut.
Notes
-----
This assumes the true energy axis limits are also valid for the
reconstructed energy limits.
"""
if not irf.is_pointlike:
raise ValueError("RadMax2D.from_irf requires a point-like irf")
if "RAD_MAX" not in irf.meta:
raise ValueError("Irf does not contain RAD_MAX keyword")
rad_max_value = irf.meta["RAD_MAX"]
if not isinstance(rad_max_value, float):
raise ValueError(
f"RAD_MAX must be a float, got '{type(rad_max_value)}' instead"
)
energy_axis = irf.axes["energy_true"].copy(name="energy").squash()
offset_axis = irf.axes["offset"].squash()
return cls(
data=rad_max_value,
axes=[energy_axis, offset_axis],
unit="deg",
interp_kwargs={"method": "nearest", "fill_value": None},
)
[docs]
def plot_rad_max_vs_energy(self, ax=None, **kwargs):
"""Plot rad max value against energy.
Parameters
----------
ax : `~matplotlib.pyplot.Axes`, optional
Matplotlib axes. Default is None.
**kwargs : dict
Keyword arguments passed to `~matplotlib.pyplot.pcolormesh`.
Returns
-------
ax : `~matplotlib.pyplot.Axes`
Matplotlib axes.
"""
if ax is None:
ax = plt.gca()
energy_axis = self.axes["energy"]
offset_axis = self.axes["offset"]
with quantity_support():
for value in offset_axis.center:
rad_max = self.evaluate(offset=value)
label = f"Offset {value:.2f}"
kwargs.setdefault("label", label)
ax.plot(energy_axis.center, rad_max, **kwargs)
energy_axis.format_plot_xaxis(ax=ax)
ax.set_ylim(0 * u.deg, None)
ax.legend(loc="best")
ax.set_ylabel(f"Rad max. [{ax.yaxis.units.to_string(UNIT_STRING_FORMAT)}]")
ax.yaxis.set_major_formatter(FormatStrFormatter("%.2f"))
return ax
@property
def is_fixed_rad_max(self):
"""Return True if rad_max axes are flat."""
return self.axes.is_flat