Пример #1
0
class ROISignificance(ROIMapPlotter):
    """ Make a plot of the poisson significance for the observed
        counts within a circual aperature of radius . """

    defaults = ROIMapPlotter.defaults + (
        ('kernel_rad', 0.25, 'Sum counts/model within radius degrees.'),
        ('conv_type', -1, 'Conversion type'),
    )
    defaults = keyword_options.change_defaults(defaults, 'title',
                                               'Poisson Significance')

    def create_pyfits(self):

        # Fit many pixels inside of the summing radius
        pixelsize = self.kernel_rad / 10.0

        kwargs = dict(size=self.size,
                      pixelsize=pixelsize,
                      galactic=self.galactic,
                      conv_type=self.conv_type,
                      kerneltype='tophat',
                      kernel_rad=self.kernel_rad)

        counts = SmoothedCounts(self.roi, **kwargs)
        model = SmoothedModel(self.roi, **kwargs)

        pyfits = counts.get_pyfits()
        pyfits['PRIMARY'].data = ROISignificance.poisson_sigma(
            counts.image, model.image)

        return pyfits

    @staticmethod
    def poisson_sigma(obs, pred):
        """ Compute the sigma of the detection if you observe 
            a given number (obs) of counts and predict a 
            given number (pred) of counts.

            Note, it is numerically easier to deal with numbers close to 0
            then close to 1, so compute the sigma from the cdf or the sf
            depending upon which is smaller. """
        cdf = poisson.cdf(obs, pred)
        sf = poisson.sf(obs, pred)

        return np.where(cdf < 0.5, norm.ppf(cdf), norm.isf(sf))
Пример #2
0
class ROISmoothedBeforeAfter(object):
    """ Make a 2x1 plot where the left plot
        has the diffuse subtracted and the right plot has the diffuse
        and all sources subtracted.

        This plot is nice for seeing how well the background source
        subtracting is doing. """
    defaults = ROISmoothedSources.defaults

    defaults = keyword_options.change_defaults(defaults, 'figsize', (8, 3.5))
    defaults = keyword_options.change_defaults(defaults, 'title', None)

    @keyword_options.decorate(defaults)
    def __init__(self, roi, **kwargs):

        if kwargs.has_key('show_colorbar') or \
           kwargs.has_key('overlay_psf'):
            raise Exception("This feature doesn't work, for now...")

        keyword_options.process(self, kwargs)

        self.roi = roi

        sources_kwargs = keyword_options.defaults_to_kwargs(
            self, ROISmoothedSources)
        sources_kwargs['show_colorbar'] = False
        self.smoothed_sources = ROISmoothedSources(roi, **sources_kwargs)

        source_kwargs = keyword_options.defaults_to_kwargs(
            self, ROISmoothedSources)
        source_kwargs['overlay_psf'] = False
        self.smoothed_source = ROISmoothedSource(roi, **source_kwargs)

    def show(self, filename=None):

        from mpl_toolkits.axes_grid1.axes_grid import ImageGrid
        import pywcsgrid2

        self.fig = fig = P.figure(self.fignum, self.figsize)
        P.clf()

        header = self.smoothed_source.pf[0].header

        self.grid = grid = ImageGrid(fig, (1, 1, 1),
                                     nrows_ncols=(1, 2),
                                     axes_pad=0.1,
                                     share_all=True,
                                     cbar_mode="single",
                                     cbar_pad="2%",
                                     cbar_location="right",
                                     axes_class=(pywcsgrid2.Axes,
                                                 dict(header=header)))

        def show():
            self.smoothed_sources.show(axes=self.grid[0])
            self.smoothed_source.show(axes=self.grid[1], cax=grid.cbar_axes[0])

        show()

        # use same color scale for each plot
        max_intensity = max(self.smoothed_sources.max_intensity,
                            self.smoothed_source.max_intensity)
        self.smoothed_sources.max_intensity = self.smoothed_source.max_intensity = max_intensity

        show()

        tight_layout(self.fig)

        self.header = self.h = [
            self.smoothed_sources.header, self.smoothed_source.header
        ]

        if filename is not None: P.savefig(filename)
