Esempio n. 1
0
def Plot_Galaxy_Image(IMG, results, options):
    """
    Plots an LSB image of the object without anything else drawn above it.
    Useful for inspecting images for spurious features
    """
    
    if 'center' in results:
        center = results['center']
    elif 'ap_set_center' in options:
        center = options['ap_set_center']
    elif 'ap_guess_center' in options:
        center = options['ap_guess_center']
    else:
        center = {'x': IMG.shape[1]/2, 'y': IMG.shape[0]/2}

    if 'prof data' in results:
        edge = 1.2*results['prof data']['R'][-1]/options['pixscale']
    elif 'init R' in results:
        edge = 3*results['init R']
    elif 'fit R' in results:
        edge = 2*results['fit R']
    else:
        edge = max(IMG.shape)/2
    edge = min([edge, abs(center['x'] - IMG.shape[1]), center['x'], abs(center['y'] - IMG.shape[0]), center['y']])
        
    ranges = [[max(0,int(center['x']-edge)), min(IMG.shape[1],int(center['x']+edge))],
              [max(0,int(center['y']-edge)), min(IMG.shape[0],int(center['y']+edge))]]
        
    LSBImage(IMG[ranges[1][0]:ranges[1][1],ranges[0][0]:ranges[0][1]] - results['background'], results['background noise'])
    if not ('ap_nologo' in options and options['ap_nologo']):
        AddLogo(plt.gcf())
    plt.savefig('%sclean_image_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
    plt.close()
    
    return IMG, {}
Esempio n. 2
0
def Plot_PSF_Stars(
    IMG, stars_x, stars_y, stars_fwhm, psf, results, options, flagstars=None
):
    LSBImage(IMG - results["background"], results["background noise"])
    AddScale(plt.gca(), IMG.shape[0]*options['ap_pixscale'])
    for i in range(len(stars_fwhm)):
        plt.gca().add_patch(
            Ellipse(
                (stars_x[i], stars_y[i]),
                20 * psf,
                20 * psf,
                0,
                fill=False,
                linewidth=1.5,
                color=autocolours["red1"]
                if not flagstars is None and flagstars[i]
                else autocolours["blue1"],
            )
        )
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "PSF_Stars_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 3
0
def Photutils_Fit(IMG, results, options):
    """
    Function to run the photutils automated isophote analysis on an image.
    """

    dat = IMG - results['background']
    geo = EllipseGeometry(x0=results['center']['x'],
                          y0=results['center']['y'],
                          sma=results['init R'] / 2,
                          eps=results['init ellip'],
                          pa=results['init pa'])
    ellipse = Photutils_Ellipse(dat, geometry=geo)

    isolist = ellipse.fit_image(fix_center=True, linear=False)
    res = {
        'fit R': isolist.sma[1:],
        'fit ellip': isolist.eps[1:],
        'fit ellip_err': isolist.ellip_err[1:],
        'fit pa': isolist.pa[1:],
        'fit pa_err': isolist.pa_err[1:],
        'auxfile fitlimit':
        'fit limit semi-major axis: %.2f pix' % isolist.sma[-1]
    }

    if 'ap_doplot' in options and options['ap_doplot']:
        ranges = [[
            max(0, int(results['center']['y'] - res['fit R'][-1] * 1.2)),
            min(dat.shape[1],
                int(results['center']['y'] + res['fit R'][-1] * 1.2))
        ],
                  [
                      max(0,
                          int(results['center']['x'] -
                              res['fit R'][-1] * 1.2)),
                      min(dat.shape[0],
                          int(results['center']['x'] + res['fit R'][-1] * 1.2))
                  ]]
        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        for i in range(len(res['fit R'])):
            plt.gca().add_patch(
                Ellipse(
                    (int(res['fit R'][-1] * 1.2), int(res['fit R'][-1] * 1.2)),
                    2 * res['fit R'][i],
                    2 * res['fit R'][i] * (1. - res['fit ellip'][i]),
                    res['fit pa'][i] * 180 / np.pi,
                    fill=False,
                    linewidth=0.5,
                    color='r'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sfit_ellipse_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=300)
        plt.close()

    return IMG, res
Esempio n. 4
0
def Plot_Phase_Profile(R, parameters, results, options):
    for i in range(len(parameters)):
        if not "m" in parameters[i]:
            parameters[i]["m"] = None

    fig = plt.figure()
    if not parameters[0]["m"] is None:
        fig.add_subplot(2, 1, 1)
    else:
        fig.add_subplot(1, 1, 1)
    plt.plot(
        R,
        list(p["ellip"] for p in parameters),
        label="e [1 - b/a]",
        color=autocolours["red1"],
    )
    plt.plot(
        R,
        list(p["pa"] / np.pi for p in parameters),
        label="PA [rad/$\\pi$]",
        color=autocolours["blue1"],
    )
    plt.legend(fontsize=11)
    plt.xlabel("Semi-Major-Axis [arcsec]", fontsize=16)
    plt.xscale("log")
    plt.tick_params(labelsize=14)
    if not parameters[0]["m"] is None:
        plt.xlabel("")
        fig.add_subplot(2, 1, 2)
        plt.subplots_adjust(hspace=0)
        for m in range(len(parameters[0]["m"])):
            plt.plot(
                R,
                list(p["Am"][m] for p in parameters),
                label="A$_%i$" % parameters[0]["m"][m],
            )
            plt.plot(
                R,
                list(
                    p["Phim"][m] / (np.pi * parameters[0]["m"][m]) for p in parameters
                ),
                label="$\\phi_%i$ [rad/%i$\\pi$]"
                % (parameters[0]["m"][m], parameters[0]["m"][m]),
            )
        plt.legend()
        plt.xlabel("Semi-Major-Axis [arcsec]", fontsize=16)
        plt.xscale("log")
        plt.tick_params(labelsize=14)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "phase_profile_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 5
0
def Plot_Isophote_Init_Ellipse(dat, circ_ellipse_radii, ellip, phase, results, options):
    ranges = [
        [
            max(0, int(results["center"]["x"] - circ_ellipse_radii[-1] * 1.5)),
            min(
                dat.shape[1], int(results["center"]["x"] + circ_ellipse_radii[-1] * 1.5)
            ),
        ],
        [
            max(0, int(results["center"]["y"] - circ_ellipse_radii[-1] * 1.5)),
            min(
                dat.shape[0], int(results["center"]["y"] + circ_ellipse_radii[-1] * 1.5)
            ),
        ],
    ]

    LSBImage(
        dat[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]],
        results["background noise"],
    )
    AddScale(plt.gca(), (ranges[0][1] - ranges[0][0])*options['ap_pixscale'])
    plt.gca().add_patch(
        Ellipse(
            (
                results["center"]["x"] - ranges[0][0],
                results["center"]["y"] - ranges[1][0],
            ),
            2 * circ_ellipse_radii[-1],
            2 * circ_ellipse_radii[-1] * (1.0 - ellip),
            phase * 180 / np.pi,
            fill=False,
            linewidth=1,
            color=autocolours["blue1"],
        )
    )
    plt.plot(
        [results["center"]["x"] - ranges[0][0]],
        [results["center"]["y"] - ranges[1][0]],
        marker="x",
        markersize=3,
        color=autocolours["red1"],
    )
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "initialize_ellipse_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 6
0
def Mask_Segmentation_Map(IMG, results, options):

    if 'ap_mask_file' not in options or options['ap_mask_file'] is None:
        mask = np.zeros(IMG.shape, dtype=bool)
    else:
        mask = Read_Image(options['ap_mask_file'], options)

    if 'center' in results:
        if mask[int(results['center']['y']),
                int(results['center']['x'])] > 1.1:
            mask[mask == mask[int(results['center']['y']),
                              int(results['center']['x'])]] = 0
    elif 'ap_set_center' in options:
        if mask[int(options['ap_set_center']['y']),
                int(options['ap_set_center']['x'])] > 1.1:
            mask[mask == mask[int(options['ap_set_center']['y']),
                              int(options['ap_set_center']['x'])]] = 0
    elif 'ap_guess_center' in options:
        if mask[int(options['ap_guess_center']['y']),
                int(options['ap_guess_center']['x'])] > 1.1:
            mask[mask == mask[int(options['ap_guess_center']['y']),
                              int(options['ap_guess_center']['x'])]] = 0
    elif mask[int(IMG.shape[0] / 2), int(IMG.shape[1] / 2)] > 1.1:
        mask[mask == mask[int(IMG.shape[0] / 2), int(IMG.shape[1] / 2)]] = 0

    # Plot star mask for diagnostic purposes
    if 'ap_doplot' in options and options['ap_doplot']:
        bkgrnd = results[
            'background'] if 'background' in results else np.median(IMG)
        noise = results[
            'background noise'] if 'background noise' in results else iqr(
                IMG, rng=[16, 84]) / 2
        LSBImage(IMG - bkgrnd, noise)
        showmask = np.copy(mask)
        showmask[showmask > 1] = 1
        showmask[showmask < 1] = np.nan
        plt.imshow(showmask, origin='lower', cmap='Reds_r', alpha=0.5)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%smask_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']))
        plt.close()

    return IMG, {'mask': mask.astype(bool)}
Esempio n. 7
0
def Plot_Isophote_Init_Optimize(
    circ_ellipse_radii,
    allphase,
    phase,
    pa_err,
    test_ellip,
    test_f2,
    ellip,
    ellip_err,
    results,
    options,
):
    fig, ax = plt.subplots(2, 1, figsize=(6, 6))
    plt.subplots_adjust(hspace=0.01, wspace=0.01)
    ax[0].plot(
        circ_ellipse_radii[:-1],
        ((-np.angle(allphase) / 2) % np.pi) * 180 / np.pi,
        color="k",
    )
    ax[0].axhline(phase * 180 / np.pi, color="r")
    ax[0].axhline((phase + pa_err) * 180 / np.pi, color="r", linestyle="--")
    ax[0].axhline((phase - pa_err) * 180 / np.pi, color="r", linestyle="--")
    # ax[0].axvline(circ_ellipse_radii[-2], color = 'orange', linestyle = '--')
    ax[0].set_xlabel("Radius [pix]", fontsize=16)
    ax[0].set_ylabel("FFT$_{1}$ phase [deg]", fontsize=16)
    ax[0].tick_params(labelsize=12)
    ax[1].plot(test_ellip, test_f2, color="k")
    ax[1].axvline(ellip, color="r")
    ax[1].axvline(ellip + ellip_err, color="r", linestyle="--")
    ax[1].axvline(ellip - ellip_err, color="r", linestyle="--")
    ax[1].set_xlabel("Ellipticity [1 - b/a]", fontsize=16)
    ax[1].set_ylabel("Loss [FFT$_{2}$/med(flux)]", fontsize=16)
    ax[1].tick_params(labelsize=14)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "initialize_ellipse_optimize_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 8
0
def Plot_Background(values, bkgrnd, noise, results, options):

    hist, bins = np.histogram(
        values[
            np.logical_and(
                (values - bkgrnd) < 20 * noise, (values - bkgrnd) > -5 * noise
            )
        ],
        bins=max(10, int(np.sqrt(len(values)) / 2)),
    )
    plt.figure(figsize=(5, 5))
    plt.bar(
        bins[:-1],
        np.log10(np.where(hist > 0, hist, np.nan)),
        width=bins[1] - bins[0],
        color="k",
        label="pixel values",
    )
    plt.axvline(bkgrnd, color="#84DCCF", label="sky level: %.5e" % bkgrnd)
    plt.axvline(
        bkgrnd - noise,
        color="#84DCCF",
        linewidth=0.7,
        linestyle="--",
        label="1$\\sigma$ noise/pix: %.5e" % noise,
    )
    plt.axvline(bkgrnd + noise, color="#84DCCF", linewidth=0.7, linestyle="--")
    plt.xlim([bkgrnd - 5 * noise, bkgrnd + 20 * noise])
    plt.legend(fontsize=12)
    plt.tick_params(labelsize=12)
    plt.xlabel("Pixel Flux", fontsize=16)
    plt.ylabel("log$_{10}$(count)", fontsize=16)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "Background_hist_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 9
0
def Axial_Profiles(IMG, results, options):

    mask = results['mask'] if 'mask' in results else None
    pa = results['init pa'] + ((options['ap_axialprof_pa'] * np.pi /
                                180) if 'ap_axialprof_pa' in options else 0.)
    dat = IMG - results['background']
    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5

    if 'prof data' in results:
        Rproflim = results['prof data']['R'][-1] / options['ap_pixscale']
    else:
        Rproflim = min(IMG.shape) / 2

    R = [0]
    while R[-1] < Rproflim:
        if 'ap_samplestyle' in options and options[
                'ap_samplestyle'] == 'linear':
            step = options[
                'ap_samplelinearscale'] if 'ap_samplelinearscale' in options else 0.5 * results[
                    'psf fwhm']
        else:
            step = R[-1] * (options['ap_samplegeometricscale']
                            if 'ap_samplegeometricscale' in options else 0.1)
        R.append(R[-1] + max(1, step))

    sb = {}
    sbE = {}
    for rd in [1, -1]:
        for ang in [1, -1]:
            key = (rd, ang)
            sb[key] = []
            sbE[key] = []
            branch_pa = (pa + ang * np.pi / 2) % (2 * np.pi)
            for pi, pR in enumerate(R):
                sb[key].append([])
                sbE[key].append([])
                width = (R[pi] - R[pi - 1]) if pi > 0 else 1.
                flux, XX = _iso_line(
                    dat, R[-1], width, branch_pa, {
                        'x':
                        results['center']['x'] +
                        ang * rd * pR * np.cos(pa + (0 if ang > 0 else np.pi)),
                        'y':
                        results['center']['y'] +
                        ang * rd * pR * np.sin(pa + (0 if ang > 0 else np.pi))
                    })
                for oi, oR in enumerate(R):
                    length = (R[oi] - R[oi - 1]) if oi > 0 else 1.
                    CHOOSE = np.logical_and(XX > (oR - length / 2), XX <
                                            (oR + length / 2))
                    if np.sum(CHOOSE) == 0:
                        sb[key][-1].append(99.999)
                        sbE[key][-1].append(99.999)
                        continue
                    medflux = _average(
                        flux[CHOOSE], options['ap_isoaverage_method']
                        if 'ap_isoaverage_method' in options else 'median')
                    scatflux = _scatter(
                        flux[CHOOSE], options['ap_isoaverage_method']
                        if 'ap_isoaverage_method' in options else 'median')
                    sb[key][-1].append(
                        flux_to_sb(medflux, options['ap_pixscale'], zeropoint
                                   ) if medflux > 0 else 99.999)
                    sbE[key][-1].append((
                        2.5 * scatflux /
                        (np.sqrt(np.sum(CHOOSE)) * medflux *
                         np.log(10))) if medflux > 0 else 99.999)

    with open(
            '%s%s_axial_profile_AP.prof' %
        ((options['ap_saveto'] if 'ap_saveto' in options else ''),
         options['ap_name']), 'w') as f:
        f.write('R')
        for rd in [1, -1]:
            for ang in [1, -1]:
                for pR in R:
                    f.write(',sb[%.3f:%s90],sbE[%.3f:%s90]' %
                            (rd * pR * options['ap_pixscale'],
                             '+' if ang > 0 else '-', rd * pR *
                             options['ap_pixscale'], '+' if ang > 0 else '-'))
        f.write('\n')
        f.write('arcsec')
        for rd in [1, -1]:
            for ang in [1, -1]:
                for pR in R:
                    f.write(',mag*arcsec^-2,mag*arcsec^-2')
        f.write('\n')
        for oi, oR in enumerate(R):
            f.write('%.4f' % (oR * options['ap_pixscale']))
            for rd in [1, -1]:
                for ang in [1, -1]:
                    key = (rd, ang)
                    for pi, pR in enumerate(R):
                        f.write(',%.4f,%.4f' %
                                (sb[key][pi][oi], sbE[key][pi][oi]))
            f.write('\n')

    if 'ap_doplot' in options and options['ap_doplot']:

        #colours = {(1,1): 'cool', (1,-1): 'summer', (-1,1): 'autumn', (-1,-1): 'winter'}
        count = 0
        for rd in [1, -1]:
            for ang in [1, -1]:
                key = (rd, ang)
                #cmap = matplotlib.cm.get_cmap('viridis_r')
                norm = matplotlib.colors.Normalize(vmin=0,
                                                   vmax=R[-1] *
                                                   options['ap_pixscale'])
                for pi, pR in enumerate(R):
                    if pi % 3 != 0:
                        continue
                    CHOOSE = np.logical_and(
                        np.array(sb[key][pi]) < 99,
                        np.array(sbE[key][pi]) < 1)
                    plt.errorbar(np.array(R)[CHOOSE] * options['ap_pixscale'],
                                 np.array(sb[key][pi])[CHOOSE],
                                 yerr=np.array(sbE[key][pi])[CHOOSE],
                                 elinewidth=1,
                                 linewidth=0,
                                 marker='.',
                                 markersize=3,
                                 color=autocmap.reversed()(norm(
                                     pR * options['ap_pixscale'])))
                plt.xlabel('%s-axis position on line [arcsec]' %
                           ('Major' if 'ap_axialprof_parallel' in options
                            and options['ap_axialprof_parallel'] else 'Minor'),
                           fontsize=16)
                plt.ylabel('Surface Brightness [mag arcsec$^{-2}$]',
                           fontsize=16)
                # cb1 = matplotlib.colorbar.ColorbarBase(plt.gca(), cmap=cmap,
                #                                        norm=norm)
                cb1 = plt.colorbar(
                    matplotlib.cm.ScalarMappable(norm=norm,
                                                 cmap=autocmap.reversed()))
                cb1.set_label(
                    '%s-axis position of line [arcsec]' %
                    ('Minor' if 'ap_axialprof_parallel' in options
                     and options['ap_axialprof_parallel'] else 'Major'),
                    fontsize=16)
                # plt.colorbar()
                bkgrdnoise = -2.5 * np.log10(
                    results['background noise']) + zeropoint + 2.5 * np.log10(
                        options['ap_pixscale']**2)
                plt.axhline(
                    bkgrdnoise,
                    color='purple',
                    linewidth=0.5,
                    linestyle='--',
                    label='1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$' %
                    bkgrdnoise)
                plt.gca().invert_yaxis()
                plt.legend(fontsize=15)
                plt.tick_params(labelsize=14)
                plt.title('%sR : pa%s90' %
                          ('+' if rd > 0 else '-', '+' if ang > 0 else '-'),
                          fontsize=15)
                plt.tight_layout()
                if not ('ap_nologo' in options and options['ap_nologo']):
                    AddLogo(plt.gcf())
                plt.savefig('%saxial_profile_q%i_%s.jpg' %
                            (options['ap_plotpath'] if 'ap_plotpath' in options
                             else '', count, options['ap_name']),
                            dpi=options['ap_plotdpi']
                            if 'ap_plotdpi' in options else 300)
                plt.close()
                count += 1

        CHOOSE = np.array(results['prof data']['SB_e']) < 0.2
        firstbad = np.argmax(np.logical_not(CHOOSE))
        if firstbad > 3:
            CHOOSE[firstbad:] = False
        outto = np.array(results['prof data']
                         ['R'])[CHOOSE][-1] * 1.5 / options['ap_pixscale']
        ranges = [[
            max(0, int(results['center']['x'] - outto - 2)),
            min(IMG.shape[1], int(results['center']['x'] + outto + 2))
        ],
                  [
                      max(0, int(results['center']['y'] - outto - 2)),
                      min(IMG.shape[0],
                          int(results['center']['y'] + outto + 2))
                  ]]
        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        count = 0
        cmap = matplotlib.cm.get_cmap('hsv')
        colorind = (np.linspace(0, 1 - 1 / 4, 4) + 0.1) % 1
        colours = list(cmap(c)
                       for c in colorind)  #['b', 'r', 'orange', 'limegreen']
        for rd in [1, -1]:
            for ang in [1, -1]:
                key = (rd, ang)
                branch_pa = (pa + ang * np.pi / 2) % (2 * np.pi)
                for pi, pR in enumerate(R):
                    if pi % 3 != 0:
                        continue
                    start = np.array([
                        results['center']['x'] +
                        ang * rd * pR * np.cos(pa + (0 if ang > 0 else np.pi)),
                        results['center']['y'] +
                        ang * rd * pR * np.sin(pa + (0 if ang > 0 else np.pi))
                    ])
                    end = start + R[-1] * np.array(
                        [np.cos(branch_pa),
                         np.sin(branch_pa)])
                    start -= np.array([ranges[0][0], ranges[1][0]])
                    end -= np.array([ranges[0][0], ranges[1][0]])
                    plt.plot(
                        [start[0], end[0]], [start[1], end[1]],
                        linewidth=0.5,
                        color=colours[count],
                        label=('%sR : pa%s90' %
                               ('+' if rd > 0 else '-',
                                '+' if ang > 0 else '-')) if pi == 0 else None)
                count += 1
        plt.legend()
        plt.xlim([0, ranges[0][1] - ranges[0][0]])
        plt.ylim([0, ranges[1][1] - ranges[1][0]])
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%saxial_profile_lines_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    return IMG, {}
Esempio n. 10
0
def Isophote_Initialize(IMG, results, options):
    """
    Determine the global pa and ellipticity for a galaxy. First grow circular isophotes
    until reaching near the noise floor, then evaluate the phase of the second FFT
    coefficients and determine the average direction. Then fit an ellipticity for one
    of the outer isophotes.
    """

    ######################################################################
    # Initial attempt to find size of galaxy in image
    # based on when isophotes SB values start to get
    # close to the background noise level
    circ_ellipse_radii = [results['psf fwhm']]
    allphase = []
    dat = IMG - results['background']

    while circ_ellipse_radii[-1] < (len(IMG) / 2):
        circ_ellipse_radii.append(circ_ellipse_radii[-1] * (1 + 0.2))
        isovals = _iso_extract(dat,
                               circ_ellipse_radii[-1],
                               0.,
                               0.,
                               results['center'],
                               more=True,
                               sigmaclip=True,
                               sclip_nsigma=3,
                               interp_mask=True)
        coefs = fft(isovals[0])
        allphase.append(coefs[2])
        # Stop when at 3 time background noise
        if np.quantile(isovals[0], 0.8) < (3 * results['background noise']
                                           ) and len(circ_ellipse_radii) > 4:
            break
    logging.info('%s: init scale: %f pix' %
                 (options['ap_name'], circ_ellipse_radii[-1]))
    # Find global position angle.
    phase = (-Angle_Median(np.angle(allphase[-5:])) / 2) % np.pi

    # Find global ellipticity
    test_ellip = np.linspace(0.05, 0.95, 15)
    test_f2 = []
    for e in test_ellip:
        test_f2.append(
            sum(
                list(
                    _fitEllip_loss(e, dat, circ_ellipse_radii[-2] *
                                   m, phase, results['center'],
                                   results['background noise'])
                    for m in np.linspace(0.8, 1.2, 5))))
    ellip = test_ellip[np.argmin(test_f2)]
    res = minimize(lambda e, d, r, p, c, n: sum(
        list(
            _fitEllip_loss(_x_to_eps(e[0]), d, r * m, p, c, n)
            for m in np.linspace(0.8, 1.2, 5))),
                   x0=_inv_x_to_eps(ellip),
                   args=(dat, circ_ellipse_radii[-2], phase, results['center'],
                         results['background noise']),
                   method='Nelder-Mead',
                   options={
                       'initial_simplex': [[_inv_x_to_eps(ellip) - 1 / 15],
                                           [_inv_x_to_eps(ellip) + 1 / 15]]
                   })
    if res.success:
        logging.debug(
            '%s: using optimal ellipticity %.3f over grid ellipticity %.3f' %
            (options['ap_name'], _x_to_eps(res.x[0]), ellip))
        ellip = _x_to_eps(res.x[0])

    # Compute the error on the parameters
    ######################################################################
    RR = np.linspace(circ_ellipse_radii[-2] - results['psf fwhm'],
                     circ_ellipse_radii[-2] + results['psf fwhm'], 10)
    errallphase = []
    for rr in RR:
        isovals = _iso_extract(dat,
                               rr,
                               0.,
                               0.,
                               results['center'],
                               more=True,
                               sigmaclip=True,
                               sclip_nsigma=3,
                               interp_mask=True)
        coefs = fft(isovals[0])
        errallphase.append(coefs[2])
    sample_pas = (-np.angle(1j * np.array(errallphase) / np.mean(errallphase))
                  / 2) % np.pi
    pa_err = iqr(sample_pas, rng=[16, 84]) / 2
    res_multi = map(
        lambda rrp: minimize(lambda e, d, r, p, c, n: _fitEllip_loss(
            _x_to_eps(e[0]), d, r, p, c, n),
                             x0=_inv_x_to_eps(ellip),
                             args=(dat, rrp[0], rrp[1], results['center'],
                                   results['background noise']),
                             method='Nelder-Mead',
                             options={
                                 'initial_simplex': [[
                                     _inv_x_to_eps(ellip) - 1 / 15
                                 ], [_inv_x_to_eps(ellip) + 1 / 15]]
                             }), zip(RR, sample_pas))
    ellip_err = iqr(list(_x_to_eps(rm.x[0])
                         for rm in res_multi), rng=[16, 84]) / 2

    circ_ellipse_radii = np.array(circ_ellipse_radii)

    if 'ap_doplot' in options and options['ap_doplot']:

        ranges = [
            [
                max(0,
                    int(results['center']['x'] -
                        circ_ellipse_radii[-1] * 1.5)),
                min(dat.shape[1],
                    int(results['center']['x'] + circ_ellipse_radii[-1] * 1.5))
            ],
            [
                max(0,
                    int(results['center']['y'] -
                        circ_ellipse_radii[-1] * 1.5)),
                min(dat.shape[0],
                    int(results['center']['y'] + circ_ellipse_radii[-1] * 1.5))
            ]
        ]

        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        # plt.imshow(np.clip(dat[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]],a_min = 0, a_max = None),
        #            origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        plt.gca().add_patch(
            Ellipse((results['center']['x'] - ranges[0][0],
                     results['center']['y'] - ranges[1][0]),
                    2 * circ_ellipse_radii[-1],
                    2 * circ_ellipse_radii[-1] * (1. - ellip),
                    phase * 180 / np.pi,
                    fill=False,
                    linewidth=1,
                    color='y'))
        plt.plot([results['center']['x'] - ranges[0][0]],
                 [results['center']['y'] - ranges[1][0]],
                 marker='x',
                 markersize=3,
                 color='r')
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sinitialize_ellipse_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        fig, ax = plt.subplots(2, 1, figsize=(6, 6))
        plt.subplots_adjust(hspace=0.01, wspace=0.01)
        ax[0].plot(circ_ellipse_radii[:-1],
                   ((-np.angle(allphase) / 2) % np.pi) * 180 / np.pi,
                   color='k')
        ax[0].axhline(phase * 180 / np.pi, color='r')
        ax[0].axhline((phase + pa_err) * 180 / np.pi,
                      color='r',
                      linestyle='--')
        ax[0].axhline((phase - pa_err) * 180 / np.pi,
                      color='r',
                      linestyle='--')
        #ax[0].axvline(circ_ellipse_radii[-2], color = 'orange', linestyle = '--')
        ax[0].set_xlabel('Radius [pix]', fontsize=16)
        ax[0].set_ylabel('FFT$_{1}$ phase [deg]', fontsize=16)
        ax[0].tick_params(labelsize=12)
        ax[1].plot(test_ellip, test_f2, color='k')
        ax[1].axvline(ellip, color='r')
        ax[1].axvline(ellip + ellip_err, color='r', linestyle='--')
        ax[1].axvline(ellip - ellip_err, color='r', linestyle='--')
        ax[1].set_xlabel('Ellipticity [1 - b/a]', fontsize=16)
        ax[1].set_ylabel('Loss [FFT$_{2}$/med(flux)]', fontsize=16)
        ax[1].tick_params(labelsize=14)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sinitialize_ellipse_optimize_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    auxmessage = 'global ellipticity: %.3f +- %.3f, pa: %.3f +- %.3f deg, size: %f pix' % (
        ellip, ellip_err, PA_shift_convention(phase) * 180 / np.pi,
        pa_err * 180 / np.pi, circ_ellipse_radii[-2])
    return IMG, {
        'init ellip': ellip,
        'init ellip_err': ellip_err,
        'init pa': phase,
        'init pa_err': pa_err,
        'init R': circ_ellipse_radii[-2],
        'auxfile initialize': auxmessage
    }
