Exemple #1
0
    def test_percent(self):
        """Test percent keywords."""
        norm = simple_norm(DATA2, stretch='linear', percent=99.)
        assert_allclose(norm(DATA2), DATA2SCL, atol=0, rtol=1.e-5)

        norm2 = simple_norm(DATA2, stretch='linear', min_percent=0.5,
                         max_percent=99.5)
        assert_allclose(norm(DATA2), norm2(DATA2), atol=0, rtol=1.e-5)
Exemple #2
0
    def test_percent(self):
        """Test percent keywords."""
        norm = simple_norm(DATA2, stretch='linear', percent=99., clip=True)
        assert_allclose(norm(DATA2), DATA2SCL, atol=0, rtol=1.e-5)

        norm2 = simple_norm(DATA2, stretch='linear', min_percent=0.5,
                            max_percent=99.5, clip=True)
        assert_allclose(norm(DATA2), norm2(DATA2), atol=0, rtol=1.e-5)
Exemple #3
0
    def test_invalid_data(self):
        data = np.arange(25.).reshape((5, 5))
        data[2, 2] = np.nan
        data[1, 2] = np.inf
        percent = 85.0
        interval = PercentileInterval(percent)

        # initialized without data
        norm = ImageNormalize(interval=interval)
        norm(data)  # sets vmin/vmax
        assert_equal((norm.vmin, norm.vmax), (1.65, 22.35))

        # initialized with data
        norm2 = ImageNormalize(data, interval=interval)
        assert_equal((norm2.vmin, norm2.vmax), (norm.vmin, norm.vmax))

        norm3 = simple_norm(data, 'linear', percent=percent)
        assert_equal((norm3.vmin, norm3.vmax), (norm.vmin, norm.vmax))

        assert_allclose(norm(data), norm2(data))
        assert_allclose(norm(data), norm3(data))

        norm4 = ImageNormalize()
        norm4(data)  # sets vmin/vmax
        assert_equal((norm4.vmin, norm4.vmax), (0, 24))

        norm5 = ImageNormalize(data)
        assert_equal((norm5.vmin, norm5.vmax), (norm4.vmin, norm4.vmax))
Exemple #4
0
def plot_image(image):

    fig = plt.figure(figsize=(10, 5))
    ax = fig.add_axes([0.0, 0.0, 1.0, 1.0], projection=image.wcs)

    ax.set_xlim(-0.5, image.data.shape[1] - 0.5)
    ax.set_ylim(-0.5, image.data.shape[0] - 0.5)

    norm = simple_norm(
        image.data,
        stretch='power',
        power=0.4,
        min_cut=0,
        max_cut=0.5,
    )
    print('image data max ', image.data.max())

    ax.imshow(
        image.data,
        origin='lower',
        norm=norm,
        cmap=plt.cm.gist_heat,
        interpolation='none',
    )

    plt.axis('off')
Exemple #5
0
 def test_sqrt_invalid_kw(self, invalid):
     stretch = SqrtStretch()
     norm1 = simple_norm(DATA3, stretch='sqrt', min_cut=-1, max_cut=1,
                         clip=False, invalid=invalid)
     norm2 = ImageNormalize(stretch=stretch, vmin=-1, vmax=1, clip=False,
                            invalid=invalid)
     assert_equal(norm1(DATA3), norm2(DATA3))
Exemple #6
0
 def test_min(self):
     """Test linear scaling."""
     norm = simple_norm(DATA2, stretch='linear', min_cut=1., clip=True)
     assert_allclose(norm(DATA2), [0., 0., 1.], atol=0, rtol=1.e-5)
Exemple #7
0
 def test_asinh(self):
     """Test asinh scaling."""
     norm = simple_norm(DATA2, stretch='asinh')
     ref = np.arcsinh(10 * DATA2SCL) / np.arcsinh(10)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #8
0
 def test_log(self):
     """Test log10 scaling."""
     norm = simple_norm(DATA2, stretch='log')
     ref = np.log10(1000 * DATA2SCL + 1.0) / np.log10(1001.0)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #9
0
 def test_sqrt(self):
     """Test sqrt scaling."""
     norm1 = simple_norm(DATA2, stretch='sqrt')
     assert_allclose(norm1(DATA2), np.sqrt(DATA2SCL), atol=0, rtol=1.e-5)
Exemple #10
0
#result.image

# In[ ]:

import matplotlib.pyplot as plt

# In[ ]:

from astropy.visualization.mpl_normalize import simple_norm

# In[ ]:

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
norm = simple_norm(result.image, 'sqrt', min_percent=1, max_percent=99)
im = ax.imshow(result.image, origin='lower', norm=norm, cmap='gray_r')
fig.colorbar(im)

# <hr>

# # Visualization

# ## Scatter Plot using Matplotlib

# In[ ]:

get_ipython().run_line_magic('matplotlib', 'notebook')
from ipywidgets import *
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
matplotlib.use('agg')
from hips import HipsTileMeta, HipsTileAllskyArray
import matplotlib.pyplot as plt
from astropy.visualization.mpl_normalize import simple_norm

meta_fits = HipsTileMeta(order=3, ipix=497, file_format='fits')
url = 'https://github.com/hipspy/hips-extra/raw/master/datasets/samples/IRAC4/Norder3/Allsky.fits'
allsky = HipsTileAllskyArray.fetch(meta_fits, url)
data = allsky.data.astype('float')
norm = simple_norm(data, 'log', min_cut=0, max_cut=data.max())
plt.figure()
plt.imshow(data, norm=norm, origin='lower')
plt.tight_layout()
plt.savefig('Allsky_from_FITS.jpg')

tile = allsky.tile(271)
data = tile.data
norm = simple_norm(data, 'linear', min_cut=0, max_cut=data.max())
plt.figure()
plt.imshow(data, norm=norm, origin='lower')
plt.tight_layout()
plt.savefig('Tile_from_FITS.jpg')