Пример #3
0
class ROISmoothedDataModel(object):
    """ Plot (on the left) the diffuse subtracted smoothed counts and
        (on the right) the diffuse subtrcted smoothed model predicted
        counts. Useful to see if your model (qualitativly) looks like
        the right source. """

    defaults = ROISmoothedSources.defaults
    defaults = keyword_options.change_defaults(defaults, 'figsize', (8, 3.5))
    defaults = keyword_options.change_defaults(defaults, 'title', None)

    @keyword_options.decorate(defaults)
    def __init__(self, roi, **kwargs):
        keyword_options.process(self, kwargs)

        self.roi = roi

        self.cmap = colormaps.b

        # Fit many pixels inside of the summing radius
        self.pixelsize = self.kernel_rad / 5.0

        # Background subtracted counts
        counts_kwargs = keyword_options.defaults_to_kwargs(
            self, ROISmoothedSources)
        counts_kwargs['show_colorbar'] = False
        counts_kwargs['overlay_psf'] = False
        self.counts = ROISmoothedSources(roi, **counts_kwargs)

        # Model counts for non-background sources.
        model_kwargs = keyword_options.defaults_to_kwargs(
            self, ROISmoothedSources)
        model_kwargs['overlay_psf'] = False
        self.model = ROISmoothedModel(roi, **model_kwargs)

    def show(self, filename=None):

        from mpl_toolkits.axes_grid1.axes_grid import ImageGrid
        import pywcsgrid2

        self.fig = fig = P.figure(self.fignum, self.figsize)
        P.clf()

        header = self.counts.pf[0].header

        self.grid = grid = ImageGrid(fig, (1, 1, 1),
                                     nrows_ncols=(1, 2),
                                     axes_pad=0.1,
                                     share_all=True,
                                     cbar_mode="single",
                                     cbar_pad="2%",
                                     cbar_location="right",
                                     axes_class=(pywcsgrid2.Axes,
                                                 dict(header=header)))

        # This is kind of ugly, but use show() once to set the max_intensity, then show again
        # with matching colormaps. Kluge, but in an unimportant function.
        def show():
            self.counts.show(axes=self.grid[0])
            self.model.show(axes=self.grid[1], cax=grid.cbar_axes[0])

        show()

        # Same colorscale kluge as in ROISmoothedBeforeAfter
        max_intensity = max(self.counts.max_intensity,
                            self.model.max_intensity)
        self.counts.max_intensity = self.model.max_intensity = max_intensity
        show()

        self.grid[0].add_inner_title("Counts", loc=2)
        self.grid[1].add_inner_title("Model", loc=2)

        tight_layout(self.fig)

        self.header = self.h = [self.counts.header, self.model.header]

        if filename is not None: P.savefig(filename)