Esempio n. 11
0
def EllipseModel_General(IMG, results, options):

    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5

    CHOOSE = np.array(results['prof data']['SB_e']) < 0.5
    R = np.array(results['prof data']['R'])[CHOOSE] / options['ap_pixscale']

    sb = UnivariateSpline(np.log10(R),
                          np.array(results['prof data']['SB'])[CHOOSE],
                          ext=3,
                          s=0)
    pa = UnivariateSpline(np.log10(R),
                          np.array(results['prof data']['pa'])[CHOOSE] *
                          np.pi / 180,
                          ext=3,
                          s=0)
    q = UnivariateSpline(np.log10(R),
                         1 - np.array(results['prof data']['ellip'])[CHOOSE],
                         ext=3,
                         s=0)

    ranges = [[
        max(0, int(results['center']['x'] - R[-1] - 2)),
        min(IMG.shape[1], int(results['center']['x'] + R[-1] + 2))
    ],
              [
                  max(0, int(results['center']['y'] - R[-1] - 2)),
                  min(IMG.shape[0], int(results['center']['y'] + R[-1] + 2))
              ]]

    XX, YY = np.meshgrid(
        np.arange(ranges[0][1] - ranges[0][0], dtype=float),
        np.arange(ranges[1][1] - ranges[1][0], dtype=np.float32))
    XX -= results['center']['x'] - float(ranges[0][0])
    YY -= results['center']['y'] - float(ranges[1][0])
    MM = np.zeros(XX.shape, dtype=np.float32)
    Prox = np.zeros(XX.shape, dtype=np.float32) + np.inf
    WINDOW = [[0, XX.shape[0]], [0, XX.shape[1]]]
    for r in reversed(
            np.logspace(
                np.log10(R[0] / 2), np.log10(R[-1]),
                int(
                    len(R) * 2 *
                    (option['ap_ellipsemodel_resolution']
                     if 'ap_ellipsemodel_resolution' in options else 1)))):
        if r < (R[-1] / 2):
            WINDOW = [[
                max(
                    0,
                    int(results['center']['y'] - float(ranges[1][0]) -
                        r * 1.5)),
                min(
                    XX.shape[0],
                    int(results['center']['y'] - float(ranges[1][0]) +
                        r * 1.5))
            ],
                      [
                          max(
                              0,
                              int(results['center']['x'] -
                                  float(ranges[0][0]) - r * 1.5)),
                          min(
                              XX.shape[1],
                              int(results['center']['x'] -
                                  float(ranges[0][0]) + r * 1.5))
                      ]]

        RR = np.sqrt((XX[WINDOW[0][0]:WINDOW[0][1],WINDOW[1][0]:WINDOW[1][1]]*np.cos(-pa(np.log10(r))) - YY[WINDOW[0][0]:WINDOW[0][1],WINDOW[1][0]:WINDOW[1][1]]*np.sin(-pa(np.log10(r))))**2 + \
                     ((XX[WINDOW[0][0]:WINDOW[0][1],WINDOW[1][0]:WINDOW[1][1]]*np.sin(-pa(np.log10(r))) + YY[WINDOW[0][0]:WINDOW[0][1],WINDOW[1][0]:WINDOW[1][1]]*np.cos(-pa(np.log10(r))))/np.clip(q(np.log10(r)),a_min = 0.03,a_max = 1))**2)
        D = np.abs(RR - r)
        CLOSE = D < Prox[WINDOW[0][0]:WINDOW[0][1], WINDOW[1][0]:WINDOW[1][1]]
        if np.any(CLOSE):
            MM[WINDOW[0][0]:WINDOW[0][1],
               WINDOW[1][0]:WINDOW[1][1]][CLOSE] = sb(np.log10(RR[CLOSE]))
            Prox[WINDOW[0][0]:WINDOW[0][1],
                 WINDOW[1][0]:WINDOW[1][1]][CLOSE] = D[CLOSE]

    MM = 10**(-(MM - zeropoint - 5 * np.log10(options['ap_pixscale'])) / 2.5)
    RR = np.sqrt((XX * np.cos(-pa(np.log10(R[-1]))) -
                  YY * np.sin(-pa(np.log10(R[-1]))))**2 +
                 ((XX * np.sin(-pa(np.log10(R[-1]))) +
                   YY * np.cos(-pa(np.log10(R[-1])))) /
                  np.clip(q(np.log10(R[-1])), a_min=0.03, a_max=1))**2)
    MM[RR > R[-1]] = 0

    Model = np.zeros(IMG.shape, dtype=np.float32)
    Model[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]] = MM

    header = fits.Header()
    hdul = fits.HDUList([fits.PrimaryHDU(header=header), fits.ImageHDU(Model)])

    hdul.writeto('%s%s_genmodel.fits' %
                 (options['ap_plotpath'] if 'ap_plotpath' in options else '',
                  options['ap_name']),
                 overwrite=True)

    if 'ap_doplot' in options and options['ap_doplot']:
        ranges = [[
            max(0, int(results['center']['x'] - R[-1] * 1.2)),
            min(IMG.shape[1], int(results['center']['x'] + R[-1] * 1.2))
        ],
                  [
                      max(0, int(results['center']['y'] - R[-1] * 1.2)),
                      min(IMG.shape[0],
                          int(results['center']['y'] + R[-1] * 1.2))
                  ]]
        plt.figure(figsize=(7, 7))
        autocmap.set_under('k', alpha=0)
        showmodel = Model[ranges[1][0]:ranges[1][1],
                          ranges[0][0]:ranges[0][1]].copy()
        showmodel[showmodel > 0] += np.max(showmodel) / (10**3.5) - np.min(
            showmodel[showmodel > 0])
        plt.imshow(showmodel,
                   origin='lower',
                   cmap=autocmap,
                   norm=ImageNormalize(stretch=LogStretch(), clip=False))
        plt.axis('off')
        plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sellipsemodel_gen_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        residual = IMG[ranges[1][0]:ranges[1][1],
                       ranges[0][0]:ranges[0][1]] - results[
                           'background'] - Model[ranges[1][0]:ranges[1][1],
                                                 ranges[0][0]:ranges[0][1]]
        plt.figure(figsize=(7, 7))
        plt.imshow(residual,
                   origin='lower',
                   cmap='PuBu',
                   vmin=np.quantile(residual, 0.0001),
                   vmax=0)
        plt.imshow(np.clip(residual,
                           a_min=0,
                           a_max=np.quantile(residual, 0.9999)),
                   origin='lower',
                   cmap=autocmap,
                   norm=ImageNormalize(stretch=LogStretch(), clip=False),
                   interpolation='none',
                   clim=[1e-5, None])
        plt.axis('off')
        plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sellipseresidual_gen_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    if 'ap_paperplots' in options and options['ap_paperplots']:
        plt.figure(figsize=(7, 7))
        LSBImage(
            IMG[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]] -
            results['background'], results['background noise'])
        plt.axis('off')
        plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
        plt.savefig(
            '%sclearimage_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    return IMG, {'ellipse model': Model}
Esempio n. 12
0
def Plot_I_Profile(dat, R, I, I_e, parameters, results, options):

    CHOOSE = np.isfinite(I)
    if np.sum(CHOOSE) < 5:
        CHOOSE = np.ones(len(CHOOSE), dtype=bool)
    errscale = 1.0
    lnlist = []
    lnlist.append(
        plt.errorbar(
            R[CHOOSE],
            I[CHOOSE],
            yerr=errscale * I_e[CHOOSE],
            elinewidth=1,
            linewidth=0,
            marker=".",
            markersize=5,
            color=autocolours["red1"],
            label="Intensity (err$\\cdot$%.1f)" % errscale,
        )
    )
    plt.errorbar(
        R[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        I[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        yerr=I_e[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        elinewidth=1,
        linewidth=0,
        marker=".",
        markersize=5,
        color=autocolours["blue1"],
    )
    plt.xlabel("Semi-Major-Axis [arcsec]", fontsize=16)
    plt.ylabel("Intensity [flux arcsec$^{-2}$]", fontsize=16)
    plt.yscale("log")
    if 'ap_plot_sbprof_xlim' in options:
        plt.xlim(options['ap_plot_sbprof_xlim'])
    else:
        plt.xlim([0, None])
    if 'ap_plot_sbprof_ylim' in options:
        plt.ylim(options['ap_plot_sbprof_ylim'])
    bkgrdnoise = results["background noise"] / (options["ap_pixscale"] ** 2)
    lnlist.append(
        plt.axhline(
            bkgrdnoise,
            color="purple",
            linewidth=0.5,
            linestyle="--",
            label="1$\\sigma$ noise/pixel: %.1f flux arcsec$^{-2}$" % bkgrdnoise,
        )
    )
    plt.tick_params(labelsize=14)
    labs = [l.get_label() for l in lnlist]
    plt.legend(lnlist, labs, fontsize=11)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "photometry_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()

    _Plot_Isophotes(
        dat,
        R[CHOOSE] / options["ap_pixscale"],
        list(compress(parameters, CHOOSE)),
        results,
        options,
    )
Esempio n. 13
0
def _Generate_Profile(IMG, results, R, E, Ee, PA, PAe, options):

    # Create image array with background and mask applied
    try:
        if np.any(results['mask']):
            mask = results['mask']
        else:
            mask = None
    except:
        mask = None
    dat = IMG - results['background']
    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5

    sb = []
    sbE = []
    cogdirect = []
    sbfix = []
    sbfixE = []

    count_neg = 0
    medflux = np.inf
    end_prof = None
    for i in range(len(R)):
        isobandwidth = R[i] * (options['ap_isoband_width']
                               if 'ap_isoband_width' in options else 0.025)
        if medflux > (results['background noise'] *
                      (options['ap_isoband_start'] if 'ap_isoband_start'
                       in options else 2)) or isobandwidth < 0.5:
            isovals = _iso_extract(
                dat,
                R[i],
                E[i],
                PA[i],
                results['center'],
                mask=mask,
                rad_interp=(options['ap_iso_interpolate_start']
                            if 'ap_iso_interpolate_start' in options else 5) *
                results['psf fwhm'],
                sigmaclip=options['ap_isoclip']
                if 'ap_isoclip' in options else False,
                sclip_iterations=options['ap_isoclip_iterations']
                if 'ap_isoclip_iterations' in options else 10,
                sclip_nsigma=options['ap_isoclip_nsigma']
                if 'ap_isoclip_nsigma' in options else 5)
            isovalsfix = _iso_extract(
                dat,
                R[i],
                results['init ellip'],
                results['init pa'],
                results['center'],
                mask=mask,
                rad_interp=(options['ap_iso_interpolate_start']
                            if 'ap_iso_interpolate_start' in options else 5) *
                results['psf fwhm'],
                sigmaclip=options['ap_isoclip']
                if 'ap_isoclip' in options else False,
                sclip_iterations=options['ap_isoclip_iterations']
                if 'ap_isoclip_iterations' in options else 10,
                sclip_nsigma=options['ap_isoclip_nsigma']
                if 'ap_isoclip_nsigma' in options else 5)
        else:
            isovals = _iso_between(
                dat,
                R[i] - isobandwidth,
                R[i] + isobandwidth,
                E[i],
                PA[i],
                results['center'],
                mask=mask,
                sigmaclip=options['ap_isoclip']
                if 'ap_isoclip' in options else False,
                sclip_iterations=options['ap_isoclip_iterations']
                if 'ap_isoclip_iterations' in options else 10,
                sclip_nsigma=options['ap_isoclip_nsigma']
                if 'ap_isoclip_nsigma' in options else 5)
            isovalsfix = _iso_between(
                dat,
                R[i] - isobandwidth,
                R[i] + isobandwidth,
                results['init ellip'],
                results['init pa'],
                results['center'],
                mask=mask,
                sigmaclip=options['ap_isoclip']
                if 'ap_isoclip' in options else False,
                sclip_iterations=options['ap_isoclip_iterations']
                if 'ap_isoclip_iterations' in options else 10,
                sclip_nsigma=options['ap_isoclip_nsigma']
                if 'ap_isoclip_nsigma' in options else 5)
        isotot = np.sum(
            _iso_between(dat,
                         0,
                         R[i],
                         E[i],
                         PA[i],
                         results['center'],
                         mask=mask))
        medflux = _average(
            isovals, options['ap_isoaverage_method']
            if 'ap_isoaverage_method' in options else 'median')
        scatflux = _scatter(
            isovals, options['ap_isoaverage_method']
            if 'ap_isoaverage_method' in options else 'median')
        medfluxfix = _average(
            isovalsfix, options['ap_isoaverage_method']
            if 'ap_isoaverage_method' in options else 'median')
        scatfluxfix = _scatter(
            isovalsfix, options['ap_isoaverage_method']
            if 'ap_isoaverage_method' in options else 'median')

        sb.append(
            flux_to_sb(medflux, options['ap_pixscale'], zeropoint
                       ) if medflux > 0 else 99.999)
        sbE.append((2.5 * scatflux / (np.sqrt(len(isovals)) * medflux *
                                      np.log(10))) if medflux > 0 else 99.999)
        sbfix.append(
            flux_to_sb(medfluxfix, options['ap_pixscale'], zeropoint
                       ) if medfluxfix > 0 else 99.999)
        sbfixE.append((2.5 * scatfluxfix /
                       (np.sqrt(len(isovalsfix)) * np.median(isovalsfix) *
                        np.log(10))) if medfluxfix > 0 else 99.999)
        cogdirect.append(
            flux_to_mag(isotot, zeropoint) if isotot > 0 else 99.999)
        if medflux <= 0:
            count_neg += 1
        if 'ap_truncate_evaluation' in options and options[
                'ap_truncate_evaluation'] and count_neg >= 2:
            end_prof = i + 1
            break

    # Compute Curve of Growth from SB profile
    cog, cogE = SBprof_to_COG_errorprop(R[:end_prof] * options['ap_pixscale'],
                                        np.array(sb),
                                        np.array(sbE),
                                        1. - E[:end_prof],
                                        Ee[:end_prof],
                                        N=100,
                                        method=0,
                                        symmetric_error=True)
    cogE[cog > 99] = 99.999
    cogfix, cogfixE = SBprof_to_COG_errorprop(R[:end_prof] *
                                              options['ap_pixscale'],
                                              np.array(sbfix),
                                              np.array(sbfixE),
                                              1. - E[:end_prof],
                                              Ee[:end_prof],
                                              N=100,
                                              method=0,
                                              symmetric_error=True)
    cogfixE[cogfix > 99] = 99.999

    # For each radius evaluation, write the profile parameters
    params = [
        'R', 'SB', 'SB_e', 'totmag', 'totmag_e', 'ellip', 'ellip_e', 'pa',
        'pa_e', 'totmag_direct', 'SB_fix', 'SB_fix_e', 'totmag_fix',
        'totmag_fix_e'
    ]

    SBprof_data = dict((h, None) for h in params)
    SBprof_units = {
        'R': 'arcsec',
        'SB': 'mag*arcsec^-2',
        'SB_e': 'mag*arcsec^-2',
        'totmag': 'mag',
        'totmag_e': 'mag',
        'ellip': 'unitless',
        'ellip_e': 'unitless',
        'pa': 'deg',
        'pa_e': 'deg',
        'totmag_direct': 'mag',
        'SB_fix': 'mag*arcsec^-2',
        'SB_fix_e': 'mag*arcsec^-2',
        'totmag_fix': 'mag',
        'totmag_fix_e': 'mag'
    }
    SBprof_format = {
        'R': '%.4f',
        'SB': '%.4f',
        'SB_e': '%.4f',
        'totmag': '%.4f',
        'totmag_e': '%.4f',
        'ellip': '%.3f',
        'ellip_e': '%.3f',
        'pa': '%.2f',
        'pa_e': '%.2f',
        'totmag_direct': '%.4f',
        'SB_fix': '%.4f',
        'SB_fix_e': '%.4f',
        'totmag_fix': '%.4f',
        'totmag_fix_e': '%.4f'
    }

    SBprof_data['R'] = list(R[:end_prof] * options['ap_pixscale'])
    SBprof_data['SB'] = list(sb)
    SBprof_data['SB_e'] = list(sbE)
    SBprof_data['totmag'] = list(cog)
    SBprof_data['totmag_e'] = list(cogE)
    SBprof_data['ellip'] = list(E[:end_prof])
    SBprof_data['ellip_e'] = list(Ee[:end_prof])
    SBprof_data['pa'] = list(PA[:end_prof] * 180 / np.pi)
    SBprof_data['pa_e'] = list(PAe[:end_prof] * 180 / np.pi)
    SBprof_data['totmag_direct'] = list(cogdirect)
    SBprof_data['SB_fix'] = list(sbfix)
    SBprof_data['SB_fix_e'] = list(sbfixE)
    SBprof_data['totmag_fix'] = list(cogfix)
    SBprof_data['totmag_fix_e'] = list(cogfixE)

    if 'ap_doplot' in options and options['ap_doplot']:
        CHOOSE = np.logical_and(
            np.array(SBprof_data['SB']) < 99,
            np.array(SBprof_data['SB_e']) < 1)
        errscale = 1.
        if np.all(np.array(SBprof_data['SB_e'])[CHOOSE] < 0.5):
            errscale = 1 / np.max(np.array(SBprof_data['SB_e'])[CHOOSE])
        lnlist = []
        lnlist.append(
            plt.errorbar(np.array(SBprof_data['R'])[CHOOSE],
                         np.array(SBprof_data['SB'])[CHOOSE],
                         yerr=errscale * np.array(SBprof_data['SB_e'])[CHOOSE],
                         elinewidth=1,
                         linewidth=0,
                         marker='.',
                         markersize=5,
                         color='r',
                         label='Surface Brightness (err$\\cdot$%.1f)' %
                         errscale))
        plt.errorbar(np.array(SBprof_data['R'])[np.logical_and(
            CHOOSE,
            np.arange(len(CHOOSE)) % 4 == 0)],
                     np.array(SBprof_data['SB'])[np.logical_and(
                         CHOOSE,
                         np.arange(len(CHOOSE)) % 4 == 0)],
                     yerr=np.array(SBprof_data['SB_e'])[np.logical_and(
                         CHOOSE,
                         np.arange(len(CHOOSE)) % 4 == 0)],
                     elinewidth=1,
                     linewidth=0,
                     marker='.',
                     markersize=5,
                     color='limegreen')
        # plt.errorbar(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['totmag'])[CHOOSE], yerr = np.array(SBprof_data['totmag_e'])[CHOOSE],
        #              elinewidth = 1, linewidth = 0, marker = '.', markersize = 5, color = 'orange', label = 'Curve of Growth')
        plt.xlabel('Semi-Major-Axis [arcsec]', fontsize=16)
        plt.ylabel('Surface Brightness [mag arcsec$^{-2}$]', fontsize=16)
        bkgrdnoise = -2.5 * np.log10(
            results['background noise']) + zeropoint + 2.5 * np.log10(
                options['ap_pixscale']**2)
        lnlist.append(
            plt.axhline(
                bkgrdnoise,
                color='purple',
                linewidth=0.5,
                linestyle='--',
                label='1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$' %
                bkgrdnoise))
        plt.gca().invert_yaxis()
        plt.tick_params(labelsize=14)
        # ax2 = plt.gca().twinx()
        # lnlist += ax2.plot(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['pa'])[CHOOSE]/180, color = 'b', label = 'PA/180')
        # lnlist += ax2.plot(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['ellip'])[CHOOSE], color = 'orange', linestyle = '--', label = 'ellipticity')
        labs = [l.get_label() for l in lnlist]
        plt.legend(lnlist, labs, fontsize=11)
        # ax2.set_ylabel('Position Angle, Ellipticity', fontsize = 16)
        # ax2.tick_params(labelsize = 14)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sphotometry_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        useR = np.array(SBprof_data['R'])[CHOOSE] / options['ap_pixscale']
        useE = np.array(SBprof_data['ellip'])[CHOOSE]
        usePA = np.array(SBprof_data['pa'])[CHOOSE]
        ranges = [[
            max(0, int(results['center']['x'] - useR[-1] * 1.2)),
            min(dat.shape[1], int(results['center']['x'] + useR[-1] * 1.2))
        ],
                  [
                      max(0, int(results['center']['y'] - useR[-1] * 1.2)),
                      min(dat.shape[0],
                          int(results['center']['y'] + useR[-1] * 1.2))
                  ]]
        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        for i in range(len(useR)):
            plt.gca().add_patch(
                Ellipse(
                    (results['center']['x'] - ranges[0][0],
                     results['center']['y'] - ranges[1][0]),
                    2 * useR[i],
                    2 * useR[i] * (1. - useE[i]),
                    usePA[i],
                    fill=False,
                    linewidth=((i + 1) / len(useR))**2,
                    color='limegreen' if (i % 4 == 0) else 'r',
                    linestyle='-' if useR[i] < results['fit R'][-1] else '--'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sphotometry_ellipse_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    return {
        'prof header': params,
        'prof units': SBprof_units,
        'prof data': SBprof_data,
        'prof format': SBprof_format
    }
Esempio n. 14
0
def Center_HillClimb(IMG, results, options):
    """
    Using 10 circular isophotes out to 10 times the PSF length, the first FFT coefficient
    phases are averaged to find the direction of increasing flux. Flux values are sampled
    along this direction and a quadratic fit gives the maximum. This is iteratively
    repeated until the step size becomes very small.
    """
    
    current_center = {'x': IMG.shape[1]/2, 'y': IMG.shape[0]/2}
    if 'ap_guess_center' in options:
        current_center = deepcopy(options['ap_guess_center'])
        logging.info('%s: Center initialized by user: %s' % (options['ap_name'], str(current_center)))
    if 'ap_set_center' in options:
        logging.info('%s: Center set by user: %s' % (options['ap_name'], str(options['ap_set_center'])))
        return IMG, {'center': deepcopy(options['ap_set_center'])}

    dat = IMG - results['background']

    sampleradii = np.linspace(1,10,10) * results['psf fwhm']

    track_centers = []
    small_update_count = 0
    total_count = 0
    while small_update_count <= 5 and total_count <= 100:
        total_count += 1
        phases = []
        isovals = []
        coefs = []
        for r in sampleradii:
            isovals.append(_iso_extract(dat,r,0.,0.,current_center, more = True))
            coefs.append(fft(np.clip(isovals[-1][0], a_max = np.quantile(isovals[-1][0],0.85), a_min = None)))
            phases.append((-np.angle(coefs[-1][1])) % (2*np.pi))
        direction = Angle_Median(phases) % (2*np.pi)
        levels = []
        level_locs = []
        for i, r in enumerate(sampleradii):
            floc = np.argmin(np.abs((isovals[i][1] % (2*np.pi)) - direction))
            rloc = np.argmin(np.abs((isovals[i][1] % (2*np.pi)) - ((direction+np.pi) % (2*np.pi))))
            smooth = np.abs(ifft(coefs[i][:min(10,len(coefs[i]))],n = len(coefs[i])))
            levels.append(smooth[floc])
            level_locs.append(r)
            levels.insert(0,smooth[rloc])
            level_locs.insert(0,-r)
        try:
            p = np.polyfit(level_locs, levels, deg = 2)
            if p[0] < 0 and len(levels) > 3:
                dist = np.clip(-p[1]/(2*p[0]), a_min = min(level_locs), a_max = max(level_locs))
            else:
                dist = level_locs[np.argmax(levels)]
        except:
            dist = results['psf fwhm']
        current_center['x'] += dist*np.cos(direction)
        current_center['y'] += dist*np.sin(direction)
        if abs(dist) < (0.25*results['psf fwhm']):
            small_update_count += 1
        else:
            small_update_count = 0
        track_centers.append([current_center['x'], current_center['y']])

    # refine center
    ranges = [[max(0,int(current_center['x']-results['psf fwhm']*5)), min(dat.shape[1],int(current_center['x']+results['psf fwhm']*5))],
              [max(0,int(current_center['y']-results['psf fwhm']*5)), min(dat.shape[0],int(current_center['y']+results['psf fwhm']*5))]]

    res = minimize(_hillclimb_loss, x0 =  [current_center['x'] - ranges[0][0], current_center['y'] - ranges[1][0]],
                   args = (dat[ranges[1][0]:ranges[1][1],ranges[0][0]:ranges[0][1]], results['psf fwhm'], results['background noise']), method = 'Nelder-Mead')
    if res.success:
        current_center['x'] = res.x[0] + ranges[0][0]
        current_center['y'] = res.x[1] + ranges[1][0]
    track_centers.append([current_center['x'], current_center['y']])
    # paper plot
    if 'ap_paperplots' in options and options['ap_paperplots']:    
        plt.imshow(np.clip(dat,a_min = 0, a_max = None), origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        plt.plot([current_center['x']],[current_center['y']], marker = 'x', markersize = 3, color = 'r')
        for i in range(3):
            plt.gca().add_patch(Ellipse((current_center['x'],current_center['y']), 2*((i+0.5)*results['psf fwhm']),
                                        2*((i+0.5)*results['psf fwhm']),
                                        0, fill = False, linewidth = 0.5, color = 'y'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig('%stest_center_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        plt.close()
        track_centers = np.array(track_centers)
        xwidth = 2*max(np.abs(track_centers[:,0] - current_center['x']))
        ywidth = 2*max(np.abs(track_centers[:,1] - current_center['y']))
        width = max(xwidth, ywidth)
        ranges = [[int(current_center['x'] - width), int(current_center['x'] + width)],
                  [int(current_center['y'] - width), int(current_center['y'] + width)]]
        fig, axarr = plt.subplots(2,1, figsize = (3,6))
        plt.subplots_adjust(hspace = 0.01, wspace = 0.01, left = 0.05, right = 0.95, top = 0.95, bottom = 0.05)
        axarr[0].imshow(np.clip(dat[ranges[1][0]:ranges[1][1],ranges[0][0]:ranges[0][1]],a_min = 0, a_max = None),
                        origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()),
                        extent = [ranges[0][0],ranges[0][1],ranges[1][0]-1,ranges[1][1]-1])
        axarr[0].plot(track_centers[:,0], track_centers[:,1], color = 'y')
        axarr[0].scatter(track_centers[:,0], track_centers[:,1], c = range(len(track_centers)), cmap = 'Reds')
        axarr[0].set_xticks([])
        axarr[0].set_yticks([])        
        width = 10.
        ranges = [[int(current_center['x'] - width), int(current_center['x'] + width)],
                  [int(current_center['y'] - width), int(current_center['y'] + width)]]
        axarr[1].imshow(np.clip(dat[ranges[1][0]:ranges[1][1],ranges[0][0]:ranges[0][1]],a_min = 0, a_max = None),
                        origin = 'lower', cmap = 'Greys_r',
                        extent = [ranges[0][0],ranges[0][1],ranges[1][0]-1,ranges[1][1]-1])
        axarr[1].plot(track_centers[:,0], track_centers[:,1], color = 'y')
        axarr[1].scatter(track_centers[:,0], track_centers[:,1], c = range(len(track_centers)), cmap = 'Reds')
        axarr[1].set_xlim(ranges[0])
        axarr[1].set_ylim(np.array(ranges[1])-1)        
        axarr[1].set_xticks([])
        axarr[1].set_yticks([])
        plt.savefig('%sCenter_path_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()
        
    return IMG, {'center': current_center, 'auxfile center': 'center x: %.2f pix, y: %.2f pix' % (current_center['x'], current_center['y'])}
Esempio n. 15
0
def Isophote_Initialize_mean(IMG, results, options):
    """Fit global elliptical isophote to a galaxy image using FFT coefficients.

    Same as the default isophote initialization routine, except uses
    mean/std measures for low S/N applications.

    Parameters
    -----------------
    ap_fit_limit : float, default 2
      noise level out to which to extend the fit in units of pixel
      background noise level. Default is 2, smaller values will end
      fitting further out in the galaxy image.

    Notes
    ----------
    :References:
    - 'background'
    - 'background noise'
    - 'psf fwhm'
    - 'center'

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {'init ellip': , # Ellipticity of the global fit (float)
         'init pa': ,# Position angle of the global fit (float)
         'init R': ,# Semi-major axis length of global fit (float)
         'auxfile initialize': # optional, message for aux file to record the global ellipticity and postition angle (string)

        }

    """

    ######################################################################
    # Initial attempt to find size of galaxy in image
    # based on when isophotes SB values start to get
    # close to the background noise level
    circ_ellipse_radii = [results["psf fwhm"]]
    allphase = []
    dat = IMG - results["background"]

    while circ_ellipse_radii[-1] < (len(IMG) / 2):
        circ_ellipse_radii.append(circ_ellipse_radii[-1] * (1 + 0.2))
        isovals = _iso_extract(
            dat,
            circ_ellipse_radii[-1],
            {
                "ellip": 0.0,
                "pa": 0.0
            },
            results["center"],
            more=True,
        )
        coefs = fft(isovals[0])
        allphase.append(coefs[2])
        # Stop when at 3 times background noise
        if (np.mean(isovals[0]) < (3 * results["background noise"])
                and len(circ_ellipse_radii) > 4):
            break
    logging.info("%s: init scale: %f pix" %
                 (options["ap_name"], circ_ellipse_radii[-1]))
    # Find global position angle.
    phase = (-Angle_Median(np.angle(allphase[-5:])) /
             2) % np.pi  # (-np.angle(np.mean(allphase[-5:]))/2) % np.pi

    # Find global ellipticity
    test_ellip = np.linspace(0.05, 0.95, 15)
    test_f2 = []
    for e in test_ellip:
        test_f2.append(
            sum(
                list(
                    _fitEllip_mean_loss(
                        e,
                        dat,
                        circ_ellipse_radii[-2] * m,
                        phase,
                        results["center"],
                        results["background noise"],
                    ) for m in np.linspace(0.8, 1.2, 5))))
    ellip = test_ellip[np.argmin(test_f2)]
    res = minimize(
        lambda e, d, r, p, c, n: sum(
            list(
                _fitEllip_mean_loss(_x_to_eps(e[0]), d, r * m, p, c, n)
                for m in np.linspace(0.8, 1.2, 5))),
        x0=_inv_x_to_eps(ellip),
        args=(
            dat,
            circ_ellipse_radii[-2],
            phase,
            results["center"],
            results["background noise"],
        ),
        method="Nelder-Mead",
        options={
            "initial_simplex": [
                [_inv_x_to_eps(ellip) - 1 / 15],
                [_inv_x_to_eps(ellip) + 1 / 15],
            ]
        },
    )
    if res.success:
        logging.debug(
            "%s: using optimal ellipticity %.3f over grid ellipticity %.3f" %
            (options["ap_name"], _x_to_eps(res.x[0]), ellip))
        ellip = _x_to_eps(res.x[0])

    # Compute the error on the parameters
    ######################################################################
    RR = np.linspace(
        circ_ellipse_radii[-2] - results["psf fwhm"],
        circ_ellipse_radii[-2] + results["psf fwhm"],
        10,
    )
    errallphase = []
    for rr in RR:
        isovals = _iso_extract(dat,
                               rr, {
                                   "ellip": 0.0,
                                   "pa": 0.0
                               },
                               results["center"],
                               more=True)
        coefs = fft(isovals[0])
        errallphase.append(coefs[2])
    sample_pas = (-np.angle(1j * np.array(errallphase) / np.mean(errallphase))
                  / 2) % np.pi
    pa_err = np.std(sample_pas)
    res_multi = map(
        lambda rrp: minimize(
            lambda e, d, r, p, c, n: _fitEllip_mean_loss(
                _x_to_eps(e[0]), d, r, p, c, n),
            x0=_inv_x_to_eps(ellip),
            args=(dat, rrp[0], rrp[1], results["center"], results[
                "background noise"]),
            method="Nelder-Mead",
            options={
                "initial_simplex": [
                    [_inv_x_to_eps(ellip) - 1 / 15],
                    [_inv_x_to_eps(ellip) + 1 / 15],
                ]
            },
        ),
        zip(RR, sample_pas),
    )
    ellip_err = np.std(list(_x_to_eps(rm.x[0]) for rm in res_multi))

    circ_ellipse_radii = np.array(circ_ellipse_radii)

    if "ap_doplot" in options and options["ap_doplot"]:

        ranges = [
            [
                max(0,
                    int(results["center"]["x"] -
                        circ_ellipse_radii[-1] * 1.5)),
                min(
                    dat.shape[1],
                    int(results["center"]["x"] + circ_ellipse_radii[-1] * 1.5),
                ),
            ],
            [
                max(0,
                    int(results["center"]["y"] -
                        circ_ellipse_radii[-1] * 1.5)),
                min(
                    dat.shape[0],
                    int(results["center"]["y"] + circ_ellipse_radii[-1] * 1.5),
                ),
            ],
        ]

        LSBImage(
            dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
            results["background noise"],
        )
        # plt.imshow(np.clip(dat[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]],a_min = 0, a_max = None),
        #            origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        plt.gca().add_patch(
            Ellipse(
                (
                    results["center"]["x"] - ranges[0][0],
                    results["center"]["y"] - ranges[1][0],
                ),
                2 * circ_ellipse_radii[-1],
                2 * circ_ellipse_radii[-1] * (1.0 - ellip),
                phase * 180 / np.pi,
                fill=False,
                linewidth=1,
                color="y",
            ))
        plt.plot(
            [results["center"]["x"] - ranges[0][0]],
            [results["center"]["y"] - ranges[1][0]],
            marker="x",
            markersize=3,
            color="r",
        )
        plt.tight_layout()
        if not ("ap_nologo" in options and options["ap_nologo"]):
            AddLogo(plt.gcf())
        plt.savefig(
            "%sinitialize_ellipse_%s.jpg" % (
                options["ap_plotpath"] if "ap_plotpath" in options else "",
                options["ap_name"],
            ),
            dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
        )
        plt.close()

        fig, ax = plt.subplots(2, 1, figsize=(6, 6))
        ax[0].plot(
            circ_ellipse_radii[:-1],
            ((-np.angle(allphase) / 2) % np.pi) * 180 / np.pi,
            color="k",
        )
        ax[0].axhline(phase * 180 / np.pi, color="r")
        ax[0].axhline((phase + pa_err) * 180 / np.pi,
                      color="r",
                      linestyle="--")
        ax[0].axhline((phase - pa_err) * 180 / np.pi,
                      color="r",
                      linestyle="--")
        # ax[0].axvline(circ_ellipse_radii[-2], color = 'orange', linestyle = '--')
        ax[0].set_xlabel("Radius [pix]")
        ax[0].set_ylabel("FFT$_{1}$ phase [deg]")
        ax[1].plot(test_ellip, test_f2, color="k")
        ax[1].axvline(ellip, color="r")
        ax[1].axvline(ellip + ellip_err, color="r", linestyle="--")
        ax[1].axvline(ellip - ellip_err, color="r", linestyle="--")
        ax[1].set_xlabel("Ellipticity [1 - b/a]")
        ax[1].set_ylabel("Loss [FFT$_{2}$/med(flux)]")
        plt.tight_layout()
        if not ("ap_nologo" in options and options["ap_nologo"]):
            AddLogo(plt.gcf())
        plt.savefig(
            "%sinitialize_ellipse_optimize_%s.jpg" % (
                options["ap_plotpath"] if "ap_plotpath" in options else "",
                options["ap_name"],
            ),
            dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
        )
        plt.close()

    auxmessage = (
        "global ellipticity: %.3f +- %.3f, pa: %.3f +- %.3f deg, size: %f pix"
        % (
            ellip,
            ellip_err,
            PA_shift_convention(phase) * 180 / np.pi,
            pa_err * 180 / np.pi,
            circ_ellipse_radii[-2],
        ))
    return IMG, {
        "init ellip": ellip,
        "init ellip_err": ellip_err,
        "init pa": phase,
        "init pa_err": pa_err,
        "init R": circ_ellipse_radii[-2],
        "auxfile initialize": auxmessage,
    }
Esempio n. 16
0
def Plot_Galaxy_Image(IMG, results, options):
    """Generate a plain image of the galaxy

    Plots an LSB image of the object without anything else drawn above
    it.  Useful for inspecting images for spurious features. This step
    can be run at any point in the pipeline. It will take advantage of
    whatever information has been determined so far. So if it is the
    first pipeline step, it has little to work from and will simply
    plot the whole image, if it is run after the isophote
    initialization step then the plotted image will be cropped to
    focus on the galaxy.

    Parameters
    -----------------
    ap_guess_center : dict, default None
      user provided starting point for center fitting. Center should
      be formatted as:

      .. code-block:: python

        {'x':float, 'y': float}

      , where the floats are the center coordinates in pixels. If not
      given, Autoprof will default to a guess of the image center.

    ap_set_center : dict, default None
      user provided fixed center for rest of calculations. Center
      should be formatted as:

      .. code-block:: python

        {'x':float, 'y': float}

      , where the floats are the center coordinates in pixels. If not
      given, Autoprof will default to a guess of the image center.

    Notes
    --------------
    :References:
    - 'background'
    - 'background noise'
    - 'center' (optional)
    - 'init R' (optional)

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {}
    """

    if "center" in results:
        center = results["center"]
    elif "ap_set_center" in options:
        center = options["ap_set_center"]
    elif "ap_guess_center" in options:
        center = options["ap_guess_center"]
    else:
        center = {"x": IMG.shape[1] / 2, "y": IMG.shape[0] / 2}

    if "prof data" in results:
        edge = 1.2 * results["prof data"]["R"][-1] / options["ap_pixscale"]
    elif "init R" in results:
        edge = 3 * results["init R"]
    elif "fit R" in results:
        edge = 2 * results["fit R"]
    else:
        edge = max(IMG.shape) / 2
    edge = min(
        [
            edge,
            abs(center["x"] - IMG.shape[1]),
            center["x"],
            abs(center["y"] - IMG.shape[0]),
            center["y"],
        ]
    )

    ranges = [
        [max(0, int(center["x"] - edge)), min(IMG.shape[1], int(center["x"] + edge))],
        [max(0, int(center["y"] - edge)), min(IMG.shape[0], int(center["y"] + edge))],
    ]

    LSBImage(
        IMG[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]]
        - results["background"],
        results["background noise"],
    )
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        "%sclean_image_%s.jpg"
        % (
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()

    return IMG, {}
Esempio n. 17
0
def Mask_Segmentation_Map(IMG, results, options):
    """Reads the results from other masking routines into AutoProf.

    Creates a mask from a supplied segmentation map. Such maps
    typically number each source with an integer. In such a case,
    AutoProf will check to see if the object center lands on one of
    these segments, if so it will zero out that source-id before
    converting the segmentation map into a mask. If the supplied image
    is just a 0, 1 mask then AutoProf will take it as is.

    Parameters
    -----------------
    ap_mask_file : string, default None
      path to fits file which is a mask for the image. Must have the same dimensions as the main image.

    See Also
    --------
    ap_savemask : bool, default False
      indicates if the mask should be saved after fitting

    Notes
    ----------
    :References:
    - 'background' (optional)
    - 'background noise' (optional)
    - 'center' (optional)
    - 'mask' (optional)

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {'mask':  # 2d mask image with boolean datatype (ndarray)
        }

    """

    if "ap_mask_file" not in options or options["ap_mask_file"] is None:
        mask = np.zeros(IMG.shape, dtype=bool)
    else:
        mask = Read_Image(options["ap_mask_file"], options)

    if "center" in results:
        if mask[int(results["center"]["y"]),
                int(results["center"]["x"])] > 1.1:
            mask[mask == mask[int(results["center"]["y"]),
                              int(results["center"]["x"])]] = 0
    elif "ap_set_center" in options:
        if (mask[int(options["ap_set_center"]["y"]),
                 int(options["ap_set_center"]["x"])] > 1.1):
            mask[mask == mask[int(options["ap_set_center"]["y"]),
                              int(options["ap_set_center"]["x"]), ]] = 0
    elif "ap_guess_center" in options:
        if (mask[int(options["ap_guess_center"]["y"]),
                 int(options["ap_guess_center"]["x"]), ] > 1.1):
            mask[mask == mask[int(options["ap_guess_center"]["y"]),
                              int(options["ap_guess_center"]["x"]), ]] = 0
    elif mask[int(IMG.shape[0] / 2), int(IMG.shape[1] / 2)] > 1.1:
        mask[mask == mask[int(IMG.shape[0] / 2), int(IMG.shape[1] / 2)]] = 0

    if "mask" in results:
        mask = np.logical_or(mask, results["mask"])

    # Plot star mask for diagnostic purposes
    if "ap_doplot" in options and options["ap_doplot"]:
        bkgrnd = results[
            "background"] if "background" in results else np.median(IMG)
        noise = (results["background noise"] if "background noise" in results
                 else iqr(IMG, rng=[16, 84]) / 2)
        LSBImage(IMG - bkgrnd, noise)
        showmask = np.copy(mask)
        showmask[showmask > 1] = 1
        showmask[showmask < 1] = np.nan
        plt.imshow(showmask, origin="lower", cmap="Reds_r", alpha=0.5)
        plt.tight_layout()
        if not ("ap_nologo" in options and options["ap_nologo"]):
            AddLogo(plt.gcf())
        plt.savefig(
            "%smask_%s.jpg" % (
                options["ap_plotpath"] if "ap_plotpath" in options else "",
                options["ap_name"],
            ),
            dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
        )
        plt.close()

    return IMG, {"mask": mask.astype(bool)}
Esempio n. 18
0
def Radial_Profiles(IMG, results, options):

    mask = results['mask'] if 'mask' in results else None
    nwedges = options[
        'ap_radialprofiles_nwedges'] if 'ap_radialprofiles_nwedges' in options else 4
    wedgeangles = np.linspace(0, 2 * np.pi * (1 - 1. / nwedges), nwedges)

    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5

    R = np.array(results['prof data']['R']) / options['ap_pixscale']
    SBE = np.array(results['prof data']['SB_e'])
    if 'ap_radialprofiles_variable_pa' in options and options[
            'ap_radialprofiles_variable_pa']:
        pa = np.array(results['prof data']['pa']) * np.pi / 180
    else:
        pa = np.ones(len(R)) * (
            (options['ap_radialprofiles_pa'] * np.pi /
             180) if 'ap_radialprofiles_pa' in options else results['init pa'])
    dat = IMG - results['background']

    maxwedgewidth = options[
        'ap_radialprofiles_width'] if 'ap_radialprofiles_width' in options else 15.
    maxwedgewidth *= np.pi / 180
    if 'ap_radialprofiles_expwidth' in options and options[
            'ap_radialprofiles_expwidth']:
        wedgewidth = maxwedgewidth * np.exp(R / R[-1] - 1)
    else:
        wedgewidth = np.ones(len(R)) * maxwedgewidth

    if wedgewidth[-1] * nwedges > 2 * np.pi:
        logging.warning(
            '%s: Radial sampling wedges are overlapping! %i wedges with a maximum width of %.3f rad'
            % (nwedges, wedgewidth[-1]))

    sb = list([] for i in wedgeangles)
    sbE = list([] for i in wedgeangles)

    for i in range(len(R)):
        if R[i] < 100:
            isovals = list(
                _iso_extract(dat,
                             R[i],
                             0,
                             0,
                             results['center'],
                             more=True,
                             minN=int(5 * 2 * np.pi / wedgewidth[i]),
                             mask=mask))
        else:
            isobandwidth = R[i] * (options['ap_isoband_width']
                                   if 'ap_isoband_width' in options else 0.025)
            isovals = list(
                _iso_between(dat,
                             R[i] - isobandwidth,
                             R[i] + isobandwidth,
                             0,
                             0,
                             results['center'],
                             more=True,
                             mask=mask))
        isovals[1] -= pa[i]

        for sa_i in range(len(wedgeangles)):
            aselect = np.abs(Angle_TwoAngles(wedgeangles[sa_i],
                                             isovals[1])) < (wedgewidth[i] / 2)
            if np.sum(aselect) == 0:
                sb[sa_i].append(99.999)
                sbE[sa_i].append(99.999)
                continue
            medflux = _average(
                isovals[0][aselect], options['ap_isoaverage_method']
                if 'ap_isoaverage_method' in options else 'median')
            scatflux = _scatter(
                isovals[0][aselect], options['ap_isoaverage_method']
                if 'ap_isoaverage_method' in options else 'median')
            sb[sa_i].append(
                flux_to_sb(medflux, options['ap_pixscale'], zeropoint
                           ) if medflux > 0 else 99.999)
            sbE[sa_i].append((2.5 * scatflux /
                              (np.sqrt(np.sum(aselect)) * medflux *
                               np.log(10))) if medflux > 0 else 99.999)

    newprofheader = results['prof header']
    newprofunits = results['prof units']
    newprofformat = results['prof format']
    newprofdata = results['prof data']
    for sa_i in range(len(wedgeangles)):
        p1, p2 = ('SB_rad[%.1f]' % (wedgeangles[sa_i] * 180 / np.pi),
                  'SB_rad_e[%.1f]' % (wedgeangles[sa_i] * 180 / np.pi))
        newprofheader.append(p1)
        newprofheader.append(p2)
        newprofunits[p1] = 'mag*arcsec^-2'
        newprofunits[p2] = 'mag*arcsec^-2'
        newprofformat[p1] = '%.4f'
        newprofformat[p2] = '%.4f'
        newprofdata[p1] = sb[sa_i]
        newprofdata[p2] = sbE[sa_i]

    if 'ap_doplot' in options and options['ap_doplot']:
        CHOOSE = SBE < 0.2
        firstbad = np.argmax(np.logical_not(CHOOSE))
        if firstbad > 3:
            CHOOSE[firstbad:] = False
        ranges = [
            [
                max(0, int(results['center']['x'] - 1.5 * R[CHOOSE][-1] - 2)),
                min(IMG.shape[1],
                    int(results['center']['x'] + 1.5 * R[CHOOSE][-1] + 2))
            ],
            [
                max(0, int(results['center']['y'] - 1.5 * R[CHOOSE][-1] - 2)),
                min(IMG.shape[0],
                    int(results['center']['y'] + 1.5 * R[CHOOSE][-1] + 2))
            ]
        ]
        # cmap = matplotlib.cm.get_cmap('tab10' if nwedges <= 10 else 'viridis')
        # colorind = np.arange(nwedges)/10
        cmap = matplotlib.cm.get_cmap('hsv')
        colorind = (np.linspace(0, 1 - 1 / nwedges, nwedges) + 0.1) % 1
        for sa_i in range(len(wedgeangles)):
            CHOOSE = np.logical_and(
                np.array(sb[sa_i]) < 99,
                np.array(sbE[sa_i]) < 1)
            plt.errorbar(np.array(R)[CHOOSE] * options['ap_pixscale'],
                         np.array(sb[sa_i])[CHOOSE],
                         yerr=np.array(sbE[sa_i])[CHOOSE],
                         elinewidth=1,
                         linewidth=0,
                         marker='.',
                         markersize=5,
                         color=cmap(colorind[sa_i]),
                         label='Wedge %.2f' %
                         (wedgeangles[sa_i] * 180 / np.pi))
        plt.xlabel('Radius [arcsec]', fontsize=16)
        plt.ylabel('Surface Brightness [mag arcsec$^{-2}$]', fontsize=16)
        bkgrdnoise = -2.5 * np.log10(
            results['background noise']) + zeropoint + 2.5 * np.log10(
                options['ap_pixscale']**2)
        plt.axhline(bkgrdnoise,
                    color='purple',
                    linewidth=0.5,
                    linestyle='--',
                    label='1$\\sigma$ noise/pixel:\n%.1f mag arcsec$^{-2}$' %
                    bkgrdnoise)
        plt.gca().invert_yaxis()
        plt.legend(fontsize=15)
        plt.tick_params(labelsize=14)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sradial_profiles_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])

        # plt.imshow(np.clip(dat[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]],
        #                    a_min = 0,a_max = None), origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        cx, cy = (results['center']['x'] - ranges[0][0],
                  results['center']['y'] - ranges[1][0])
        for sa_i in range(len(wedgeangles)):
            endx, endy = (R * np.cos(wedgeangles[sa_i] + pa),
                          R * np.sin(wedgeangles[sa_i] + pa))
            plt.plot(endx + cx, endy + cy, color='w', linewidth=1.1)
            plt.plot(endx + cx,
                     endy + cy,
                     color=cmap(colorind[sa_i]),
                     linewidth=0.7)
            endx, endy = (R * np.cos(wedgeangles[sa_i] + pa + wedgewidth / 2),
                          R * np.sin(wedgeangles[sa_i] + pa + wedgewidth / 2))
            plt.plot(endx + cx, endy + cy, color='w', linewidth=0.7)
            plt.plot(endx + cx,
                     endy + cy,
                     color=cmap(colorind[sa_i]),
                     linestyle='--',
                     linewidth=0.5)
            endx, endy = (R * np.cos(wedgeangles[sa_i] + pa - wedgewidth / 2),
                          R * np.sin(wedgeangles[sa_i] + pa - wedgewidth / 2))
            plt.plot(endx + cx, endy + cy, color='w', linewidth=0.7)
            plt.plot(endx + cx,
                     endy + cy,
                     color=cmap(colorind[sa_i]),
                     linestyle='--',
                     linewidth=0.5)

        plt.xlim([0, ranges[0][1] - ranges[0][0]])
        plt.ylim([0, ranges[1][1] - ranges[1][0]])
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sradial_profiles_wedges_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    return IMG, {
        'prof header': newprofheader,
        'prof units': newprofunits,
        'prof data': newprofdata,
        'prof format': newprofformat
    }
Esempio n. 19
0
def Slice_Profile(IMG, results, options):

    dat = IMG - (results['background'] if 'background' in results else 0.)
    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5
    
    use_anchor = results['center'] if 'center' in results else {'x': IMG.shape[1]/2, 'y': IMG.shape[0]/2}
    if 'ap_slice_anchor' in options:
        use_anchor = options['ap_slice_anchor']
    else:
        logging.warning('%s: ap_slice_anchor not specified by user, using: %s' % (options['ap_name'], str(use_anchor)))

    use_pa = results['init pa'] if 'init pa' in results else 0.
    if 'ap_slice_pa' in options:
        use_pa = options['ap_slice_pa']*np.pi/180
    else:
        logging.warning('%s: ap_slice_pa not specified by user, using: %.2f' % (options['ap_name'], use_pa))

    use_length = results['init R'] if 'init R' in results else min(IMG.shape)
    if 'ap_slice_length' in options:
        use_length = options['ap_slice_length']
    else:
        logging.warning('%s: ap_slice_length not specified by user, using: %.2f' % (options['ap_name'], use_length))

    use_width = 10.
    if 'ap_slice_width' in options:
        use_width = options['ap_slice_width']
    else:
        logging.warning('%s: ap_slice_width not specified by user, using: %.2f' % (options['ap_name'], use_width))

    use_step = results['psf fwhm'] if 'psf fwhm' in results else max(2., use_length/100)
    if 'ap_slice_step' in options:
        use_step = options['ap_slice_step']
    else:
        logging.warning('%s: ap_slice_step not specified by user, using: %.2f' % (options['ap_name'], use_step))
    
    F, X = _iso_line(dat, use_length, use_width, use_pa, use_anchor, more = False)

    windows = np.arange(0, use_length, use_step)

    R = (windows[1:] + windows[:-1])/2
    sb = []
    sb_e = []
    sb_sclip = []
    sb_sclip_e = []
    for i in range(len(windows)-1):
        isovals = F[np.logical_and(X >= windows[i], X < windows[i+1])]
        isovals_sclip = Sigma_Clip_Upper(isovals, iterations = 10, nsigma = 5)

        medflux = _average(isovals, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median')
        scatflux = _scatter(isovals, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median')
        medflux_sclip = _average(isovals_sclip, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median')
        scatflux_sclip = _scatter(isovals_sclip, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median')

        sb.append(flux_to_sb(medflux, options['ap_pixscale'], zeropoint) if medflux > 0 else 99.999)
        sb_e.append((2.5*scatflux / (np.sqrt(len(isovals))*medflux*np.log(10))) if medflux > 0 else 99.999)
        sb_sclip.append(flux_to_sb(medflux_sclip, options['ap_pixscale'], zeropoint) if medflux_sclip > 0 else 99.999)
        sb_sclip_e.append((2.5*scatflux_sclip / (np.sqrt(len(isovals))*medflux_sclip*np.log(10))) if medflux_sclip > 0 else 99.999)
    
    with open('%s%s_slice_profile_AP.prof' % ((options['ap_saveto'] if 'ap_saveto' in options else ''), options['ap_name']), 'w') as f:
        f.write('# flux sum: %f\n' % (np.sum(F[np.logical_and(X >= 0, X <= use_length)])))
        f.write('# flux mean: %f\n' % (_average(F[np.logical_and(X >= 0, X <= use_length)], 'mean')))
        f.write('# flux median: %f\n' % (_average(F[np.logical_and(X >= 0, X <= use_length)], 'median')))
        f.write('# flux mode: %f\n' % (_average(F[np.logical_and(X >= 0, X <= use_length)], 'mode')))
        f.write('# flux std: %f\n' % (np.std(F[np.logical_and(X >= 0, X <= use_length)])))
        f.write('# flux 16-84%% range: %f\n' % (iqr(F[np.logical_and(X >= 0, X <= use_length)], rng = [16,84])))
        f.write('R,sb,sb_e,sb_sclip,sb_sclip_e\n')
        f.write('arcsec,mag*arcsec^-2,mag*arcsec^-2,mag*arcsec^-2,mag*arcsec^-2\n')
        for i in range(len(R)):
            f.write('%.4f,%.4f,%.4f,%.4f,%.4f\n' % (R[i]*options['ap_pixscale'], sb[i], sb_e[i], sb_sclip[i], sb_sclip_e[i]))

    if 'ap_doplot' in options and options['ap_doplot']:
        CHOOSE = np.array(sb_e) < 0.5
        plt.errorbar(np.array(R)[CHOOSE]*options['ap_pixscale'], np.array(sb)[CHOOSE], yerr = np.array(sb_e)[CHOOSE],
                     elinewidth = 1, linewidth = 0, marker = '.', markersize = 3, color = 'r')
        plt.xlabel('Position on line [arcsec]', fontsize = 16)
        plt.ylabel('Surface Brightness [mag arcsec$^{-2}$]', fontsize = 16)
        if 'background noise' in results:
            bkgrdnoise = -2.5*np.log10(results['background noise']) + zeropoint + 2.5*np.log10(options['ap_pixscale']**2)
            plt.axhline(bkgrdnoise, color = 'purple', linewidth = 0.5, linestyle = '--', label = '1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$' % bkgrdnoise)
        plt.gca().invert_yaxis()
        plt.legend(fontsize = 15)
        plt.tick_params(labelsize = 14)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig('%sslice_profile_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        plt.close()
        
        ranges = [[max(0,int(use_anchor['x']+0.5*use_length*np.cos(use_pa)-use_length*0.7)), min(IMG.shape[1],int(use_anchor['x']+0.5*use_length*np.cos(use_pa)+use_length*0.7))],
                  [max(0,int(use_anchor['y']+0.5*use_length*np.sin(use_pa)-use_length*0.7)), min(IMG.shape[0],int(use_anchor['y']+0.5*use_length*np.sin(use_pa)+use_length*0.7))]]
        LSBImage(dat[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]], results['background noise'] if 'background noise' in results else iqr(dat, rng = (31.731/2, 100 - 31.731/2))/2)
        
        XX, YY = np.meshgrid(np.arange(ranges[0][1] - ranges[0][0], dtype = float), np.arange(ranges[1][1] - ranges[1][0], dtype = float))
        XX -= use_anchor['x'] - float(ranges[0][0])
        YY -= use_anchor['y'] - float(ranges[1][0])
        XX, YY = (XX*np.cos(-use_pa) - YY*np.sin(-use_pa), XX*np.sin(-use_pa) + YY*np.cos(-use_pa))
        ZZ = np.ones(XX.shape)
        ZZ[np.logical_not(np.logical_and(np.logical_and(YY <= use_width/2, YY >= -use_width/2),
                                         np.logical_and(XX >= 0, XX <= use_length)))] = np.nan
        plt.imshow(ZZ, origin = 'lower', cmap = 'Reds_r', alpha = 0.6)
        plt.tight_layout()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig('%sslice_profile_window_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        plt.close()
        
    return IMG, {}
Esempio n. 20
0
def Plot_Isophote_Fit(dat, sample_radii, parameters, results, options):
    for i in range(len(parameters)):
        if not "m" in parameters[i]:
            parameters[i]["m"] = None
    Rlim = sample_radii[-1] * (
        1.0
        if parameters[-1]["m"] is None
        else np.exp(
            sum(
                np.abs(parameters[-1]["Am"][m]) for m in range(len(parameters[-1]["m"]))
            )
        )
    )
    ranges = [
        [
            max(0, int(results["center"]["x"] - Rlim * 1.2)),
            min(dat.shape[1], int(results["center"]["x"] + Rlim * 1.2)),
        ],
        [
            max(0, int(results["center"]["y"] - Rlim * 1.2)),
            min(dat.shape[0], int(results["center"]["y"] + Rlim * 1.2)),
        ],
    ]
    LSBImage(
        dat[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]],
        results["background noise"],
    )
    AddScale(plt.gca(), (ranges[0][1] - ranges[0][0])*options['ap_pixscale'])

    for i in range(len(sample_radii)):
        N = max(15, int(0.9 * 2 * np.pi * sample_radii[i]))
        theta = np.linspace(0, 2 * np.pi * (1.0 - 1.0 / N), N)
        theta = np.arctan((1.0 - parameters[i]["ellip"]) * np.tan(theta)) + np.pi * (
            np.cos(theta) < 0
        )
        R = sample_radii[i] * (
            1.0
            if parameters[i]["m"] is None
            else np.exp(
                sum(
                    parameters[i]["Am"][m]
                    * np.cos(parameters[i]["m"][m] * (theta + parameters[i]["Phim"][m]))
                    for m in range(len(parameters[i]["m"]))
                )
            )
        )
        X, Y = parametric_SuperEllipse(
            theta,
            parameters[i]["ellip"],
            2 if parameters[i]["C"] is None else parameters[i]["C"],
        )
        X, Y = Rotate_Cartesian(parameters[i]["pa"], X, Y)
        X, Y = (
            R * X + results["center"]["x"] - ranges[0][0],
            R * Y + results["center"]["y"] - ranges[1][0],
        )
        
        plt.plot(
            list(X) + [X[0]],
            list(Y) + [Y[0]],
            linewidth=((i + 1) / len(sample_radii)) ** 2,
            color=autocolours["red1"],
        )
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "fit_ellipse_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 21
0
def _Plot_Isophotes(dat, R, parameters, results, options):
    for i in range(len(parameters)):
        if not "m" in parameters[i]:
            parameters[i]["m"] = None
    Rlim = R[-1] * (
        1.0
        if parameters[-1]["m"] is None
        else np.exp(
            sum(
                np.abs(parameters[-1]["Am"][m]) for m in range(len(parameters[-1]["m"]))
            )
        )
    )
    ranges = [
        [
            max(0, int(results["center"]["x"] - Rlim * 1.2)),
            min(dat.shape[1], int(results["center"]["x"] + Rlim * 1.2)),
        ],
        [
            max(0, int(results["center"]["y"] - Rlim * 1.2)),
            min(dat.shape[0], int(results["center"]["y"] + Rlim * 1.2)),
        ],
    ]
    LSBImage(
        dat[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]],
        results["background noise"],
    )
    AddScale(plt.gca(), (ranges[0][1] - ranges[0][0])*options['ap_pixscale'])
    fitlim = results["fit R"][-1] if "fit R" in results else np.inf
    for i in range(len(R)):
        N = max(15, int(0.9 * 2 * np.pi * R[i]))
        theta = np.linspace(0, 2 * np.pi * (1.0 - 1.0 / N), N)
        theta = np.arctan((1.0 - parameters[i]["ellip"]) * np.tan(theta)) + np.pi * (
            np.cos(theta) < 0
        )
        RR = R[i] * (
            np.ones(N)
            if parameters[i]["m"] is None
            else np.exp(
                sum(
                    parameters[i]["Am"][m]
                    * np.cos(parameters[i]["m"][m] * (theta + parameters[i]["Phim"][m]))
                    for m in range(len(parameters[i]["m"]))
                )
            )
        )
        X = RR * np.cos(theta)
        Y = RR * (1 - parameters[i]["ellip"]) * np.sin(theta)
        X, Y = (
            X * np.cos(parameters[i]["pa"]) - Y * np.sin(parameters[i]["pa"]),
            X * np.sin(parameters[i]["pa"]) + Y * np.cos(parameters[i]["pa"]),
        )
        X += results["center"]["x"] - ranges[0][0]
        Y += results["center"]["y"] - ranges[1][0]
        plt.plot(
            list(X) + [X[0]],
            list(Y) + [Y[0]],
            linewidth=((i + 1) / len(R)) ** 2,
            color=autocolours["blue1"] if (i % 4 == 0) else autocolours["red1"],
            linestyle="-" if R[i] < fitlim else "--",
        )
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "photometry_ellipse_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 22
0
def Plot_Radial_Profiles(
    dat, R, sb, sbE, pa, nwedges, wedgeangles, wedgewidth, results, options
):

    zeropoint = options["ap_zeropoint"] if "ap_zeropoint" in options else 22.5
    ranges = [
        [
            max(0, int(results["center"]["x"] - 1.5 * R[-1] - 2)),
            min(dat.shape[1], int(results["center"]["x"] + 1.5 * R[-1] + 2)),
        ],
        [
            max(0, int(results["center"]["y"] - 1.5 * R[-1] - 2)),
            min(dat.shape[0], int(results["center"]["y"] + 1.5 * R[-1] + 2)),
        ],
    ]
    
    cmap = cm.get_cmap("hsv")
    colorind = (np.linspace(0, 1 - 1 / nwedges, nwedges) + 0.1) % 1.0
    for sa_i in range(len(wedgeangles)):
        CHOOSE = np.logical_and(np.array(sb[sa_i]) < 99, np.array(sbE[sa_i]) < 1)
        plt.errorbar(
            np.array(R)[CHOOSE] * options["ap_pixscale"],
            np.array(sb[sa_i])[CHOOSE],
            yerr=np.array(sbE[sa_i])[CHOOSE],
            elinewidth=1,
            linewidth=0,
            marker=".",
            markersize=5,
            color=cmap(colorind[sa_i]),
            label="Wedge %.2f" % (wedgeangles[sa_i] * 180 / np.pi),
        )
    plt.xlabel("Radius [arcsec]", fontsize=16)
    plt.ylabel("Surface Brightness [mag arcsec$^{-2}$]", fontsize=16)
    bkgrdnoise = (
        -2.5 * np.log10(results["background noise"])
        + zeropoint
        + 2.5 * np.log10(options["ap_pixscale"] ** 2)
    )
    plt.axhline(
        bkgrdnoise,
        color="purple",
        linewidth=0.5,
        linestyle="--",
        label="1$\\sigma$ noise/pixel:\n%.1f mag arcsec$^{-2}$" % bkgrdnoise,
    )
    plt.gca().invert_yaxis()
    plt.legend(fontsize=15)
    plt.tick_params(labelsize=14)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "radial_profiles_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()

    LSBImage(
        dat[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]],
        results["background noise"],
    )
    AddScale(plt.gca(), (ranges[0][1] - ranges[0][0])*options['ap_pixscale'])

    cx, cy = (
        results["center"]["x"] - ranges[0][0],
        results["center"]["y"] - ranges[1][0],
    )
    for sa_i in range(len(wedgeangles)):
        if np.all(pa == pa[0]):
            plt.gca().add_patch(
                Wedge(
                    (cx, cy),
                    R[-1],
                    (wedgeangles[sa_i] + pa[0] - wedgewidth[-1] / 2) * 180 / np.pi,
                    (wedgeangles[sa_i] + pa[0] + wedgewidth[-1] / 2) * 180 / np.pi,
                    facecolor=cmap(colorind[sa_i]),
                    linewidth=0,
                    alpha=0.3,
                )
            )
        else:
            endx, endy = (
                R * np.cos(wedgeangles[sa_i] + pa),
                R * np.sin(wedgeangles[sa_i] + pa),
            )
            plt.plot(endx + cx, endy + cy, color="w", linewidth=1.1)
            plt.plot(endx + cx, endy + cy, color=cmap(colorind[sa_i]), linewidth=0.7)
            endx, endy = (
                R * np.cos(wedgeangles[sa_i] + pa + wedgewidth / 2),
                R * np.sin(wedgeangles[sa_i] + pa + wedgewidth / 2),
            )
            plt.plot(endx + cx, endy + cy, color="w", linewidth=0.7)
            plt.plot(
                endx + cx,
                endy + cy,
                color=cmap(colorind[sa_i]),
                linestyle="--",
                linewidth=0.5,
            )
            endx, endy = (
                R * np.cos(wedgeangles[sa_i] + pa - wedgewidth / 2),
                R * np.sin(wedgeangles[sa_i] + pa - wedgewidth / 2),
            )
            plt.plot(endx + cx, endy + cy, color="w", linewidth=0.7)
            plt.plot(
                endx + cx,
                endy + cy,
                color=cmap(colorind[sa_i]),
                linestyle="--",
                linewidth=0.5,
            )

    plt.xlim([0, ranges[0][1] - ranges[0][0]])
    plt.ylim([0, ranges[1][1] - ranges[1][0]])
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "radial_profiles_wedges_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 23
0
def Plot_SB_Profile(dat, R, SB, SB_e, parameters, results, options):

    zeropoint = options["ap_zeropoint"] if "ap_zeropoint" in options else 22.5

    CHOOSE = np.logical_and(SB < 99, SB_e < 1)
    if np.sum(CHOOSE) < 5:
        CHOOSE = np.ones(len(CHOOSE), dtype=bool)
    errscale = 1.0
    if np.all(SB_e[CHOOSE] < 0.5):
        errscale = 1 / np.max(SB_e[CHOOSE])
    if 'ap_plot_sbprof_set_errscale' in options:
        errscale = options['ap_plot_sbprof_set_errscale']
        
    lnlist = []
    if errscale > 1.01 or 'ap_plot_sbprof_set_errscale' in options:
        errlabel = ' (err$\\times$%.1f)'  % errscale
    else:
        errlabel = ''
    lnlist.append(
        plt.errorbar(
            R[CHOOSE],
            SB[CHOOSE],
            yerr=errscale * SB_e[CHOOSE],
            elinewidth=1,
            linewidth=0,
            marker=".",
            markersize=5,
            color=autocolours["red1"],
            label="Surface Brightness" + errlabel,
        )
    )
    plt.errorbar(
        R[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        SB[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        yerr=SB_e[np.logical_and(CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)],
        elinewidth=1,
        linewidth=0,
        marker=".",
        markersize=5,
        color=autocolours["blue1"],
    )
    plt.xlabel("Semi-Major-Axis [arcsec]", fontsize=16)
    plt.ylabel("Surface Brightness [mag arcsec$^{-2}$]", fontsize=16)
    if 'ap_plot_sbprof_xlim' in options:
        plt.xlim(options['ap_plot_sbprof_xlim'])
    else:
        plt.xlim([0, None])
    if 'ap_plot_sbprof_ylim' in options:
        plt.ylim(options['ap_plot_sbprof_ylim'])
    bkgrdnoise = (
        -2.5 * np.log10(results["background noise"])
        + zeropoint
        + 2.5 * np.log10(options["ap_pixscale"] ** 2)
    )
    lnlist.append(
        plt.axhline(
            bkgrdnoise,
            color="purple",
            linewidth=0.5,
            linestyle="--",
            label="1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$" % bkgrdnoise,
        )
    )
    plt.gca().invert_yaxis()
    plt.tick_params(labelsize=14)
    labs = [l.get_label() for l in lnlist]
    plt.legend(lnlist, labs, fontsize=11)
    plt.tight_layout()
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "photometry_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()

    _Plot_Isophotes(
        dat,
        R[CHOOSE] / options["ap_pixscale"],
        list(compress(parameters, CHOOSE)),
        results,
        options,
    )
Esempio n. 24
0
def PSF_Image(IMG, results, options):
    """PSF routine which identifies stars and averages the FWHM.

    Constructs an averaged PSF image. Extracts a window of pixels
    around each identified star (+-10 PSF) and normalizes the flux
    total to 1. All extraced normalized stars are median stacked. The
    final PSF is saved as "<name>_psf.fits" and added to the results
    dictionary. Also calculates the PSF FWHM and adds it to the
    results dictionary. This method is currently very slow.

    Parameters
    -----------------

    ap_guess_psf : float, default None
      Initialization value for the PSF calculation in pixels. If not
      given, AutoProf will default with a guess of 1/*ap_pixscale*

    ap_set_psf : float, default None
      force AutoProf to use this PSF value (in pixels) instead of
      calculating its own.

    Notes
    ----------
    :References:
    - 'background'
    - 'background noise'

    Returns
    -------
    IMG : ndarray
      Unaltered galaxy image

    results : dict
      .. code-block:: python

        {'psf fwhm':  # FWHM of the average PSF for the image
         'auxfile psf': # aux file message giving the PSF
         'psf img':   # image of the PSF as numpy array
        }

    """

    if "ap_set_psf" in options:
        logging.info("%s: PSF set by user: %.4e" %
                     (options["ap_name"], options["ap_set_psf"]))
        return IMG, {"psf fwhm": options["ap_set_psf"]}
    elif "ap_guess_psf" in options:
        logging.info("%s: PSF initialized by user: %.4e" %
                     (options["ap_name"], options["ap_guess_psf"]))
        fwhm_guess = options["ap_guess_psf"]
    else:
        fwhm_guess = max(1.0, 1.0 / options["ap_pixscale"])

    edge_mask = np.zeros(IMG.shape, dtype=bool)
    edge_mask[int(IMG.shape[0] / 4.0):int(3.0 * IMG.shape[0] / 4.0),
              int(IMG.shape[1] / 4.0):int(3.0 * IMG.shape[1] / 4.0), ] = True
    dat = IMG - results["background"]
    stars = StarFind(
        dat,
        fwhm_guess,
        results["background noise"],
        edge_mask,
        detect_threshold=5.0,
        maxstars=100,
    )
    if len(stars["fwhm"]) <= 10:
        logging.error(
            "%s: unable to detect enough stars! PSF results not valid, using 1 arcsec estimate psf of %f"
            % (options["ap_name"], fwhm_guess))

    def_clip = 0.1
    while np.sum(stars["deformity"] < def_clip) < max(
            10,
            len(stars["fwhm"]) * 2 / 3):
        def_clip += 0.1
    psf = np.median(stars["fwhm"][stars["deformity"] < def_clip])
    psf_iqr = np.quantile(stars["fwhm"][stars["deformity"] < def_clip],
                          [0.1, 0.9])
    psf_size = int(psf * 10)
    if psf_size % 2 == 0:  # make PSF odd for easier calculations
        psf_size += 1

    psf_img = None
    XX, YY = np.meshgrid(
        np.array(range(psf_size)) - psf_size // 2,
        np.array(range(psf_size)) - psf_size // 2,
    )
    XX, YY = np.ravel(XX), np.ravel(YY)

    for i in range(len(stars["x"])):
        # ignore objects that likely aren't stars
        if (stars["deformity"][i] > def_clip or stars["fwhm"][i] < psf_iqr[0]
                or stars["fwhm"][i] > psf_iqr[1]):
            continue
        # ignore objects that are too close to the edge
        if (stars["x"][i] < psf_size // 2
                or (dat.shape[1] - stars["x"][i]) < psf_size // 2
                or stars["y"][i] < psf_size // 2
                or (dat.shape[1] - stars["y"][i]) < psf_size // 2):
            continue
        flux = interpolate_Lanczos(dat, XX + stars["x"][i], YY + stars["y"][i],
                                   10).reshape((1, psf_size, psf_size))
        flux /= np.sum(flux)
        psf_img = flux if psf_img is None else np.concatenate((psf_img, flux))

    # stack the PSF
    psf_img = np.median(psf_img, axis=0)
    # normalize the PSF
    psf_img /= np.sum(psf_img)

    hdul = fits.HDUList([fits.PrimaryHDU(psf_img)])
    hdul.writeto(
        os.path.join(
            options["ap_saveto"] if "ap_saveto" in options else "",
            "%s_psf.fits" % options["ap_name"],
        ),
        overwrite=True,
    )

    if "ap_doplot" in options and options["ap_doplot"]:
        plt.imshow(
            psf_img,
            origin="lower",
            cmap="Greys",
            norm=ImageNormalize(stretch=HistEqStretch(psf_img)),
        )
        my_cmap = cm.Greys_r
        my_cmap.set_under("k", alpha=0)
        fluxpeak = psf_img[psf_size // 2 + 1, psf_size // 2 + 1] / 2
        plt.imshow(
            np.clip(psf_img, a_min=fluxpeak / 10, a_max=None),
            origin="lower",
            cmap=my_cmap,
            norm=ImageNormalize(stretch=LogStretch(), clip=False),
            clim=[fluxpeak / 9, None],
            vmin=fluxpeak / 9,
        )
        plt.axis("off")
        plt.tight_layout()
        if not ("ap_nologo" in options and options["ap_nologo"]):
            AddLogo(plt.gcf())
        plt.savefig(
            "%sPSF_%s.jpg" % (
                options["ap_plotpath"] if "ap_plotpath" in options else "",
                options["ap_name"],
            ),
            dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
        )
        plt.close()

    return IMG, {
        "psf fwhm": psf,
        "auxfile psf": "psf fwhm: %.3f pix" % psf,
        "psf img": psf_img,
    }
Esempio n. 25
0
def PSF_StarFind(IMG, results, options):

    if 'ap_set_psf' in options:
        logging.info('%s: PSF set by user: %.4e' % (options['ap_name'], options['ap_set_psf']))
        return IMG, {'psf fwhm': options['ap_set_psf']}
    elif 'ap_guess_psf' in options:
        logging.info('%s: PSF initialized by user: %.4e' % (options['ap_name'], options['ap_guess_psf']))
        fwhm_guess = options['ap_guess_psf']
    else:
        fwhm_guess = max(1., 1./options['ap_pixscale'])

    edge_mask = np.zeros(IMG.shape, dtype = bool)
    edge_mask[int(IMG.shape[0]/4.):int(3.*IMG.shape[0]/4.),
              int(IMG.shape[1]/4.):int(3.*IMG.shape[1]/4.)] = True
    stars = StarFind(IMG - results['background'], fwhm_guess, results['background noise'],
                     edge_mask, # peakmax = (options['ap_overflowval']-results['background'])*0.95 if 'ap_overflowval' in options else None,
                     maxstars = 50)
    if len(stars['fwhm']) <= 10:
        return IMG, {'psf fwhm': fwhm_guess}
    def_clip = 0.1
    while np.sum(stars['deformity'] < def_clip) < max(10,2*len(stars['fwhm'])/3):
        def_clip += 0.1
    if 'ap_doplot' in options and options['ap_doplot']:
        plt.imshow(np.clip(IMG - results['background'], a_min = 0, a_max = None), origin = 'lower',
                   cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        plt.axis('off')
        for i in range(len(stars['fwhm'])):
            plt.gca().add_patch(Ellipse((stars['x'][i],stars['y'][i]), 16/options['ap_pixscale'], 16/options['ap_pixscale'],
                                        0, fill = False, linewidth = 0.5, color = 'r' if stars['deformity'][i] >= def_clip else 'y'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig('%sPSF_Stars_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        plt.close()

    if 'ap_paperplots' in options and options['ap_paperplots']:    
        # paper plot
        N = np.argsort(stars['deformity'])
        figscale = max(stars['fwhm'][N[:9]])*2
        fig, axarr = plt.subplots(3,3, figsize = (6,6))
        plt.subplots_adjust(hspace = 0.01, wspace = 0.01, left = 0.05, right = 0.95, top = 0.95, bottom = 0.05)
        count = 0
        for i in range(3):
            for j in range(3):
                ranges = [[int(stars['x'][N[count]]-figscale),1+int(stars['x'][N[count]]+figscale)],
                          [int(stars['y'][N[count]]-figscale),1+int(stars['y'][N[count]]+figscale)]]
                axarr[i][j].imshow(np.clip(IMG[ranges[1][0]:ranges[1][1],ranges[0][0]:ranges[0][1]] - results['background'], a_min = 0, a_max = None), origin = 'lower',
                                   cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()), extent = (0,1,0,1))
                axarr[i][j].add_patch(Ellipse(((stars['x'][N[count]]-ranges[0][0])/(ranges[0][1]-ranges[0][0]),
                                               (stars['y'][N[count]]-ranges[1][0])/(ranges[1][1]-ranges[1][0])),
                                              stars['fwhm'][N[count]]/(ranges[0][1]-ranges[0][0]),
                                              stars['fwhm'][N[count]]/(ranges[1][1]-ranges[1][0]),
                                              0, fill = False, linewidth = 1, color = 'r'))
                axarr[i][j].set_xticks([])
                axarr[i][j].set_yticks([])
                count += 1
        plt.savefig('%sPSF_Best_Stars_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        plt.close()

    psf = np.median(stars['fwhm'][stars['deformity'] < def_clip])
    logging.info('%s: found psf: %f with deformity clip of: %f' % (options['ap_name'],psf, def_clip))
    return IMG, {'psf fwhm': psf, 'auxfile psf': 'psf fwhm: %.3f pix' % psf}
Esempio n. 26
0
def EllipseModel_Fix(IMG, results, options):

    zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5
    pa = results['init pa']
    eps = results['init ellip']

    CHOOSE = np.array(results['prof data']['SB_fix_e']) < 0.3
    R = np.array(results['prof data']['R'])[CHOOSE] / options['ap_pixscale']
    SB = np.array(results['prof data']['SB_fix'])[CHOOSE]

    Model = np.zeros(IMG.shape, dtype=np.float32)
    ranges = [[
        max(0, int(results['center']['x'] - R[-1] - 2)),
        min(IMG.shape[1], int(results['center']['x'] + R[-1] + 2))
    ],
              [
                  max(0, int(results['center']['y'] - R[-1] - 2)),
                  min(IMG.shape[0], int(results['center']['y'] + R[-1] + 2))
              ]]
    XX, YY = np.meshgrid(np.arange(ranges[0][1] - ranges[0][0], dtype=float),
                         np.arange(ranges[1][1] - ranges[1][0], dtype=float))
    XX -= results['center']['x'] - float(ranges[0][0])
    YY -= results['center']['y'] - float(ranges[1][0])
    XX, YY = (XX * np.cos(-pa) - YY * np.sin(-pa),
              XX * np.sin(-pa) + YY * np.cos(-pa))
    YY /= 1 - eps
    RR = np.sqrt(XX**2 + YY**2)

    MM = np.interp(RR.ravel(), R, SB).reshape(RR.shape)
    MM = 10**(-(MM - zeropoint - 5 * np.log10(options['ap_pixscale'])) / 2.5)
    MM[RR > R[-1]] = 0
    Model[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]] = MM

    header = fits.Header()
    hdul = fits.HDUList([fits.PrimaryHDU(header=header), fits.ImageHDU(Model)])

    hdul.writeto('%s%s_fixmodel.fits' %
                 (options['ap_plotpath'] if 'ap_plotpath' in options else '',
                  options['ap_name']),
                 overwrite=True)

    if 'ap_doplot' in options and options['ap_doplot']:

        plt.figure(figsize=(7, 7))
        autocmap.set_under('k', alpha=0)
        showmodel = Model[ranges[1][0]:ranges[1][1],
                          ranges[0][0]:ranges[0][1]].copy()
        showmodel[showmodel > 0] += np.max(showmodel) / (10**3.5) - np.min(
            showmodel[showmodel > 0])
        plt.imshow(showmodel,
                   origin='lower',
                   cmap=autocmap,
                   norm=ImageNormalize(stretch=LogStretch(), clip=False))
        plt.axis('off')
        plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sellipsemodel_fix_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        residual = IMG[ranges[1][0]:ranges[1][1],
                       ranges[0][0]:ranges[0][1]] - results[
                           'background'] - Model[ranges[1][0]:ranges[1][1],
                                                 ranges[0][0]:ranges[0][1]]
        plt.figure(figsize=(7, 7))
        plt.imshow(residual,
                   origin='lower',
                   cmap='PuBu',
                   vmin=np.quantile(residual, 0.0001),
                   vmax=0)
        plt.imshow(np.clip(residual,
                           a_min=0,
                           a_max=np.quantile(residual, 0.9999)),
                   origin='lower',
                   cmap=autocmap,
                   norm=ImageNormalize(stretch=LogStretch(), clip=False),
                   interpolation='none',
                   clim=[1e-5, None])
        plt.axis('off')
        plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sellipseresidual_fix_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        # plt.figure(figsize = (7,7))
        # plt.imshow(np.clip(Model[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]],a_min = 0, a_max = None),
        #            origin = 'lower', cmap = autocmap, norm = ImageNormalize(stretch=LogStretch(), clip = False))
        # plt.axis('off')
        # plt.tight_layout()
        # if not ('ap_nologo' in options and options['ap_nologo']):
        #     AddLogo(plt.gcf())
        # plt.savefig('%sellipsemodel_fix_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        # plt.close()

        # residual = IMG[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]] - results['background'] - Model[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]]
        # plt.figure(figsize = (7,7))
        # plt.imshow(residual, origin = 'lower', cmap = 'PuBu',
        #            vmin = np.quantile(residual, 0.0001), vmax = 0)
        # autocmap.set_under('k', alpha=0)
        # plt.imshow(np.clip(residual,a_min = 0, a_max = np.quantile(residual,0.9999)),
        #            origin = 'lower', cmap = autocmap, norm = ImageNormalize(stretch=LogStretch(), clip = False),
        #            interpolation = 'none', clim = [1e-5, None])
        # plt.axis('off')
        # plt.tight_layout()
        # if not ('ap_nologo' in options and options['ap_nologo']):
        #     AddLogo(plt.gcf())
        # plt.savefig('%sellipseresidual_fix_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi = options['ap_plotdpi'] if 'ap_plotdpi'in options else 300)
        # plt.close()

    return IMG, {'ellipse model': Model}
Esempio n. 27
0
def Plot_Axial_Profiles(dat, R, sb, sbE, pa, results, options):

    zeropoint = options["ap_zeropoint"] if "ap_zeropoint" in options else 22.5
    count = 0
    for rd in [1, -1]:
        for ang in [1, -1]:
            key = (rd, ang)
            # cmap = matplotlib.cm.get_cmap('viridis_r')
            norm = matplotlib.colors.Normalize(
                vmin=0, vmax=R[-1] * options["ap_pixscale"]
            )
            for pi, pR in enumerate(R):
                if pi % 3 != 0:
                    continue
                CHOOSE = np.logical_and(
                    np.array(sb[key][pi]) < 99, np.array(sbE[key][pi]) < 1
                )
                plt.errorbar(
                    np.array(R)[CHOOSE] * options["ap_pixscale"],
                    np.array(sb[key][pi])[CHOOSE],
                    yerr=np.array(sbE[key][pi])[CHOOSE],
                    elinewidth=1,
                    linewidth=0,
                    marker=".",
                    markersize=3,
                    color=autocmap.reversed()(norm(pR * options["ap_pixscale"])),
                )
            plt.xlabel(
                "%s-axis position on line [arcsec]"
                % (
                    "Major"
                    if "ap_axialprof_parallel" in options
                    and options["ap_axialprof_parallel"]
                    else "Minor"
                ),
                fontsize=16,
            )
            plt.ylabel("Surface Brightness [mag arcsec$^{-2}$]", fontsize=16)
            cb1 = plt.colorbar(
                matplotlib.cm.ScalarMappable(norm=norm, cmap=autocmap.reversed())
            )
            cb1.set_label(
                "%s-axis position of line [arcsec]"
                % (
                    "Minor"
                    if "ap_axialprof_parallel" in options
                    and options["ap_axialprof_parallel"]
                    else "Major"
                ),
                fontsize=16,
            )
            bkgrdnoise = (
                -2.5 * np.log10(results["background noise"])
                + zeropoint
                + 2.5 * np.log10(options["ap_pixscale"] ** 2)
            )
            plt.axhline(
                bkgrdnoise,
                color="purple",
                linewidth=0.5,
                linestyle="--",
                label="1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$" % bkgrdnoise,
            )
            plt.gca().invert_yaxis()
            plt.legend(fontsize=15)
            plt.tick_params(labelsize=14)
            plt.title(
                "%sR : pa%s90" % ("+" if rd > 0 else "-", "+" if ang > 0 else "-"),
                fontsize=15,
            )
            plt.tight_layout()
            if not ("ap_nologo" in options and options["ap_nologo"]):
                AddLogo(plt.gcf())
            plt.savefig(
                os.path.join(
                    options["ap_plotpath"] if "ap_plotpath" in options else "",
                    "axial_profile_q%i_%s.jpg" % (count, options["ap_name"]),
                ),
                dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
            )
            plt.close()
            count += 1

    CHOOSE = np.array(results["prof data"]["SB_e"]) < 0.2
    firstbad = np.argmax(np.logical_not(CHOOSE))
    if firstbad > 3:
        CHOOSE[firstbad:] = False
    outto = (
        np.array(results["prof data"]["R"])[CHOOSE][-1] * 1.5 / options["ap_pixscale"]
    )
    ranges = [
        [
            max(0, int(results["center"]["x"] - outto - 2)),
            min(dat.shape[1], int(results["center"]["x"] + outto + 2)),
        ],
        [
            max(0, int(results["center"]["y"] - outto - 2)),
            min(dat.shape[0], int(results["center"]["y"] + outto + 2)),
        ],
    ]
    LSBImage(
        dat[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]],
        results["background noise"],
    )
    AddScale(plt.gca(), (ranges[0][1] - ranges[0][0])*options['ap_pixscale'])
    count = 0
    cmap = matplotlib.cm.get_cmap("hsv")
    colorind = (np.linspace(0, 1 - 1 / 4, 4) + 0.1) % 1
    colours = list(cmap(c) for c in colorind) 
    for rd in [1, -1]:
        for ang in [1, -1]:
            key = (rd, ang)
            branch_pa = (pa + ang * np.pi / 2) % (2 * np.pi)
            for pi, pR in enumerate(R):
                if pi % 3 != 0:
                    continue
                start = np.array(
                    [
                        results["center"]["x"]
                        + ang * rd * pR * np.cos(pa + (0 if ang > 0 else np.pi)),
                        results["center"]["y"]
                        + ang * rd * pR * np.sin(pa + (0 if ang > 0 else np.pi)),
                    ]
                )
                end = start + R[-1] * np.array([np.cos(branch_pa), np.sin(branch_pa)])
                start -= np.array([ranges[0][0], ranges[1][0]])
                end -= np.array([ranges[0][0], ranges[1][0]])
                plt.plot(
                    [start[0], end[0]],
                    [start[1], end[1]],
                    linewidth=0.5,
                    color=colours[count],
                    label=(
                        "%sR : pa%s90"
                        % ("+" if rd > 0 else "-", "+" if ang > 0 else "-")
                    )
                    if pi == 0
                    else None,
                )
            count += 1
    plt.legend()
    plt.xlim([0, ranges[0][1] - ranges[0][0]])
    plt.ylim([0, ranges[1][1] - ranges[1][0]])
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "axial_profile_lines_%s.jpg" % options["ap_name"],
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 28
0
def Isophote_Fit_Forced(IMG, results, options):
    """
    Take isophotal fit from a given profile.
    """
    with open(options['ap_forcing_profile'], 'r') as f:
        raw = f.readlines()
        for i, l in enumerate(raw):
            if l[0] != '#':
                readfrom = i
                break
        header = list(h.strip() for h in raw[readfrom].split(','))
        force = dict((h, []) for h in header)
        for l in raw[readfrom + 2:]:
            for d, h in zip(l.split(','), header):
                force[h].append(float(d.strip()))

    force['pa'] = PA_shift_convention(np.array(force['pa']), deg=True)

    if 'ap_doplot' in options and options['ap_doplot']:
        dat = IMG - results['background']
        ranges = [
            [
                max(
                    0,
                    int(results['center']['y'] -
                        (np.array(force['R'])[-1] / options['ap_pixscale']) *
                        1.2)),
                min(
                    dat.shape[1],
                    int(results['center']['y'] +
                        (np.array(force['R'])[-1] / options['ap_pixscale']) *
                        1.2))
            ],
            [
                max(
                    0,
                    int(results['center']['x'] -
                        (np.array(force['R'])[-1] / options['ap_pixscale']) *
                        1.2)),
                min(
                    dat.shape[0],
                    int(results['center']['x'] +
                        (np.array(force['R'])[-1] / options['ap_pixscale']) *
                        1.2))
            ]
        ]
        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        # plt.imshow(np.clip(dat[ranges[0][0]: ranges[0][1], ranges[1][0]: ranges[1][1]],
        #                    a_min = 0,a_max = None), origin = 'lower', cmap = 'Greys_r', norm = ImageNormalize(stretch=LogStretch()))
        for i in range(0, len(np.array(force['R'])), 2):
            plt.gca().add_patch(
                Ellipse(
                    (results['center']['x'] - ranges[0][0],
                     results['center']['y'] - ranges[1][0]),
                    2 * (np.array(force['R'])[i] / options['ap_pixscale']),
                    2 * (np.array(force['R'])[i] / options['ap_pixscale']) *
                    (1. - force['ellip'][i]),
                    force['pa'][i],
                    fill=False,
                    linewidth=0.5,
                    color='r'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sforcedfit_ellipse_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()
    res = {
        'fit ellip': np.array(force['ellip']),
        'fit pa': np.array(force['pa']) * np.pi / 180,
        'fit R': list(np.array(force['R']) / options['ap_pixscale'])
    }
    if 'ellip_e' in force and 'pa_e' in force:
        res['fit ellip_err'] = np.array(force['ellip_e'])
        res['fit pa_err'] = np.array(force['pa_e']) * np.pi / 180
    return IMG, res
Esempio n. 29
0
def Plot_EllipseModel(IMG, Model, R, modeltype, results, options):

    ranges = [
        [
            max(0, int(results["center"]["x"] - R[-1] * 1.2)),
            min(IMG.shape[1], int(results["center"]["x"] + R[-1] * 1.2)),
        ],
        [
            max(0, int(results["center"]["y"] - R[-1] * 1.2)),
            min(IMG.shape[0], int(results["center"]["y"] + R[-1] * 1.2)),
        ],
    ]
    plt.figure(figsize=(7, 7))
    autocmap.set_under("k", alpha=0)
    showmodel = Model[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]].copy()
    showmodel[showmodel > 0] += np.max(showmodel) / (10 ** 3.5) - np.min(
        showmodel[showmodel > 0]
    )
    plt.imshow(
        showmodel,
        origin="lower",
        cmap=autocmap,
        norm=ImageNormalize(stretch=LogStretch(), clip=False),
    )
    plt.axis("off")
    plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "ellipsemodel_%s_%s.jpg" % (modeltype, options["ap_name"]),
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()

    residual = (
        IMG[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]]
        - results["background"]
        - Model[ranges[1][0] : ranges[1][1], ranges[0][0] : ranges[0][1]]
    )
    plt.figure(figsize=(7, 7))
    plt.imshow(
        residual,
        origin="lower",
        cmap="PuBu",
        vmin=np.quantile(residual, 0.0001),
        vmax=0,
    )
    plt.imshow(
        np.clip(residual, a_min=0, a_max=np.quantile(residual, 0.9999)),
        origin="lower",
        cmap=autocmap,
        norm=ImageNormalize(stretch=LogStretch(), clip=False),
        interpolation="none",
        clim=[1e-5, None],
    )
    plt.axis("off")
    plt.subplots_adjust(left=0.03, right=0.97, top=0.97, bottom=0.05)
    if not ("ap_nologo" in options and options["ap_nologo"]):
        AddLogo(plt.gcf())
    plt.savefig(
        os.path.join(
            options["ap_plotpath"] if "ap_plotpath" in options else "",
            "ellipseresidual_%s_%s.jpg" % (modeltype, options["ap_name"]),
        ),
        dpi=options["ap_plotdpi"] if "ap_plotdpi" in options else 300,
    )
    plt.close()
Esempio n. 30
0
def Isophote_Fit_FFT_mean(IMG, results, options):
    """
    Fit isophotes by minimizing the amplitude of the second FFT coefficient, relative to the local median flux.
    Included is a regularization term which penalizes isophotes for having large differences between parameters
    of adjacent isophotes.
    """

    if 'ap_scale' in options:
        scale = options['ap_scale']
    else:
        scale = 0.2

    # subtract background from image during processing
    dat = IMG - results['background']
    mask = results['mask'] if 'mask' in results else None
    if not np.any(mask):
        mask = None

    # Determine sampling radii
    ######################################################################
    shrink = 0
    while shrink < 5:
        sample_radii = [3 * results['psf fwhm'] / 2]
        while sample_radii[-1] < (max(IMG.shape) / 2):
            isovals = _iso_extract(dat,
                                   sample_radii[-1],
                                   results['init ellip'],
                                   results['init pa'],
                                   results['center'],
                                   more=False,
                                   mask=mask)
            if np.mean(isovals) < (options['ap_fit_limit']
                                   if 'ap_fit_limit' in options else
                                   1) * results['background noise']:
                break
            sample_radii.append(sample_radii[-1] * (1. + scale /
                                                    (1. + shrink)))
        if len(sample_radii) < 15:
            shrink += 1
        else:
            break
    if shrink >= 5:
        raise Exception(
            'Unable to initialize ellipse fit, check diagnostic plots. Possible missed center.'
        )
    ellip = np.ones(len(sample_radii)) * results['init ellip']
    pa = np.ones(len(sample_radii)) * results['init pa']
    logging.debug('%s: sample radii: %s' %
                  (options['ap_name'], str(sample_radii)))

    # Fit isophotes
    ######################################################################
    perturb_scale = np.array([0.03, 0.06])
    regularize_scale = options[
        'ap_regularize_scale'] if 'ap_regularize_scale' in options else 1.
    N_perturb = 5

    count = 0

    count_nochange = 0
    use_center = copy(results['center'])
    I = np.array(range(len(sample_radii)))
    while count < 300 and count_nochange < (3 * len(sample_radii)):
        # Periodically include logging message
        if count % 10 == 0:
            logging.debug('%s: count: %i' % (options['ap_name'], count))
        count += 1

        np.random.shuffle(I)
        for i in I:
            perturbations = []
            perturbations.append({'ellip': copy(ellip), 'pa': copy(pa)})
            perturbations[-1]['loss'] = _FFT_mean_loss(
                dat,
                sample_radii,
                perturbations[-1]['ellip'],
                perturbations[-1]['pa'],
                i,
                use_center,
                results['background noise'],
                mask=mask,
                reg_scale=regularize_scale if count > 4 else 0,
                name=options['ap_name'])
            for n in range(N_perturb):
                perturbations.append({'ellip': copy(ellip), 'pa': copy(pa)})
                if count % 3 in [0, 1]:
                    perturbations[-1]['ellip'][i] = _x_to_eps(
                        _inv_x_to_eps(perturbations[-1]['ellip'][i]) +
                        np.random.normal(loc=0, scale=perturb_scale[0]))
                if count % 3 in [1, 2]:
                    perturbations[-1]['pa'][i] = (
                        perturbations[-1]['pa'][i] + np.random.normal(
                            loc=0, scale=perturb_scale[1])) % np.pi
                perturbations[-1]['loss'] = _FFT_mean_loss(
                    dat,
                    sample_radii,
                    perturbations[-1]['ellip'],
                    perturbations[-1]['pa'],
                    i,
                    use_center,
                    results['background noise'],
                    mask=mask,
                    reg_scale=regularize_scale if count > 4 else 0,
                    name=options['ap_name'])

            best = np.argmin(list(p['loss'] for p in perturbations))
            if best > 0:
                ellip = copy(perturbations[best]['ellip'])
                pa = copy(perturbations[best]['pa'])
                count_nochange = 0
            else:
                count_nochange += 1

    logging.info('%s: Completed isohpote fit in %i itterations' %
                 (options['ap_name'], count))
    # detect collapsed center
    ######################################################################
    for i in range(5):
        if (_inv_x_to_eps(ellip[i]) - _inv_x_to_eps(ellip[i + 1])) > 0.5:
            ellip[:i + 1] = ellip[i + 1]
            pa[:i + 1] = pa[i + 1]

    # Smooth ellip and pa profile
    ######################################################################
    smooth_ellip = copy(ellip)
    smooth_pa = copy(pa)
    ellip[:3] = min(ellip[:3])
    smooth_ellip = _ellip_smooth(sample_radii, smooth_ellip, 5)
    smooth_pa = _pa_smooth(sample_radii, smooth_pa, 5)

    if 'ap_doplot' in options and options['ap_doplot']:
        ranges = [[
            max(0, int(use_center['x'] - sample_radii[-1] * 1.2)),
            min(dat.shape[1], int(use_center['x'] + sample_radii[-1] * 1.2))
        ],
                  [
                      max(0, int(use_center['y'] - sample_radii[-1] * 1.2)),
                      min(dat.shape[0],
                          int(use_center['y'] + sample_radii[-1] * 1.2))
                  ]]
        LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]],
                 results['background noise'])
        # plt.imshow(np.clip(dat[ranges[1][0]: ranges[1][1], ranges[0][0]: ranges[0][1]],
        #                    a_min = 0,a_max = None), origin = 'lower', cmap = 'Greys', norm = ImageNormalize(stretch=LogStretch()))
        for i in range(len(sample_radii)):
            plt.gca().add_patch(
                Ellipse((use_center['x'] - ranges[0][0],
                         use_center['y'] - ranges[1][0]),
                        2 * sample_radii[i],
                        2 * sample_radii[i] * (1. - ellip[i]),
                        pa[i] * 180 / np.pi,
                        fill=False,
                        linewidth=((i + 1) / len(sample_radii))**2,
                        color='r'))
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sfit_ellipse_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

        plt.scatter(sample_radii, ellip, color='r', label='ellip')
        plt.scatter(sample_radii, pa / np.pi, color='b', label='pa/$np.pi$')
        show_ellip = _ellip_smooth(sample_radii, ellip, deg=5)
        show_pa = _pa_smooth(sample_radii, pa, deg=5)
        plt.plot(sample_radii,
                 show_ellip,
                 color='orange',
                 linewidth=2,
                 linestyle='--',
                 label='smooth ellip')
        plt.plot(sample_radii,
                 show_pa / np.pi,
                 color='purple',
                 linewidth=2,
                 linestyle='--',
                 label='smooth pa/$np.pi$')
        #plt.xscale('log')
        plt.legend()
        if not ('ap_nologo' in options and options['ap_nologo']):
            AddLogo(plt.gcf())
        plt.savefig(
            '%sphaseprofile_%s.jpg' %
            (options['ap_plotpath'] if 'ap_plotpath' in options else '',
             options['ap_name']),
            dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300)
        plt.close()

    # Compute errors
    ######################################################################
    ellip_err = np.zeros(len(ellip))
    ellip_err[:2] = np.sqrt(np.sum((ellip[:4] - smooth_ellip[:4])**2) / 4)
    ellip_err[-1] = np.sqrt(np.sum((ellip[-4:] - smooth_ellip[-4:])**2) / 4)
    pa_err = np.zeros(len(pa))
    pa_err[:2] = np.sqrt(np.sum((pa[:4] - smooth_pa[:4])**2) / 4)
    pa_err[-1] = np.sqrt(np.sum((pa[-4:] - smooth_pa[-4:])**2) / 4)
    for i in range(2, len(pa) - 1):
        ellip_err[i] = np.sqrt(
            np.sum((ellip[i - 2:i + 2] - smooth_ellip[i - 2:i + 2])**2) / 4)
        pa_err[i] = np.sqrt(
            np.sum((pa[i - 2:i + 2] - smooth_pa[i - 2:i + 2])**2) / 4)

    res = {
        'fit ellip':
        ellip,
        'fit pa':
        pa,
        'fit R':
        sample_radii,
        'fit ellip_err':
        ellip_err,
        'fit pa_err':
        pa_err,
        'auxfile fitlimit':
        'fit limit semi-major axis: %.2f pix' % sample_radii[-1]
    }
    return IMG, res