# Print infos about the brightest pixel in the FITS image
max_value = allsky.data.max()
idx = np.where(allsky.data == max_value)
print('Brightest pixel value:', max_value)
print('Brightest pixel in allsky data:', idx)
for tile in allsky.tiles:
Exemple #12
0
def make_clean_comparison_fig(u, v, vis, weights, sol, clean_profile,
                              bin_widths, stretch='power',
                              gamma=1.0, asinh_a=0.02, mean_convolved=None,
                              dist=None, force_style=True, save_prefix=None,
                              figsize=(8, 10)):
    r"""
    Produce a figure comparing a frank fit to a CLEAN fit, in real space by
    convolving the frank fit with the CLEAN beam, and in visibility space by
    taking the discrete Hankel transform of the CLEAN profile

    Parameters
    ----------
    u, v : array, unit = :math:`\lambda`
        u and v coordinates of observations
    vis : array, unit = Jy
        Observed visibilities (complex: real + imag * 1j)
    weights : array, unit = Jy^-2
        Weights assigned to observed visibilities, of the form
        :math:`1 / \sigma^2`
    sol : _HankelRegressor object
        Reconstructed profile using Maximum a posteriori power spectrum
        (see frank.radial_fitters.FrankFitter)
    clean_profile : dict
        Dictionary with entries 'r' for the radial points [arcsec],
        'I' for the brightness [Jy / sr], and optionally the negative and positive
        brightness uncertainties 'lo_err' and 'hi_err' [Jy / sr]. If only the
        negative uncertainty is provided, the positive uncertainty is assumed
        equal to it
    bin_widths : list, unit = \lambda
        Bin widths in which to bin the observed visibilities
    stretch : string, default = 'power'
        Transformation to apply to the colorscale. The default 'power' is a
        power law stretch. The other option is 'asinh', an arcsinh stretch,
        which requires astropy.visualization.mpl_normalize.simple_norm
    gamma : float, default = 1.0
        Index of power law normalization to apply to swept profile image's
        colormap (see matplotlib.colors.PowerNorm).
        gamma=1.0 yields a linear colormap
    asinh_a : float, default = 0.02
        Scale parameter for an asinh stretch
    mean_convolved : None (default) or array, unit = Jy / sr
        frank brightness profile convolved with a CLEAN beam
        (see utilities.convolve_profile).
        The assumed unit is for the x-label
    dist : float, optional, unit = AU, default = None
        Distance to source, used to show second x-axis in [AU]
    force_style: bool, default = True
        Whether to use preconfigured matplotlib rcParams in generated figure
    save_prefix : string, default = None
        Prefix for saved figure name. If None, the figure won't be saved
    figsize : tuple = (width, height) of figure, unit = inch

    Returns
    -------
    fig : Matplotlib `.Figure` instance
        The produced figure, including the GridSpec
    axes : Matplotlib `~.axes.Axes` class
        The axes of the produced figure
    """

    logging.info('    Making CLEAN comparison figure')

    with frank_plotting_style_context_manager(force_style):
        gs = GridSpec(3, 1)
        gs2 = GridSpec(3, 3)

        fig = plt.figure(figsize=figsize)

        ax0 = fig.add_subplot(gs[0])
        ax1 = fig.add_subplot(gs[1])

        ax2 = fig.add_subplot(gs2[6])
        ax3 = fig.add_subplot(gs2[7])
        ax4 = fig.add_subplot(gs2[8])

        axes = [ax0, ax1, ax2, ax3, ax4]

        if 'lo_err' in clean_profile.keys():
            low_uncer = clean_profile['lo_err']
        else:
            low_uncer = None
        if 'hi_err' in clean_profile.keys():
            high_uncer = clean_profile['hi_err']
        else:
            high_uncer = None

        plot_brightness_profile(clean_profile['r'], clean_profile['I'] / 1e10, ax0,
                                low_uncer=low_uncer, high_uncer=high_uncer,
                                c='b', ls='--', label='CLEAN')

        plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, c='r', ls=':', label='frank')

        if mean_convolved is not None:
            plot_brightness_profile(sol.r, mean_convolved / 1e10, ax0, c='k', ls='-',
                                    label='frank, convolved')

        if dist:
            ax0_5 = plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, dist=dist, c='r', ls=':')

        u_deproj, v_deproj, vis_deproj = sol.geometry.apply_correction(u, v, vis)
        baselines = (u_deproj**2 + v_deproj**2)**.5
        grid = np.logspace(np.log10(min(baselines.min(), sol.q[0])),
                           np.log10(max(baselines.max(), sol.q[-1])), 10**4
                           )

        for i in range(len(bin_widths)):
            binned_vis = UVDataBinner(baselines, vis_deproj, weights, bin_widths[i])
            vis_re_kl = binned_vis.V.real * 1e3
            vis_err_re_kl = binned_vis.error.real * 1e3

            plot_vis_quantity(binned_vis.uv, vis_re_kl, ax1, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs.>0, {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))
            plot_vis_quantity(binned_vis.uv, -vis_re_kl, ax1, c=cs2[i],
                     marker=ms[i], ls='None',
                     label=r'Obs.<0, {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

        vis_fit_kl = sol.predict_deprojected(grid).real * 1e3

        # Take the discrete Hankel transform of the CLEAN profile, using the same
        # collocation points for the DHT as those in the frank fit
        Inu_interp = np.interp(
            sol.r, clean_profile['r'], clean_profile['I'].real) * 1e3
        clean_DHT_kl = sol.predict_deprojected(grid, I=Inu_interp)

        plot_vis_quantity(grid, vis_fit_kl, ax1, c='r', label='frank>0')
        plot_vis_quantity(grid, -vis_fit_kl, ax1, c='r', ls='--', label='frank<0')
        plot_vis_quantity(grid, clean_DHT_kl, ax1, c='b', label='DHT of CLEAN>0')
        plot_vis_quantity(grid, -clean_DHT_kl, ax1, c='b', ls='--', label='DHT of CLEAN<0')

        if mean_convolved is not None:
            vmax = max(sol.mean.max(), mean_convolved.max(), clean_profile['I'].max())
        else:
            vmax = max(sol.mean.max(), clean_profile['I'].max())
        if stretch == 'asinh':
            vmin = max(0, min(sol.mean))
            from astropy.visualization.mpl_normalize import simple_norm
            norm = simple_norm(sol.mean, stretch='asinh', asinh_a=asinh_a, min_cut=vmin)
        elif stretch == 'power':
            vmin = 0
            norm = PowerNorm(gamma, vmin, vmax)
        else:
            err = ValueError("Unknown 'stretch'. Should be one of 'power' or 'asinh'")
            raise err

        plot_2dsweep(sol.r, sol.mean, ax=ax2, cmap='inferno', norm=norm, vmin=0,
                    vmax=vmax / 1e10, xmax=sol.Rmax, plot_colorbar=True)
        if mean_convolved is not None:
            plot_2dsweep(sol.r, mean_convolved, ax=ax3, cmap='inferno', norm=norm,
                        vmin=0, vmax=vmax / 1e10, xmax=sol.Rmax, plot_colorbar=True)

        # Interpolate the CLEAN profile onto the frank grid to ensure the CLEAN
        # swept 'image' has the same pixel resolution as the frank swept 'images'
        from scipy.interpolate import interp1d
        interp = interp1d(clean_profile['r'], clean_profile['I'])
        regrid_I_clean = interp(sol.r)
        plot_2dsweep(sol.r, regrid_I_clean, ax=ax4, cmap='inferno', norm=norm,
                    vmin=0, vmax=vmax / 1e10, xmax=sol.Rmax, plot_colorbar=True)

        ax0.legend(loc='best')
        ax1.legend(loc='best')

        ax0.set_xlabel('r ["]')
        ax0.set_ylabel(r'Brightness [$10^{10}$ Jy sr$^{-1}$]')
        ax1.set_xlabel(r'Baseline [$\lambda$]')
        ax1.set_ylabel(r'Re(V) [mJy]')
        ax2.set_xlabel('RA offset ["]')
        ax3.set_xlabel('RA offset ["]')
        ax4.set_xlabel('RA offset ["]')
        ax2.set_ylabel('Dec offset ["]')

        ax0.set_xlim(right=sol.Rmax)
        if dist:
            xlims = ax0.get_xlim()
            ax0_5.set_xlim(np.multiply(xlims, dist))

        ax1.set_xlim(.9 * baselines.min(), 1.2 * baselines.max())
        ax1.set_xscale('log')
        ax1.set_yscale('log')
        ax1.set_ylim(bottom=1e-3)

        ax2.set_title('Unconvolved frank profile swept')
        ax3.set_title('Convolved frank profile swept')
        ax4.set_title('CLEAN profile swept')

        ax0.text(.5, .9, 'a)', transform=ax0.transAxes)
        ax1.text(.5, .9, 'b)', transform=ax1.transAxes)
        ax2.text(.1, .9, 'c)', c='w', transform=ax2.transAxes)
        ax3.text(.1, .9, 'd)', c='w', transform=ax3.transAxes)
        ax4.text(.1, .9, 'e)', c='w', transform=ax4.transAxes)

        if save_prefix:
            plt.savefig(save_prefix + '_frank_clean_comparison.png', dpi=600)
            plt.close()

    return fig, axes
Exemple #13
0
def make_full_fig(u, v, vis, weights, sol, bin_widths, alpha, wsmooth,
                  dist=None, logx=True, force_style=True,
                  save_prefix=None, norm_residuals=False, stretch='power',
                  gamma=1.0, asinh_a=0.02, figsize=(8, 6)):
    r"""
    Produce a figure showing a Frankenstein fit and some useful diagnostics

    Parameters
    ----------
    u, v : array, unit = :math:`\lambda`
        u and v coordinates of observations
    vis : array, unit = Jy
        Observed visibilities (complex: real + imag * 1j)
    weights : array, unit = Jy^-2
        Weights assigned to observed visibilities, of the form
        :math:`1 / \sigma^2`
    sol : _HankelRegressor object
        Reconstructed profile using Maximum a posteriori power spectrum
        (see frank.radial_fitters.FrankFitter)
    bin_widths : list, unit = \lambda
        Bin widths in which to bin the observed visibilities
    alpha : float
        Value for the :math:`\alpha` hyperparameter.
        Used for the plot legends
    wsmooth : float
        Value for the :math:`w_{smooth}` hyperparameter.
        Used for the plot legends
    dist : float, optional, unit = AU, default = None
        Distance to source, used to show second x-axis in [AU]
    logx : bool, default = True
        Whether to plot the visibility distributions in log(baseline)
    force_style: bool, default = True
        Whether to use preconfigured matplotlib rcParams in generated figure
    save_prefix : string, default = None
        Prefix for saved figure name. If None, the figure won't be saved
    norm_residuals : bool, default = False
        Whether to normalize the residual visibilities by the data's
        visibility amplitudes
    stretch : string, default = 'power'
        Transformation to apply to the colorscale. The default 'power' is a
        power law stretch. The other option is 'asinh', an arcsinh stretch,
        which requires astropy.visualization.mpl_normalize.simple_norm
    gamma : float, default = 1.0
        Index of power law normalization to apply to swept profile image's
        colormap (see matplotlib.colors.PowerNorm).
        gamma=1.0 yields a linear colormap
    asinh_a : float, default = 0.02
        Scale parameter for an asinh stretch
    figsize : tuple = (width, height) of figure, unit = inch

    Returns
    -------
    fig : Matplotlib `.Figure` instance
        The produced figure, including the GridSpec
    axes : Matplotlib `~.axes.Axes` class
        The axes of the produced figure
    """

    logging.info('    Making full figure')

    with frank_plotting_style_context_manager(force_style):
        gs = GridSpec(3, 3, hspace=0)
        gs1 = GridSpec(4, 3, hspace=0, top=.88)
        gs2 = GridSpec(3, 3, hspace=.35, left=.04)
        fig = plt.figure(figsize=figsize)

        ax0 = fig.add_subplot(gs[0])
        ax1 = fig.add_subplot(gs[3])
        ax2 = fig.add_subplot(gs2[6])

        ax3 = fig.add_subplot(gs[1])
        ax4 = fig.add_subplot(gs[4])
        ax5 = fig.add_subplot(gs[7])

        ax6 = fig.add_subplot(gs[2])
        ax7 = fig.add_subplot(gs1[5])
        ax8 = fig.add_subplot(gs1[8])
        ax9 = fig.add_subplot(gs1[11])

        ax0.text(.9, .6, 'a)', transform=ax0.transAxes)
        ax1.text(.9, .6, 'b)', transform=ax1.transAxes)
        ax2.text(.1, .9, 'c)', c='w', transform=ax2.transAxes)

        ax3.text(.1, .5, 'd)', transform=ax3.transAxes)
        ax4.text(.1, .7, 'e)', transform=ax4.transAxes)
        ax5.text(.1, .7, 'f)', transform=ax5.transAxes)
        ax6.text(.9, .9, 'g)', transform=ax6.transAxes)
        ax7.text(.9, .9, 'h)', transform=ax7.transAxes)
        ax8.text(.9, .9, 'i)', transform=ax8.transAxes)
        ax9.text(.9, .9, 'j)', transform=ax9.transAxes)

        axes = [ax0, ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]

        # Calculate the fit's total flux (2D, by sweeping the 1D profile over 2\pi)
        total_flux = trapz(sol.mean * 2 * np.pi * sol.r, sol.r)

        # Plot the fitted brightness profile in linear- and log-y
        plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, c='r',
            label='frank, total flux {:.2e} Jy'.format(total_flux))
        if dist:
            ax0_5 = plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, dist=dist, c='r')
            xlims = ax0.get_xlim()
            ax0_5.set_xlim(np.multiply(xlims, dist))

        plot_brightness_profile(sol.r, sol.mean / 1e10, ax1, c='r', label='frank')

        # Apply deprojection to the provided (u, v) coordinates
        # and visibility amplitudes
        u_deproj, v_deproj, vis_deproj = sol.geometry.apply_correction(u, v, vis)
        baselines = (u_deproj**2 + v_deproj**2)**.5
        # Set a grid of baselines on which to plot the visibility domain frank fit
        grid = np.logspace(np.log10(min(baselines.min(), sol.q[0])),
                           np.log10(max(baselines.max(), sol.q[-1])), 10**4
                           )
        # Map the frank visibility fit to `grid`, considering only the real component
        # that frank fits
        vis_fit_kl = sol.predict_deprojected(grid).real * 1e3

        # Make a guess of good y-bounds for zooming in on the visibility fit
        # in linear-y
        zoom_ylim_guess = abs(vis_fit_kl[np.int(.5 * len(vis_fit_kl)):]).max()
        zoom_bounds = [-1.1 * zoom_ylim_guess, 1.1 * zoom_ylim_guess]
        ax4.set_ylim(zoom_bounds)

        # Bin the observed (real and imaginary components of the) visibilities
        # for plotting
        for i in range(len(bin_widths)):
            binned_vis = UVDataBinner(baselines, vis_deproj, weights, bin_widths[i])
            vis_re_kl = binned_vis.V.real * 1e3
            vis_im_kl = binned_vis.V.imag * 1e3
            vis_err_re_kl = binned_vis.error.real * 1e3
            vis_err_im_kl = binned_vis.error.imag * 1e3
            vis_fit = sol.predict_deprojected(binned_vis.uv).real * 1e3

            # Determine the visiblity domain frank fit residuals (and RMS error)
            # for Real(V)
            resid = vis_re_kl - vis_fit
            if norm_residuals:
                resid /= vis_re_kl
            rmse = (np.mean(resid**2))**.5

            # Plot the observed, binned visibilities (with errorbars) and the residuals
            plot_vis_quantity(binned_vis.uv, vis_re_kl, ax3, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs., {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

            plot_vis_quantity(binned_vis.uv, vis_re_kl, ax4, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs., {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

            plot_vis_quantity(binned_vis.uv, vis_re_kl, ax6, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs.>0, {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

            plot_vis_quantity(binned_vis.uv, -vis_re_kl, ax6, c=cs2[i],
                     marker=ms[i], ls='None',
                     label=r'Obs.<0, {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

            plot_vis_quantity(binned_vis.uv, vis_im_kl, ax9, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs., {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

            plot_vis_quantity(binned_vis.uv, resid, ax5, c=cs[i], marker=ms[i], ls='None',
                           label=r'{:.0f} k$\lambda$ bins, RMSE {:.3f} mJy'.format(bin_widths[i]/1e3, rmse))

            # Plot a histogram of the observed visibilties to examine how the
            # visibility count varies with baseline
            plot_vis_hist(binned_vis, ax8, color=hist_cs[i],
                          label=r'Obs., {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

        # Plot the visibility domain frank fit in log-y
        plot_vis_quantity(grid, vis_fit_kl, ax3, c='r', label='frank')
        plot_vis_quantity(grid, vis_fit_kl, ax4, c='r', label='frank')
        plot_vis_quantity(grid, vis_fit_kl, ax6, c='r', label='frank>0')
        plot_vis_quantity(grid, -vis_fit_kl, ax6, c='#1EFEDC', label='frank<0')

        # Plot the frank inferred power spectrum
        plot_vis_quantity(sol.q, sol.power_spectrum, ax7, label=r'$\alpha$ {:.2f}'.format(
            alpha) + '\n' + '$w_{smooth}$' + ' {:.1e}'.format(wsmooth))

        # Plot a sweep over 2\pi of the frank 1D fit
        # (analogous to a model image of the source)
        vmax = sol.mean.max()
        if stretch == 'asinh':
            vmin = max(0, min(sol.mean))
            from astropy.visualization.mpl_normalize import simple_norm
            norm = simple_norm(sol.mean, stretch='asinh', asinh_a=asinh_a, min_cut=vmin)
        elif stretch == 'power':
            vmin = 0
            norm = PowerNorm(gamma, vmin, vmax)
        else:
            err = ValueError("Unknown 'stretch'. Should be one of 'power' or 'asinh'")
            raise err

        plot_2dsweep(sol.r, sol.mean, ax=ax2, cmap='inferno', norm=norm, vmin=vmin,
                    vmax=vmax / 1e10, project=True, geom=sol.geometry)

        ax1.set_xlabel('r ["]')
        ax0.set_ylabel(r'Brightness [$10^{10}$ Jy sr$^{-1}$]')
        ax1.set_ylabel(r'Brightness [$10^{10}$ Jy sr$^{-1}$]')
        ax1.set_yscale('log')
        ax1.set_ylim(bottom=1e-3)

        ax2.set_xlabel('RA offset ["]')
        ax2.set_ylabel('Dec offset ["]')

        ax3.set_ylabel('Re(V) [mJy]')
        ax4.set_ylabel('Re(V) [mJy]')
        if norm_residuals:
            ax5.set_ylabel('Norm. residual')
        else:
            ax5.set_ylabel('Residual [mJy]')
        ax5.set_xlabel(r'Baseline [$\lambda$]')

        ax6.set_ylabel('Re(V) [mJy]')
        ax7.set_ylabel(r'Power [Jy$^2$]')
        ax8.set_ylabel('Count')
        ax9.set_ylabel('Im(V) [mJy]')
        ax9.set_xlabel(r'Baseline [$\lambda$]')

        if logx:
            ax3.set_xscale('log')
            ax4.set_xscale('log')
            ax5.set_xscale('log')
            ax6.set_xscale('log')
            ax7.set_xscale('log')
            ax8.set_xscale('log')
            ax9.set_xscale('log')

        xlims = ax5.get_xlim()
        ax3.set_xlim(xlims)
        ax4.set_xlim(xlims)
        ax6.set_xlim(xlims)
        ax7.set_xlim(xlims)
        ax8.set_xlim(xlims)
        ax9.set_xlim(xlims)

        ax6.set_yscale('log')
        ax7.set_yscale('log')
        ax8.set_yscale('log')
        ax6.set_ylim(bottom=1e-4)

        plt.setp(ax0.get_xticklabels(), visible=False)
        plt.setp(ax3.get_xticklabels(), visible=False)
        plt.setp(ax4.get_xticklabels(), visible=False)
        plt.setp(ax6.get_xticklabels(), visible=False)
        plt.setp(ax7.get_xticklabels(), visible=False)
        plt.setp(ax8.get_xticklabels(), visible=False)

        plt.tight_layout()

        if save_prefix:
            plt.savefig(save_prefix + '_frank_fit_full.png', dpi=600)
            plt.close()

    return fig, axes
Exemple #14
0
def make_quick_fig(u, v, vis, weights, sol, bin_widths, dist=None, logx=True,
                   force_style=True, save_prefix=None,
                   stretch='power', gamma=1.0, asinh_a=0.02, figsize=(8,6)):
    r"""
    Produce a simple figure showing just a Frankenstein fit, not any diagnostics

    Parameters
    ----------
    u, v : array, unit = :math:`\lambda`
        u and v coordinates of observations
    vis : array, unit = Jy
        Observed visibilities (complex: real + imag * 1j)
    weights : array, unit = Jy^-2
        Weights assigned to observed visibilities, of the form
        :math:`1 / \sigma^2`
    sol : _HankelRegressor object
        Reconstructed profile using Maximum a posteriori power spectrum
        (see frank.radial_fitters.FrankFitter)
    bin_widths : list, unit = \lambda
        Bin widths in which to bin the observed visibilities
    dist : float, optional, unit = AU, default = None
        Distance to source, used to show second x-axis in [AU]
    logx : bool, default = True
        Whether to plot the visibility distributions in log(baseline)
    gamma : float, default = 1.0
        Index of power law normalization to apply to swept profile image's
        colormap (see matplotlib.colors.PowerNorm).
        gamma=1.0 yields a linear colormap
    force_style: bool, default = True
        Whether to use preconfigured matplotlib rcParams in generated figure
    save_prefix : string, default = None
        Prefix for saved figure name. If None, the figure won't be saved
    stretch : string, default = 'power'
        Transformation to apply to the colorscale. The default 'power' is a
        power law stretch. The other option is 'asinh', an arcsinh stretch,
        which requires astropy.visualization.mpl_normalize.simple_norm
    asinh_a : float, default = 0.02
        Scale parameter for an asinh stretch
    figsize : tuple = (width, height) of figure, unit = inch

    Returns
    -------
    fig : Matplotlib `.Figure` instance
        The produced figure, including the GridSpec
    axes : Matplotlib `~.axes.Axes` class
        The axes of the produced figure
    """

    logging.info('    Making quick figure')

    with frank_plotting_style_context_manager(force_style):
        gs = GridSpec(3, 2, hspace=0, bottom=.12)
        gs2 = GridSpec(3, 2, hspace=.2)
        fig = plt.figure(figsize=figsize)

        ax0 = fig.add_subplot(gs[0])
        ax1 = fig.add_subplot(gs[2])

        ax2 = fig.add_subplot(gs[1])
        ax3 = fig.add_subplot(gs[3])

        ax4 = fig.add_subplot(gs2[4])
        ax5 = fig.add_subplot(gs2[5])

        ax0.text(.5, .9, 'a)', transform=ax0.transAxes)
        ax1.text(.5, .9, 'b)', transform=ax1.transAxes)

        ax2.text(.5, .9, 'c)', transform=ax2.transAxes)
        ax3.text(.5, .9, 'd)', transform=ax3.transAxes)

        ax4.text(.5, .9, 'e)', c='w', transform=ax4.transAxes)
        ax5.text(.5, .9, 'f)', c='w', transform=ax5.transAxes)

        axes = [ax0, ax1, ax2, ax3, ax4, ax5]

        total_flux = trapz(sol.mean * 2 * np.pi * sol.r, sol.r)
        plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, c='r',
            label='frank, total flux {:.2e} Jy'.format(total_flux))
        if dist:
            ax0_5 = plot_brightness_profile(sol.r, sol.mean / 1e10, ax0, dist=dist, c='r')
            xlims = ax0.get_xlim()
            ax0_5.set_xlim(np.multiply(xlims, dist))

        plot_brightness_profile(sol.r, sol.mean / 1e10, ax1, c='r', label='frank')

        u_deproj, v_deproj, vis_deproj = sol.geometry.apply_correction(u, v, vis)
        baselines = (u_deproj**2 + v_deproj**2)**.5
        grid = np.logspace(np.log10(min(baselines.min(), sol.q[0])),
                           np.log10(max(baselines.max(), sol.q[-1])),
                           10**4)

        for i in range(len(bin_widths)):
            binned_vis = UVDataBinner(
                baselines, vis_deproj, weights, bin_widths[i])
            vis_re_kl = binned_vis.V.real * 1e3
            vis_err_re_kl = binned_vis.error.real * 1e3
            vis_fit = sol.predict_deprojected(binned_vis.uv).real * 1e3

            for ax in [ax2, ax3]:
                plot_vis_quantity(binned_vis.uv / 1e6, vis_re_kl, ax,
                     vis_err_re_kl, c=cs[i],
                     marker=ms[i], ls='None',
                     label=r'Obs., {:.0f} k$\lambda$ bins'.format(bin_widths[i]/1e3))

        vis_fit_kl = sol.predict_deprojected(grid).real * 1e3
        plot_vis_quantity(grid / 1e6, vis_fit_kl, ax2, c='r', label='frank', zorder=10)

        # Make a guess of good y-bounds for zooming in on the visibility fit
        # in linear-y
        zoom_ylim_guess = abs(vis_fit_kl[np.int(.5 * len(vis_fit_kl)):]).max()
        zoom_bounds = [-1.1 * zoom_ylim_guess, 1.1 * zoom_ylim_guess]
        ax3.set_ylim(zoom_bounds)

        plot_vis_quantity(grid / 1e6, vis_fit_kl, ax3, c='r', label='frank', zorder=10)

        vmax = sol.mean.max()
        if stretch == 'asinh':
            vmin = max(0, min(sol.mean))
            from astropy.visualization.mpl_normalize import simple_norm
            norm = simple_norm(sol.mean, stretch='asinh', asinh_a=asinh_a, min_cut=vmin)
        elif stretch == 'power':
            vmin = 0
            norm = PowerNorm(gamma, vmin, vmax)
        else:
            err = ValueError("Unknown 'stretch'. Should be one of 'power' or 'asinh'")
            raise err

        plot_2dsweep(sol.r, sol.mean, ax=ax4, cmap='inferno', norm=norm, vmin=vmin,
                    vmax=vmax / 1e10, project=False)
        plot_2dsweep(sol.r, sol.mean, ax=ax5, cmap='inferno', norm=norm, vmin=vmin,
                    vmax=vmax / 1e10, project=True, geom=sol.geometry)

        ax1.set_xlabel('r ["]')
        ax0.set_ylabel(r'Brightness [$10^{10}$ Jy sr$^{-1}$]')
        ax1.set_ylabel(r'Brightness [$10^{10}$ Jy sr$^{-1}$]')
        ax1.set_yscale('log')
        ax1.set_ylim(bottom=1e-3)

        ax3.set_xlabel(r'Baseline [M$\lambda$]')
        ax2.set_ylabel('Re(V) [mJy]')
        ax3.set_ylabel('Re(V) [mJy]')

        if logx:
            ax2.set_xscale('log')
            ax3.set_xscale('log')
        else:
            ax2.set_xlim(0., max(binned_vis.uv) / 1e6 * 1.1)

        xlims = ax2.get_xlim()
        ax3.set_xlim(xlims)

        ax4.set_xlabel('RA offset ["]')
        ax4.set_ylabel('Dec offset ["]')
        ax5.set_xlabel('RA offset ["]')
        ax5.set_ylabel('Dec offset ["]')

        plt.setp(ax0.get_xticklabels(), visible=False)
        plt.setp(ax2.get_xticklabels(), visible=False)

        plt.tight_layout()

        if save_prefix:
            plt.savefig(save_prefix + '_frank_fit_quick.png', dpi=600)
            plt.close()

    return fig, axes
Exemple #15
0
def fits2bitmap(filename, ext=0, out_fn=None, stretch='linear',
                power=1.0, asinh_a=0.1, min_cut=None, max_cut=None,
                min_percent=None, max_percent=None, percent=None,
                cmap='Greys_r'):
    """
    Create a bitmap file from a FITS image, applying a stretching
    transform between minimum and maximum cut levels and a matplotlib
    colormap.

    Parameters
    ----------
    filename : str
        The filename of the FITS file.
    ext : int
        FITS extension name or number of the image to convert.  The
        default is 0.
    out_fn : str
        The filename of the output bitmap image.  The type of bitmap
        is determined by the filename extension (e.g. '.jpg', '.png').
        The default is a PNG file with the same name as the FITS file.
    stretch : {{'linear', 'sqrt', 'power', log', 'asinh'}}
        The stretching function to apply to the image.  The default is
        'linear'.
    power : float, optional
        The power index for ``stretch='power'``.  The default is 1.0.
    asinh_a : float, optional
        For ``stretch='asinh'``, the value where the asinh curve
        transitions from linear to logarithmic behavior, expressed as a
        fraction of the normalized image.  Must be in the range between
        0 and 1.  The default is 0.1.
    min_cut : float, optional
        The pixel value of the minimum cut level.  Data values less than
        ``min_cut`` will set to ``min_cut`` before stretching the image.
        The default is the image minimum.  ``min_cut`` overrides
        ``min_percent``.
    max_cut : float, optional
        The pixel value of the maximum cut level.  Data values greater
        than ``min_cut`` will set to ``min_cut`` before stretching the
        image.  The default is the image maximum.  ``max_cut`` overrides
        ``max_percent``.
    min_percent : float, optional
        The percentile value used to determine the pixel value of
        minimum cut level.  The default is 0.0.  ``min_percent``
        overrides ``percent``.
    max_percent : float, optional
        The percentile value used to determine the pixel value of
        maximum cut level.  The default is 100.0.  ``max_percent``
        overrides ``percent``.
    percent : float, optional
        The percentage of the image values used to determine the pixel
        values of the minimum and maximum cut levels.  The lower cut
        level will set at the ``(100 - percent) / 2`` percentile, while
        the upper cut level will be set at the ``(100 + percent) / 2``
        percentile.  The default is 100.0.  ``percent`` is ignored if
        either ``min_percent`` or ``max_percent`` is input.
    cmap : str
        The matplotlib color map name.  The default is 'Greys_r'.
    """

    import matplotlib
    import matplotlib.cm as cm
    import matplotlib.image as mimg

    # __main__ gives ext as a string
    try:
        ext = int(ext)
    except ValueError:
        pass

    try:
        image = getdata(filename, ext)
    except Exception as e:
        log.critical(e)
        return 1

    if image.ndim != 2:
        log.critical('data in FITS extension {0} is not a 2D array'
                     .format(ext))

    if out_fn is None:
        out_fn = os.path.splitext(filename)[0]
        if out_fn.endswith('.fits'):
            out_fn = os.path.splitext(out_fn)[0]
        out_fn += '.png'

    # need to explicitly define the output format due to a bug in
    # matplotlib (<= 2.1), otherwise the format will always be PNG
    out_format = os.path.splitext(out_fn)[1][1:]

    # workaround for matplotlib 2.0.0 bug where png images are inverted
    # (mpl-#7656)
    if (out_format.lower() == 'png' and
            LooseVersion(matplotlib.__version__) == LooseVersion('2.0.0')):
        image = image[::-1]

    if cmap not in cm.datad:
        log.critical('{0} is not a valid matplotlib colormap name.'
                     .format(cmap))
        return 1

    norm = simple_norm(image, stretch=stretch, power=power, asinh_a=asinh_a,
                       min_cut=min_cut, max_cut=max_cut,
                       min_percent=min_percent, max_percent=max_percent,
                       percent=percent)

    mimg.imsave(out_fn, norm(image), cmap=cmap, origin='lower',
                format=out_format)
    log.info('Saved file to {0}.'.format(out_fn))
Exemple #16
0
 def test_asinh(self):
     """Test asinh scaling."""
     a = 0.1
     norm = simple_norm(DATA2, stretch='asinh', asinh_a=a)
     ref = np.arcsinh(DATA2SCL / a) / np.arcsinh(1. / a)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #17
0
 def test_min(self):
     """Test linear scaling."""
     norm = simple_norm(DATA2, stretch='linear', min_cut=1.)
     assert_allclose(norm(DATA2), [0., 0., 1.], atol=0, rtol=1.e-5)
Exemple #18
0
 def test_asinh(self):
     """Test asinh scaling."""
     a = 0.1
     norm = simple_norm(DATA2, stretch='asinh', asinh_a=a)
     ref = np.arcsinh(DATA2SCL / a) / np.arcsinh(1. / a)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #19
0
 def test_invalid_stretch(self):
     """Test invalid stretch keyword."""
     with pytest.raises(ValueError):
         simple_norm(DATA2, stretch='invalid')
Exemple #20
0
 def test_linear(self):
     """Test linear scaling."""
     norm = simple_norm(DATA2, stretch='linear')
     assert_allclose(norm(DATA2), DATA2SCL, atol=0, rtol=1.e-5)
Exemple #21
0
def fits2bitmap(filename, ext=0, out_fn=None, stretch='linear',
                power=1.0, asinh_a=0.1, min_cut=None, max_cut=None,
                min_percent=None, max_percent=None, percent=None,
                cmap='Greys_r'):
    """
    Create a bitmap file from a FITS image, applying a stretching
    transform between minimum and maximum cut levels and a matplotlib
    colormap.

    Parameters
    ----------
    filename : str
        The filename of the FITS file.
    ext : int
        FITS extension name or number of the image to convert.  The
        default is 0.
    out_fn : str
        The filename of the output bitmap image.  The type of bitmap
        is determined by the filename extension (e.g. '.jpg', '.png').
        The default is a PNG file with the same name as the FITS file.
    stretch : {{'linear', 'sqrt', 'power', log', 'asinh'}}
        The stretching function to apply to the image.  The default is
        'linear'.
    power : float, optional
        The power index for ``stretch='power'``.  The default is 1.0.
    asinh_a : float, optional
        For ``stretch='asinh'``, the value where the asinh curve
        transitions from linear to logarithmic behavior, expressed as a
        fraction of the normalized image.  Must be in the range between
        0 and 1.  The default is 0.1.
    min_cut : float, optional
        The pixel value of the minimum cut level.  Data values less than
        ``min_cut`` will set to ``min_cut`` before stretching the image.
        The default is the image minimum.  ``min_cut`` overrides
        ``min_percent``.
    max_cut : float, optional
        The pixel value of the maximum cut level.  Data values greater
        than ``min_cut`` will set to ``min_cut`` before stretching the
        image.  The default is the image maximum.  ``max_cut`` overrides
        ``max_percent``.
    min_percent : float, optional
        The percentile value used to determine the pixel value of
        minimum cut level.  The default is 0.0.  ``min_percent``
        overrides ``percent``.
    max_percent : float, optional
        The percentile value used to determine the pixel value of
        maximum cut level.  The default is 100.0.  ``max_percent``
        overrides ``percent``.
    percent : float, optional
        The percentage of the image values used to determine the pixel
        values of the minimum and maximum cut levels.  The lower cut
        level will set at the ``(100 - percent) / 2`` percentile, while
        the upper cut level will be set at the ``(100 + percent) / 2``
        percentile.  The default is 100.0.  ``percent`` is ignored if
        either ``min_percent`` or ``max_percent`` is input.
    cmap : str
        The matplotlib color map name.  The default is 'Greys_r'.
    """

    import matplotlib
    import matplotlib.cm as cm
    import matplotlib.image as mimg

    # __main__ gives ext as a string
    try:
        ext = int(ext)
    except ValueError:
        pass

    try:
        image = getdata(filename, ext)
    except Exception as e:
        log.critical(e)
        return 1

    if image.ndim != 2:
        log.critical('data in FITS extension {} is not a 2D array'
                     .format(ext))

    if out_fn is None:
        out_fn = os.path.splitext(filename)[0]
        if out_fn.endswith('.fits'):
            out_fn = os.path.splitext(out_fn)[0]
        out_fn += '.png'

    # need to explicitly define the output format due to a bug in
    # matplotlib (<= 2.1), otherwise the format will always be PNG
    out_format = os.path.splitext(out_fn)[1][1:]

    # workaround for matplotlib 2.0.0 bug where png images are inverted
    # (mpl-#7656)
    if (out_format.lower() == 'png' and
            LooseVersion(matplotlib.__version__) == LooseVersion('2.0.0')):
        image = image[::-1]

    try:
        cm.get_cmap(cmap)
    except ValueError:
        log.critical('{} is not a valid matplotlib colormap name.'
                     .format(cmap))
        return 1

    norm = simple_norm(image, stretch=stretch, power=power, asinh_a=asinh_a,
                       min_cut=min_cut, max_cut=max_cut,
                       min_percent=min_percent, max_percent=max_percent,
                       percent=percent)

    mimg.imsave(out_fn, norm(image), cmap=cmap, origin='lower',
                format=out_format)
    log.info(f'Saved file to {out_fn}.')
Exemple #22
0
 def test_sqrt(self):
     """Test sqrt scaling."""
     norm = simple_norm(DATA2, stretch='sqrt')
     assert_allclose(norm(DATA2), np.sqrt(DATA2SCL), atol=0, rtol=1.e-5)
Exemple #23
0
 def test_linear(self):
     """Test linear scaling."""
     norm = simple_norm(DATA2, stretch='linear')
     assert_allclose(norm(DATA2), DATA2SCL, atol=0, rtol=1.e-5)
Exemple #24
0
 def test_power(self):
     """Test power scaling."""
     power = 3.0
     norm = simple_norm(DATA2, stretch='power', power=power)
     assert_allclose(norm(DATA2), DATA2SCL ** power, atol=0, rtol=1.e-5)
Exemple #25
0
 def test_power(self):
     """Test power scaling."""
     power = 3.0
     norm = simple_norm(DATA2, stretch='power', power=power)
     assert_allclose(norm(DATA2), DATA2SCL**power, atol=0, rtol=1.e-5)
Exemple #26
0
 def test_log(self):
     """Test log10 scaling."""
     norm = simple_norm(DATA2, stretch='log')
     ref = np.log10(1000 * DATA2SCL + 1.0) / np.log10(1001.0)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #27
0
 def test_log_with_log_a(self):
     """Test log10 scaling with a custom log_a."""
     log_a = 100
     norm = simple_norm(DATA2, stretch='log', log_a=log_a)
     ref = np.log10(log_a * DATA2SCL + 1.0) / np.log10(log_a + 1)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #28
0
 def test_log_with_log_a(self):
     """Test log10 scaling with a custom log_a."""
     log_a = 100
     norm = simple_norm(DATA2, stretch='log', log_a=log_a)
     ref = np.log10(log_a * DATA2SCL + 1.0) / np.log10(log_a + 1)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #29
0
 def test_asinh_with_asinh_a(self):
     """Test asinh scaling with a custom asinh_a."""
     asinh_a = 0.5
     norm = simple_norm(DATA2, stretch='asinh', asinh_a=asinh_a)
     ref = np.arcsinh(DATA2SCL / asinh_a) / np.arcsinh(1. / asinh_a)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #30
0
 def test_asinh(self):
     """Test asinh scaling."""
     norm = simple_norm(DATA2, stretch='asinh')
     ref = np.arcsinh(10 * DATA2SCL) / np.arcsinh(10)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)
Exemple #31
0
 def test_invalid_stretch(self):
     """Test invalid stretch keyword."""
     with pytest.raises(ValueError):
         simple_norm(DATA2, stretch='invalid')
Exemple #32
0
 def test_asinh_with_asinh_a(self):
     """Test asinh scaling with a custom asinh_a."""
     asinh_a = 0.5
     norm = simple_norm(DATA2, stretch='asinh', asinh_a=asinh_a)
     ref = np.arcsinh(DATA2SCL / asinh_a) / np.arcsinh(1. / asinh_a)
     assert_allclose(norm(DATA2), ref, atol=0, rtol=1.e-5)