Пример #4
0
class ROISmoothedSources(ROIMapPlotter):
    """ Make a smoothed residual plot which subtracts the diffuse emission. """

    defaults = ROIMapPlotter.defaults + (
        ('which', None, 'Draw the smoothed point version of this source.'),
        ('conv_type', -1, 'Conversion type'),
        ('overlay_psf', True,
         'Add a smoothed reference PSF on top of the counts.'),
        ('label_psf', False, 'Add a label on the PSF box.'),
        ('psf_size', 1, 'Size of the PSF insert box'),
        ('psf_loc', 4, 'Location to put the psf box.'),
        ('kerneltype', 'gaussian', 'Type of kernel to smooth image with'),
        ('kernel_rad', 0.1, 'Sum counts/model within radius degrees.'),
        ('override_center', None, 'Pick a better center'),
        ('cmap', None, 'Show the colorbar'),
        ('colorbar_radius', None,
         """ If specified, calculate the intensity maximum
                                             pixel to be the maximum of all pixels within
                                             this radius. This is useful if you want to clip
                                             out a very bright nearby sources. By default,
                                             this radius will be the source size or the PSF
                                             size (if which!=None). If which==None, the
                                             default is that colorbar_radius=inf.        """
         ),
        ('pixelsize_fraction', 5.0,
         'The pixelsize is kernel_rad/pizelsize_fraction'),
    )

    defaults = keyword_options.change_defaults(defaults, 'title',
                                               'Smoothed Counts Map')

    def get_residual(self, **kwargs):
        """ Allow the particular method for getting the residual image to be overloaded. """

        residual = SmoothedResidual(self.roi,
                                    override_diffuse_sources=[
                                        i for i in self.roi.dsm.diffuse_sources
                                        if not hasattr(i, 'skydir')
                                    ],
                                    **kwargs)

        return residual

    def create_pyfits(self):

        # Fit many pixels inside of the summing radius
        self.pixelsize = self.kernel_rad / self.pixelsize_fraction

        roi = self.roi

        if self.which is not None:
            self.source = roi.get_source(self.which)
            self.center = self.source.skydir
        else:
            self.source = None
            self.center = roi.roi_dir

        if self.override_center is not None: self.center = self.override_center

        self.smoothed_kwargs = dict(size=self.size,
                                    pixelsize=self.pixelsize,
                                    galactic=self.galactic,
                                    conv_type=self.conv_type,
                                    center=self.center,
                                    per_solid_angle=True,
                                    kerneltype=self.kerneltype,
                                    kernel_rad=self.kernel_rad)

        residual = self.get_residual(**self.smoothed_kwargs)

        return residual.get_pyfits()

    def imshow_kwargs(self):
        self.max_intensity = ROISmoothedSources.get_max_intensity(
            self.source,
            self.pf,
            self.roi,
            colorbar_radius=self.colorbar_radius)
        # sanity check
        self.max_intensity = max(self.max_intensity, 1)

        if self.cmap is None:
            self.cmap = colormaps.b

        imshow_kwargs = dict(cmap=self.cmap, vmin=0, vmax=self.max_intensity)
        return imshow_kwargs

    @staticmethod
    def get_max_intensity(source, pyfits, roi, colorbar_radius=None):
        """ Return the maximum value in the pyfits file either 
            within the extended source's size or otherwise
            within the 68% containment radius of the PSF (at
            the lowest energy). """
        try:
            import pyregion
        except:
            return pyfits[0].data.max()

        if source is None and colorbar_radius is None:
            return pyfits[0].data.max()

        if colorbar_radius is not None:
            ra, dec = roi.roi_dir.ra(), roi.roi_dir.dec()
            reg = pyregion.parse("fk5; circle(%.4f, %.4f, %.4f)" %
                                 (ra, dec, colorbar_radius))
            extensionmask = reg.get_mask(pyfits[0])

        elif hasattr(source, 'spatial_model'):
            # For extended sources,
            # Get the maximum intensity value inside
            # the spatial model's extension
            extension_string = '\n'.join(
                region_writer.unparse_extension(source.spatial_model,
                                                r68=True))
            reg = pyregion.parse(extension_string)
            extensionmask = reg.get_mask(pyfits[0])
        else:
            extensionmask = False  # no mask

        # Get the maximum intensity inside the PSF (in lowest bin)
        emin = roi.bin_edges[0]
        ra, dec = source.skydir.ra(), source.skydir.dec()
        r68 = roi.sa.psf.inverse_integral(emin, 1,
                                          68)  # 1=front entering events
        reg = pyregion.parse("fk5; circle(%.4f, %.4f, %.4f)" % (ra, dec, r68))
        psfmask = reg.get_mask(pyfits[0])

        # use whatever region mask is bigger
        return pyfits[0].data[psfmask | extensionmask].max()

    def _additional_plotting(self):
        from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
        import pywcsgrid2

        if self.overlay_psf:

            if self.source is not None:
                model = self.source.model.copy()
            else:
                model = PowerLaw(index=2)

            # convert it to a point source placed at the origin
            point_version = PointSource(name='PSF',
                                        skydir=self.center,
                                        model=model)

            # create an image of the PSF (for our model).
            # Shrink down the image of the psf
            psf_kwargs = copy.deepcopy(self.smoothed_kwargs)
            psf_kwargs['size'] = self.psf_size
            self.psf_model = SmoothedModel(
                self.roi, override_point_sources=[point_version], **psf_kwargs)
            self.psf_pyfits = self.psf_model.get_pyfits()

            # Normalize psf to have same maximum pixel scale
            # as residual image.
            self.psf_pyfits[0].data *= self.max_intensity / np.max(
                self.psf_pyfits[0].data)

            h_psf, d_psf = self.psf_pyfits[0].header, self.psf_pyfits[0].data
            self.axins = axins = zoomed_inset_axes(self.axes,
                                                   zoom=1,
                                                   loc=self.psf_loc,
                                                   axes_class=pywcsgrid2.Axes,
                                                   axes_kwargs=dict(wcs=h_psf))

            # Note, match color maps with parent.
            axins.imshow(d_psf, origin="lower", **self.imshow_kwargs())
            axins.axis[:].set_zorder(100)
            axins.axis[:].toggle(all=False)
            axins.axis[:].line.set_color('white')

            if self.label_psf:
                axins.add_inner_title("PSF", loc=3)

        self.cax.set_ylabel(r'$\mathrm{counts}/[\mathrm{deg}]^2$')
Пример #5
0
class ROISourceBandPlotter(ROIBandPlotter):
    object = ROISmoothedSource
    defaults = object.defaults
    defaults = keyword_options.change_defaults(defaults, 'figsize', (9, 4))
Пример #6
0
class ROITSMapBandPlotter(ROIBandPlotter):
    object = ROITSMapPlotter
    defaults = object.defaults
    defaults = keyword_options.change_defaults(defaults, 'figsize', (9, 4))
Пример #7
0
class ROISignificanceBandPlotter(ROIBandPlotter):
    object = ROISignificance
    defaults = object.defaults
    defaults = keyword_options.change_defaults(defaults, 'figsize', (9, 4))