312 lines
12 KiB
Python
312 lines
12 KiB
Python
# drm.py: Plot class for responses
|
|
#
|
|
# Authors: William Cleveland (USRA),
|
|
# Adam Goldstein (USRA) and
|
|
# Daniel Kocevski (NASA)
|
|
#
|
|
# Portions of the code are Copyright 2020 William Cleveland and
|
|
# Adam Goldstein, Universities Space Research Association
|
|
# All rights reserved.
|
|
#
|
|
# Written for the Fermi Gamma-ray Burst Monitor (Fermi-GBM)
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
import matplotlib.pyplot as plt
|
|
|
|
from .globals import *
|
|
from .gbmplot import GbmPlot, HeatMap, EffectiveArea
|
|
|
|
|
|
class ResponseMatrix(GbmPlot):
|
|
"""Class for plotting a response matrix.
|
|
|
|
Parameters:
|
|
data (:class:`~gbm.data.RSP`, optional): The response object
|
|
colorbar (bool, optional): If True, plot the colorbar for the
|
|
effective area scale. Default is True.
|
|
multi (bool, optional):
|
|
If True, plots a multiplot window showing the matrix and the integrated
|
|
effective area as a function of incident energy and recorded energy
|
|
num_contours (int, optional): Number of contours to plot. Default is 100
|
|
**kwargs: Options to pass to :class:`~.gbmplot.GbmPlot`
|
|
|
|
|
|
Attributes:
|
|
ax (:class:`matplotlib.axes`): The matplotlib axes object for the plot
|
|
canvas (Canvas Backend object): The plotting canvas, if set upon
|
|
initialization.
|
|
data (:class:`~gbm.plot.gbmplot.HeatMap'): The matrix plot object
|
|
fig (:class:`matplotlib.figure`): The matplotlib figure object
|
|
xlim (float, float): The plotting range of the x axis.
|
|
This attribute can be set.
|
|
xscale (str): The scale of the x axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
ylim (float, float): The plotting range of the y axis.
|
|
This attribute can be set.
|
|
yscale (str): The scale of the y axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
"""
|
|
_background = 'black'
|
|
|
|
def __init__(self, data=None, colorbar=True, multi=False, canvas=None,
|
|
axis=None, num_contours=100, **kwargs):
|
|
|
|
self._drm = None
|
|
self._colorbar = colorbar
|
|
self._multi = multi
|
|
|
|
# do the multiplot
|
|
if multi:
|
|
self._colorbar = False
|
|
axis, ax_x, ax_y = self._init_multiplot()
|
|
self._p = PhotonEffectiveArea(data=data, canvas=canvas, axis=ax_x,
|
|
**kwargs)
|
|
self._c = ChannelEffectiveArea(data=data, canvas=canvas, axis=ax_y,
|
|
orientation='horizontal', **kwargs)
|
|
ax_x.get_xaxis().set_visible(False)
|
|
ax_y.get_yaxis().set_visible(False)
|
|
|
|
super().__init__(canvas=canvas, axis=axis, **kwargs)
|
|
|
|
self._ax.set_facecolor(self._background)
|
|
|
|
# initialize the plot axes, labels, ticks, and scales
|
|
self._ax.set_xlabel('Photon Energy (keV)', fontsize=PLOTFONTSIZE)
|
|
self._ax.set_ylabel('Channel Energy (keV)', fontsize=PLOTFONTSIZE)
|
|
self._ax.xaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.yaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.set_xscale('log')
|
|
self._ax.set_yscale('log')
|
|
|
|
# plot data and/or background if set on init
|
|
if data is not None:
|
|
self.set_response(data, index=0, num_contours=num_contours)
|
|
self._ax.set_xlim(data.photon_bins[0][0], data.photon_bins[1][-1])
|
|
self._ax.set_ylim(data.ebounds['E_MIN'][0],
|
|
data.ebounds['E_MAX'][-1])
|
|
|
|
@property
|
|
def data(self):
|
|
return self._drm
|
|
|
|
def _init_multiplot(self):
|
|
# initialize the multiplot
|
|
|
|
# dimensions
|
|
left, width = 0.12, 0.55
|
|
bottom, height = 0.12, 0.55
|
|
bottom_h = left_h = left + width
|
|
matrix = [left, bottom, width, height]
|
|
histx = [left, bottom_h, width, 0.40]
|
|
histy = [left_h, bottom, 0.40, height]
|
|
|
|
# create the plot axes
|
|
main_ax = plt.axes(matrix)
|
|
ax_x = plt.axes(histx)
|
|
ax_y = plt.axes(histy)
|
|
|
|
return (main_ax, ax_x, ax_y)
|
|
|
|
def set_response(self, data, index=None, atime=None, **kwargs):
|
|
"""Set the response data.
|
|
|
|
Args:
|
|
data (:class:`~gbm.data.RSP`): The response object
|
|
index (int, optional): The index of the DRM to display
|
|
atime (float, optional): The time corresponding to a DRM
|
|
**kwargs: Arguments to pass to :class:`~.gbmplot.HeatMap`
|
|
"""
|
|
if index is not None:
|
|
drm = data.drm(index)
|
|
elif atime is not None:
|
|
drm = data.nearest_drm(atime)
|
|
else:
|
|
drm = data.drm(0)
|
|
self._drm = HeatMap(data.photon_bin_centroids, data.channel_centroids,
|
|
drm.T, self.ax, colorbar=self._colorbar, **kwargs)
|
|
|
|
# update the background color of the colorbar
|
|
if self._colorbar:
|
|
self._drm._artists[-1].patch.set_facecolor(self._background)
|
|
|
|
|
|
class PhotonEffectiveArea(GbmPlot):
|
|
"""Class for plotting the incident photon effective area
|
|
|
|
Parameters:
|
|
data (:class:`~gbm.data.RSP`, optional): The response object
|
|
**kwargs: Options to pass to :class:`~.gbmplot.GbmPlot`
|
|
|
|
|
|
Attributes:
|
|
ax (:class:`matplotlib.axes`): The matplotlib axes object for the plot
|
|
canvas (Canvas Backend object): The plotting canvas, if set upon
|
|
initialization.
|
|
data (:class:`~gbm.plot.gbmplot.EffectiveArea`): The effective area
|
|
plot object
|
|
fig (:class:`matplotlib.figure`): The matplotlib figure object
|
|
xlim (float, float): The plotting range of the x axis.
|
|
This attribute can be set.
|
|
xscale (str): The scale of the x axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
ylim (float, float): The plotting range of the y axis.
|
|
This attribute can be set.
|
|
yscale (str): The scale of the y axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
"""
|
|
|
|
def __init__(self, data=None, canvas=None, axis=None, **kwargs):
|
|
super().__init__(canvas=canvas, axis=axis, **kwargs)
|
|
self._data = None
|
|
|
|
# initialize the plot axes, labels, ticks, and scales
|
|
self._ax.set_xlabel('Photon Energy (keV)', fontsize=PLOTFONTSIZE)
|
|
self._ax.set_ylabel(r'Effective Area (cm$^2$)', fontsize=PLOTFONTSIZE)
|
|
self._ax.xaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.yaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.set_xscale('log')
|
|
self._ax.set_yscale('log')
|
|
|
|
# plot data and/or background if set on init
|
|
if data is not None:
|
|
self.set_response(data, index=0)
|
|
self._ax.set_xlim(data.photon_bins[0][0], data.photon_bins[1][-1])
|
|
|
|
@property
|
|
def data(self):
|
|
return self._data
|
|
|
|
def set_response(self, data, index=None, atime=None, **kwargs):
|
|
"""Set the response data.
|
|
|
|
Args:
|
|
data (:class:`~gbm.data.RSP`): The response object
|
|
index (int, optional): The index of the DRM to display
|
|
atime (float, optional): The time corresponding to a DRM
|
|
**kwargs: Arguments to pass to :class:`~.gbmplot.EffectiveArea`
|
|
"""
|
|
if (index is None) and (atime is None):
|
|
index = 0
|
|
_color, _alpha, _kwargs = self._settings()
|
|
effarea = data.photon_effective_area(index=index, atime=atime)
|
|
self._data = EffectiveArea(effarea, self._ax, color=_color,
|
|
alpha=_alpha, **_kwargs)
|
|
plt.draw()
|
|
|
|
def _settings(self):
|
|
"""The default settings for the plot. If a plot already
|
|
exists, use its settings instead.
|
|
"""
|
|
if self._data is None:
|
|
_color = DATA_COLOR
|
|
_alpha = None
|
|
_kwargs = {}
|
|
else:
|
|
_color = self._data.color
|
|
_alpha = self._data.alpha
|
|
_kwargs = self._data._kwargs
|
|
return (_color, _alpha, _kwargs)
|
|
|
|
|
|
class ChannelEffectiveArea(GbmPlot):
|
|
"""Class for plotting the recorded channel energy effective area.
|
|
|
|
Parameters:
|
|
data (:class:`~gbm.data.RSP`, optional): The response object
|
|
**kwargs: Options to pass to :class:`~.gbmplot.GbmPlot`
|
|
|
|
|
|
Attributes:
|
|
ax (:class:`matplotlib.axes`): The matplotlib axes object for the plot
|
|
canvas (Canvas Backend object): The plotting canvas, if set upon
|
|
initialization.
|
|
data (:class:`~gbm.plot.gbmplot.EffectiveArea`): The effective area
|
|
plot object
|
|
fig (:class:`matplotlib.figure`): The matplotlib figure object
|
|
xlim (float, float): The plotting range of the x axis.
|
|
This attribute can be set.
|
|
xscale (str): The scale of the x axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
ylim (float, float): The plotting range of the y axis.
|
|
This attribute can be set.
|
|
yscale (str): The scale of the y axis, either 'linear' or 'log'.
|
|
This attribute can be set.
|
|
"""
|
|
|
|
def __init__(self, data=None, canvas=None, axis=None,
|
|
orientation='vertical',
|
|
**kwargs):
|
|
super().__init__(canvas=canvas, axis=axis, **kwargs)
|
|
self._data = None
|
|
self._orientation = orientation
|
|
|
|
# initialize the plot axes, labels, ticks, and scales
|
|
if self._orientation == 'horizontal':
|
|
self._ax.set_ylabel('Channel Energy (keV)', fontsize=PLOTFONTSIZE)
|
|
self._ax.set_xlabel(r'Effective Area (cm$^2$)',
|
|
fontsize=PLOTFONTSIZE)
|
|
else:
|
|
self._ax.set_xlabel('Channel Energy (keV)', fontsize=PLOTFONTSIZE)
|
|
self._ax.set_ylabel(r'Effective Area (cm$^2$)',
|
|
fontsize=PLOTFONTSIZE)
|
|
self._ax.xaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.yaxis.set_tick_params(labelsize=PLOTFONTSIZE)
|
|
self._ax.set_xscale('log')
|
|
self._ax.set_yscale('log')
|
|
|
|
# plot data and/or background if set on init
|
|
if data is not None:
|
|
self.set_response(data, index=0)
|
|
xrange = (data.ebounds['E_MIN'][0], data.ebounds['E_MAX'][-1])
|
|
if self._orientation == 'horizontal':
|
|
self._ax.set_ylim(xrange)
|
|
else:
|
|
self._ax.set_xlim(xrange)
|
|
|
|
@property
|
|
def data(self):
|
|
return self._data
|
|
|
|
def set_response(self, data, index=None, atime=None, **kwargs):
|
|
"""Set the response data.
|
|
|
|
Args:
|
|
data (:class:`~gbm.data.RSP`): The response object
|
|
index (int, optional): The index of the DRM to display
|
|
atime (float, optional): The time corresponding to a DRM
|
|
**kwargs: Arguments to pass to :class:`~.gbmplot.EffectiveArea`
|
|
"""
|
|
if (index is None) and (atime is None):
|
|
index = 0
|
|
_color, _alpha, _kwargs = self._settings()
|
|
effarea = data.photon_effective_area(index=index, atime=atime)
|
|
self._data = EffectiveArea(effarea, self._ax, color=_color,
|
|
alpha=_alpha, orientation=self._orientation,
|
|
**_kwargs)
|
|
|
|
def _settings(self):
|
|
"""The default settings for the plot. If a plor already
|
|
exists, use its settings instead.
|
|
"""
|
|
if self._data is None:
|
|
_color = DATA_COLOR
|
|
_alpha = None
|
|
_kwargs = {}
|
|
else:
|
|
_color = self._data.color
|
|
_alpha = self._data.alpha
|
|
_kwargs = self._data._kwargs
|
|
return (_color, _alpha, _kwargs)
|