In [103]:
%matplotlib inline
%load_ext autoreload 
%autoreload 2

from __future__ import print_function, \
    division, \
    absolute_import

import os
import sys
import math
import glob
import copy
import warnings
import subprocess

import sep
import photutils

import numpy as np

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.gridspec as gridspec
from matplotlib.patches import Ellipse
from matplotlib.ticker import NullFormatter, MaxNLocator, FormatStrFormatter
from matplotlib.collections import PatchCollection
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
plt.rc('text', usetex=True)

from astropy import wcs
from astropy.io import fits
from astropy.visualization import ZScaleInterval, \
    PercentileInterval, \
    AsymmetricPercentileInterval
from astropy.convolution import Gaussian2DKernel
from astropy.convolution import convolve

# Increase the pixel stack for large image
sep.set_extract_pixstack(1000000)


The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

In [40]:
# Some useful functions from my code

from kungpao import io
from kungpao.galsbp import galSBP
from kungpao import utils
from kungpao import detection
from kungpao import imtools
from kungpao.display import display_single, IMG_CMAP, SEG_CMAP

In [4]:
# Convolution kernel I used for detecting objects on the image

kernel3 = np.asarray([[0.092163, 0.221178, 0.296069, 0.221178, 0.092163],
                      [0.221178, 0.530797, 0.710525, 0.530797, 0.221178],
                      [0.296069, 0.710525, 0.951108, 0.710525, 0.296069],
                      [0.221178, 0.530797, 0.710525, 0.530797, 0.221178],
                      [0.092163, 0.221178, 0.296069, 0.221178, 0.092163]])

# Directions to my IRAF executbles
ISO = '/Users/song/iraf/extern/stsdas/bin.macosx/x_isophote.e'
TBL = '/Users/song/iraf/extern/tables/bin.macosx/x_ttools.e'

Inspect the image


In [23]:
img_dir = '/Users/song/Dropbox/final-images-1/'

# One of my favorite galaxies of all time
hdr_test = fits.open(os.path.join(img_dir, 'M104subsky12.fits'))[0].header
img_test = fits.open(os.path.join(img_dir, 'M104subsky12.fits'))[0].data

# For running sep
img_test = img_test.byteswap().newbyteorder()

img_w, img_h = img_test.shape

In [19]:
# I just realize that these images do not have WCS information in the header.  
# It would be useful to have these information available 

wcs_test = wcs.WCS(hdr_test)

In [27]:
_ = display_single(img_test, contrast=0.2, scale_bar=None)


Image reduction

Measure and subtract a background to remove low-frequency structures

  • This will remove part of the extended halo. The purpose is to reduce the difficulty of source detection and deblending

In [30]:
bkg_local = sep.Background(img_test, bw=20, bh=20, fw=4, fh=4)

print("# Mean Sky / RMS Sky = %10.5f / %10.5f" % (bkg_local.globalback, bkg_local.globalrms))

_ = display_single(bkg_local.back(), contrast=0.5, scale_bar=None)


# The RMS map will be used as the image error for object detection 
_ = display_single(bkg_local.rms(), contrast=0.5, scale_bar=None)


# Mean Sky / RMS Sky =    1.72370 /   14.24700

In [31]:
# Subtract the very "local" sky background
img_subbkg = img_test - bkg_local.back()

# As you can see, most of the extended structures have been subtracted off.
_ = display_single(img_subbkg, contrast=0.3)


Detect objects to mask out


In [47]:
# Do not use very aggressive deblending to avoid breaking the main galaxy into many pieces
# Here we use a high threshold to make sure they represent the bright part of the image.
obj_hthre, seg_hthre = sep.extract(img_subbkg, 7.0,
                                   err=bkg_local.rms(), 
                                   minarea=50, 
                                   filter_kernel=kernel3,
                                   deblend_nthresh=48, deblend_cont=0.01,
                                   clean=True, clean_param=1.0,
                                   segmentation_map=True)

print("# Detect %d objects" % len(obj_hthre))

_ = display_single(seg_hthre, scale='linear', cmap=SEG_CMAP)


# Detect 1640 objects

Remove the target or any galaxy of interest

  • Normally, one can use the WCS information and the coordinate of the galaxy to do this.
  • Since there is no WCS information, you need to know where is the center of the galaxy manually from the image

In [53]:
# Rough center of the galaxy measured on the image
x_cen, y_cen = 2039, 1151

In [54]:
# Or if you know you galaxy is the brightest object on the image, you can do something like this: 

obj_bright = obj_hthre[np.argmax(obj_hthre['flux'])]
print(obj_bright['x'], obj_bright['y'])

# So, basically find the same galaxy


2039.1125325074615 1150.9399267214146

In [56]:
# Now, remove the segmentation associated with the galaxy
# Remember to reverse the order of x and y
seg_nocen = imtools.seg_remove_obj(seg_hthre, y_cen, x_cen)

_ = display_single(seg_nocen, scale='linear', cmap=SEG_CMAP)


Making a final object mask

  • The easiest way is to just grow the size of each segement vial convolution
  • You can separate the objects by type and/or brightness and/or distance to the target, and apply different convolution kernel and threshold to achieve more careful masking
  • You can also include specific masks for bright stars
    • If you have WCS information, I can easily show you how to do this through matching with GAIA catalog.

In [70]:
seg_conv = copy.deepcopy(seg_nocen)
seg_conv[seg_nocen > 0] = 1

# Convolve the image with a Gaussian kernel with the width of 5 pixel
# This is actually pretty slow, because the image is very large. 
seg_conv = convolve(seg_conv.astype('float'), Gaussian2DKernel(5.0))

seg_mask = seg_conv >= 0.01

_ = display_single(seg_mask.astype(int), cmap=SEG_CMAP)


Measure a more global background


In [80]:
# Low threshold detection to make sure every object is detected
obj_lthre, seg_lthre = sep.extract(img_test - bkg_local.globalback, 3.0,
                                   err=bkg_local.globalrms, 
                                   minarea=20, 
                                   deblend_nthresh=12, deblend_cont=0.1,
                                   clean=True, clean_param=1.0,
                                   segmentation_map=True)

_ = display_single(seg_lthre, cmap=SEG_CMAP)



In [81]:
seg_conv = copy.deepcopy(seg_lthre)
seg_conv[seg_lthre > 0] = 1

# Convolve the image with a Gaussian kernel with the width of 10 pixel
bkg_mask = convolve(seg_conv.astype('float'), Gaussian2DKernel(10.0))

bkg_mask = bkg_mask >= 0.005
_ = display_single(bkg_mask.astype(int), cmap=SEG_CMAP)



In [89]:
# If you trust your original sky subtraction, this step may not be necessary
# Here it is just for demonstration

bkg_global = sep.Background(img_test, 
                            mask=bkg_mask, maskthresh=0,
                            bw=500, bh=500, 
                            fw=50, fh=50)

print("# Mean Sky / RMS Sky = %10.5f / %10.5f" % (bkg_global.globalback, bkg_global.globalrms))

_ = display_single(bkg_global.back(), contrast=0.5, scale_bar=None)

img_corr = img_test - bkg_global.back()

_ = display_single(img_corr, contrast=0.3, scale_bar=None)


# Mean Sky / RMS Sky =   -0.33071 /   15.58530

Save the background subtracted image and the mask to FITS file


In [94]:
img_fits = '/Users/song/Downloads/m104_img.fits'
msk_fits = '/Users/song/Downloads/m104_msk.fits'

_ = io.save_to_fits(img_corr, img_fits)
_ = io.save_to_fits(seg_mask.astype('uint8'), msk_fits)

Running Ellipse for 1-D profile


In [98]:
# Before runnning Ellipse, we need to know something about the galaxy 
# Centeral coordinate 
x_cen, y_cen = x_cen, y_cen

# Initial guess of axis ratio and position angle 
ba_ini, pa_ini = 0.6, 90.0

# Initial radius of Ellipse fitting
sma_ini = 10.0

# Minimum and maximum radiuse of Ellipse fitting
sma_min, sma_max = 0.0, 1000.0

# Stepsize of Ellipse fitting
# By default we are not using linear step size
step = 0.10

# Behaviour of Ellipse fitting
# Ellipse can fix certain parameters at the input values or fit everything
stage = 1    # Fit everything, let the center, shape of each isophote to be free
stage = 2    # Fix the central coordinate of every isophote at the x_cen / y_cen position
stage = 3    # Fix the central coordinate and shape of every isophote at input values
stage = 4    # This is the "force photometry" mode, need an external Ellipse output binary table as template (use `inEllip` parameter)
# Here we start with step 1
stage = 1

# Pixel scale of the image
# Used to convert the intensity into surface brightness unit
# Since we do not have WCS here, I just write down 1.0 pixel / arcsec
pix_scale = 1.0

# Photometric zeropoint 
# Used to convert the intensity into surface brightness unit
# I am not sure about the calibration details, so just put 0.0 for now
zeropoint = 0.0

# Exposure time
# Used to convert the intensity into surface brightness unit
# I assume the image is normalized into 1 sec exposure time
exptime = 1.0

# Along each isophote, Ellipse will perform sigmal clipping to remove problematic pixels
# The behaviour is decided by these three parameters: Number of sigma cliping, lower, and upper clipping threshold 
n_clip, low_clip, upp_clip = 2, 3.0, 3.0

# After the clipping, Ellipse can use the mean, median, or bi-linear interpolation of the remain pixel values
# as the "average intensity" of that isophote 
integrade_mode = 'median'   # or 'mean', or 'bi-linear'


# Start running Ellipse like this 
# Step 1 will take a long time, ~ 10 mins on my computer, you can use larger stepsize to shorten the process
ell_1, bin_1 = galSBP.galSBP(img_fits, 
                             mask=msk_fits,
                             galX=x_cen, galY=y_cen,
                             galQ=ba_ini, galPA=pa_ini,
                             iniSma=sma_ini, 
                             minSma=sma_min, maxSma=sma_max,
                             pix=pix_scale, zpPhoto=zeropoint,
                             expTime=exptime, 
                             stage=stage,
                             ellipStep=step,
                             isophote=ISO, 
                             xttools=TBL, 
                             uppClip=upp_clip, lowClip=low_clip, 
                             nClip=n_clip, 
                             maxTry=3,
                             intMode=integrade_mode, 
                             saveOut=True, plMask=True,
                             verbose=True, savePng=False, 
                             updateIntens=False)


/Users/song/Downloads/m104_msk.fits -> temp_982RQ.fits.pl
/Users/song/Downloads/m104_msk.fits -> temp_982RQ.pl
----------------------------------------------------------------------------------------------------
###      galX, galY :  2039 1151
###      galR :  20.0
###      iniSma, maxSma :  10.0 1000.0
###      Stage :  1
###      Step :  0.1
----------------------------------------------------------------------------------------------------
##       Set up the Ellipse configuration
----------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------
##       Start the Ellipse Run: Attempt  1
----------------------------------------------------------------------------------------------------
###      Origin Image  : /Users/song/Downloads/m104_img.fits
###      Input Image   : temp_982RQ.fits
###      Output Binary : /Users/song/Downloads/m104_img_ellip_1.bin
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
###     Input background value   :  0.0
###     1-D SBP background value :  0.0
###     Current outer background :  0.0
----------------------------------------------------------------------------------------------------

In [100]:
# The out put file is a astropy.table

# The output binary file is at bin_1
print("# Output file: %s" % bin_1)

ell_1


# Output file: /Users/song/Downloads/m104_img_ellip_1.bin
Out[100]:
<Table length=81>
smaintensint_errpix_varrmsellell_errpapa_errx0x0_erry0y0_errgradgrad_errgrad_r_errrsmamagmag_lerrmag_uerrtflux_etflux_ctmag_etmag_cnpix_enpix_ca3a3_errb3b3_erra4a4_errb4b4_errndatanflagniterstopa_bigsareaa1a1_errb1b1_erra2a2_errb2b2_errpa_normsbp_orisbp_subsbpintens_subintens_bkgsbp_errsbp_lowsbp_uppsma_asecrsma_asecgrowth_origrowth_subavg_x0avg_y0avg_qavg_paavg_bkgintens_corsbp_corgrowth_corrad_outermag_totmag_tot_orimag_tot_sub
float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64int64int64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64float64
0.042178.07nannannannannannannan2039.304nan1157.591nan334.0568nannan0.0-11.56272nannannannannannannannannannannannannannannannan10nannannannannannannannannannannannannan-11.562716758119453-11.562716758119453-11.56271675811945342178.070.0nannannan0.00.00.00.02039.61611728311481154.9794899457660.482389437625296288.592435739618180.042178.07-11.5627167581194530.0801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.520986542352.1115.5798179.4417756.173820.6309919nan76.78014nan2039.304nan1157.591nan-5.173479447.03486.408780.8495846-11.567190.00039912880.00039959142178.0742178.07-11.56272-11.562721.01.05.018115433.70490.718931762.736353.176209274.602-2.220266192.04521301.04.0187.05862.072.522167.813622.9111917.5530119.82862.673317-11.433272.57943676.78014-11.567187629850384-11.567187629850384-11.56718762985038442352.110.00.00039932964924105363-11.567586959499625-11.5667883002011430.52098650.849584572403440.00.02039.61611728311481154.9794899457660.482389437625296288.592435739618180.042352.11-11.5671876298503840.0801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.573085142351.8417.3114888.2715862.417430.6309919nan76.78014nan2039.304nan1157.591nan-6.54353453.176669.255680.8700712-11.567180.00044384520.00044380542178.0742178.07-11.56272-11.562721.01.03.847007266.52580.912347663.56882.644436183.2842-1.750179121.4051301.04.0187.05862.079.640579.1663034.7543998.86057623.806872.932164-12.946562.82919376.78014-11.567180708124178-11.567180708124178-11.56718070812417842351.840.00.0004437082363448752-11.567624416360523-11.5667369998878340.57308510.87007117165552672798.5292666526822798.5292666526822039.61611728311481154.9794899457660.482389437625296288.592435739618180.042351.84-11.5671807081241782798.529266652682801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.630393642351.4619.3597398.7156369.802490.6309919nan76.78014nan2039.304nan1157.591nan-7.869587458.973158.322380.8910518-11.567170.00049642310.000496183742178.0742178.07-11.56272-11.562721.01.03.084227179.98231.04351561.140622.320643135.4804-1.46304285.522771301.04.0187.05862.087.4149110.82486.91779510.4637528.583553.27302-14.866463.15807976.78014-11.567170966360685-11.567170966360685-11.56717096636068542351.460.00.0004961991157017565-11.567667165476387-11.5666747672449830.63039360.89105179383645486184.7214912537536184.7214912537532039.61611728311481154.9794899457660.482389437625296288.592435739618180.042351.46-11.5671709663606856184.721491253753801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.69343342350.9721.50211109.639777.526970.6309919nan76.78014nan2039.304nan1157.591nan-7.717491462.727659.95830.9125383-11.567160.00055175430.000550821242178.0742178.07-11.56272-11.562721.01.03.007915180.45841.36165281.864432.500426150.0505-1.51668691.131641301.04.0187.05862.095.9010212.831329.43689412.4033534.262653.728474-17.241483.59753976.78014-11.567158404484-11.567158404484-11.56715840448442350.970.00.000551101778338392-11.567709506262338-11.566607302705660.6934330.912538352910883710281.97002056638310281.9700205663832039.61611728311481154.9794899457660.482389437625296288.592435739618180.042350.97-11.56715840448410281.970020566383801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.762776342350.4323.81677121.442285.872580.6309919nan76.78014nan2039.304nan1157.591nan-3.631862nannan0.934543-11.567140.00061049310.000610667342178.0742178.07-11.56272-11.562721.01.06.0825614.321643.43637313.23655.57781214.09387-3.19810113.006651301.04.0187.05862.0105.164815.1779412.0598714.671740.982734.233657-19.899744.0849876.78014-11.567144560614818-11.567144560614818-11.56714456061481842350.430.00.0006104179121422248-11.56775497852696-11.5665341427026750.76277630.934543019030608415239.57480422384815239.5748042238482039.61611728311481154.9794899457660.482389437625296288.592435739618180.042350.43-11.56714456061481815239.574804223848801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.83905442351.1626.4516134.877295.372580.6309919nan76.78014nan2039.304nan1157.591nan-4.539828nannan0.9570783-11.567160.00067866610.000677666242178.0742178.07-11.56272-11.562721.01.04.78656311.457542.48550210.569144.41429211.30325-1.87074310.351211301.04.0187.05862.0115.530217.2554612.2814516.6799348.495293.91718-20.442153.77961876.78014-11.567163275433028-11.567163275433028-11.56716327543302842351.160.00.0006779151918401283-11.567841190624868-11.5664853602411880.8390540.95707831878916421238.3857601238221238.385760123822039.61611728311481154.9794899457660.482389437625296288.592435739618180.042351.16-11.56716327543302821238.38576012382801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
0.922959442351.9829.18197148.7994105.21710.6309919nan76.78014nan2039.304nan1157.591nan-5.674785nannan0.980157-11.567180.00074864830.000747654442178.0742178.07-11.56272-11.562721.01.03.7350889.18031.7827438.4651673.5025019.08558-0.95340828.2795051301.04.0187.05862.0126.840919.8477812.3752319.1857957.467073.591613-21.133383.46548376.78014-11.567184297172904-11.567184297172904-11.56718429717290442351.980.00.000747851947213718-11.567932149120118-11.566436445225690.92295940.980157007797909428497.08178911948628497.0817891194862039.61611728311481154.9794899457660.482389437625296288.592435739618180.042351.98-11.56718429717290428497.081789119486801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
1.01525542353.1132.04822163.4145115.55150.6309919nan76.78014nan2039.304nan1157.591nan-7.093481nannan1.003792-11.567210.00082155220.000821512842178.07211356.9-11.56272-13.312541.05.02.8334357.339041.2261576.7811542.7807527.302688-0.37924786.6418891301.04.0187.05862.0138.885522.9484912.5246522.1830867.848983.3338-21.959283.21672576.78014-11.56721326548901-11.56721326548901-11.5672132654890142353.110.00.0008212562078995234-11.568034521696909-11.566392009281111.0152551.00379212509760337280.304428907337280.30442890732039.61611728311481154.9794899457660.482389437625296288.592435739618180.042353.11-11.5672132654890137280.3044289073801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
1.11678142356.1934.93153178.1165125.94740.6309919nan76.78014nan2039.304nan1157.591nan-8.866851nannan1.027997-11.567290.00089569650.000895042242178.07211356.9-11.56272-13.312541.05.01.8265295.7180060.86429285.3588082.0462875.753754-0.072233625.2619991301.04.0187.05862.0150.119225.7312115.0273824.8729977.637912.590127-21.35952.49916876.78014-11.56729221945303-11.56729221945303-11.5672922194530342356.190.00.0008950473654376623-11.568187266818468-11.5663971720875921.1167811.027997371370191847908.8654254862147908.865425486212039.61611728311481154.9794899457660.482389437625296288.592435739618180.042356.19-11.5672922194530347908.86542548621801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
...........................................................................................................................................................................................................................
411.44895.189090.30050785.640923.2918890.15088740.00359147583.273040.7110372041.3180.86539541157.0550.7168416-0.4526370.013315870.029418434.503796-4.9464680.0034329170.003422322279031904.0284503776.0-21.11413-21.13522382034.0446731.0-0.0022771810.0020021120.0039297420.0020271430.0072414390.0017220240.0088009520.0017469041206200.02.00.05481157676.81840.054930450.31540160.12514330.32422250.0055121210.31436280.092605410.325124183.27304-4.946467937549514-4.946467937549514-4.94646793754951495.189090.00.0034222136195776187-4.949890151169091-4.943045723929936411.4484.503796290750166250201442.12000945250201442.120009452039.61611728311481154.9794899457660.482389437625296288.592435739618180.095.18909-4.946467937549514250201442.12000945801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
452.592871.199660.268206388.094582.9986370.11170920.00436972480.489281.1998072042.8211.1146771157.9190.9990042-0.34414790.010660450.030976354.6124-4.6311950.0040973820.004082429287166848.0291070624.0-21.14534-21.16479735.0539810.00.002719280.0024228720.0036275530.0024162930.0042645730.0021357660.011749220.0021736251251200.02.00.1488963863.0789-0.021472960.3333125-0.034650.3324715-0.03123980.3346599-0.013405910.331101880.48928-4.631194799384401-4.631194799384401-4.63119479938440171.199660.00.004082241290067401-4.6352770406744686-4.627112558094334452.59284.612399434204993258748690.74173987258748690.741739872039.61611728311481154.9794899457660.482389437625296288.592435739618180.071.19966-4.631194799384401258748690.74173987801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
497.852151.935760.261827295.323072.8800990.068277430.00481353878.401972.0782522039.5951.2573791156.6061.218391-0.25607120.009431720.036832424.723621-4.2886660.0054874130.005459799294984768.0296933248.0-21.1745-21.18165607284.0647241.0-0.00025367270.0025101630.0038772480.0025448040.00080123260.0022710280.012559410.0022468191215200.02.00.013234311095.421-0.0085967960.2899381-0.026658990.27997270.012760560.2838547-0.062003240.285783878.40197-4.288666228088481-4.288666228088481-4.28866622808848151.935760.00.005459843117173513-4.294126071205654-4.283206384971307497.85214.723621447534691266739662.52529806266739662.525298062039.61611728311481154.9794899457660.482389437625296288.592435739618180.051.93576-4.288666228088481266739662.52529806801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
547.637337.869320.2959247119.64163.2551710.043234380.00718074262.226064.8684132038.6782.026611160.8971.996615-0.19553370.0086096390.044031484.837525-3.9457190.0085177870.008451264301315552.0302499776.0-21.19755-21.20181748885.0781228.00.0092710550.0035840130.0082858010.003549710.008945970.0032618970.012411940.0033004251215200.02.00.035250561350.879-0.018397750.3505969-0.049211260.34443430.066880350.3476112-0.062935110.347152462.22606-3.945718766967689-3.945718766967689-3.94571876696768937.869320.00.008451361146869285-3.9541701281145585-3.93726740582082547.63734.83752536438954273402771.44511807273402771.445118072039.61611728311481154.9794899457660.482389437625296288.592435739618180.037.86932-3.945718766967689273402771.44511807801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
602.40127.035830.184839482.317282.0416180.048214340.00536134142.072623.2977852043.9071.6600561156.6421.668764-0.14107830.0064430850.045670274.954176-3.5798490.0074484740.007397735306287744.0307506208.0-21.21532-21.21964900801.0948294.00.011118030.002629442-0.0068019730.0025253520.011105520.002366303-0.0047584430.0022866661224200.02.00.0054602031625.6720.024903810.19454810.093770890.19493140.078100840.19556990.032937680.193700542.07262-3.579849267393016-3.579849267393016-3.57984926739301627.035830.00.007397735101464242-3.5872470024944803-3.5724515322915518602.4014.954175885284173278367278.43475264278367278.434752642039.61611728311481154.9794899457660.482389437625296288.592435739618180.027.03583-3.579849267393016278367278.43475264801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
662.641119.08320.156063776.319741.730830.066509270.0060210728.166192.6691362041.7092.0130041154.9672.112186-0.10107350.0058209440.057591215.073639-3.2016280.0089157440.008843032310251456.0311623520.0-21.22928-21.234081071428.01150829.00.0097465590.002815434-0.015013460.0028640480.00172280.0026798-0.0076084510.0026568481233200.02.00.010326751944.3080.013217550.1758996-0.031820150.1788907-0.026201290.17694980.043706770.177743428.16619-3.2016280047743417-3.2016280047743417-3.201628004774341719.08320.00.008843113395700097-3.210471118170042-3.1927848913786416662.64115.073639342251571282234090.2158741282234090.21587412039.61611728311481154.9794899457660.482389437625296288.592435739618180.019.0832-3.2016280047743417282234090.2158741801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
728.905213.332770.144071175.463271.578220.092640360.00681013319.490262.1322352044.3332.4355661158.3532.701747-0.063501760.0047454230.0747295.195983-2.8123010.011796120.01166935313424096.0314814816.0-21.24033-21.245141263091.01389041.00.0032192690.003225191-0.017551710.003576828-0.0033893250.003074238-0.011335850.0032118531206200.02.00.039168022286.315-0.0071557430.140279-0.021054140.1448879-0.019621130.14033480.035337870.144702119.49026-2.812300968197018-2.812300968197018-2.81230096819701813.332770.00.01166930132042543-2.8239702695174436-2.8006316668765927728.90525.195983486056043285257986.2942685285257986.29426852039.61611728311481154.9794899457660.482389437625296288.592435739618180.013.33277-2.812300968197018285257986.2942685801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
801.79589.9867210.142256381.47421.5904730.13906020.0107546412.235592.392672050.3724.3513771164.3944.99588-0.040740930.0043614460.10705325.321278-2.4985570.0155770.01535661315624832.0317358720.0-21.24793-21.253881449142.01682631.0-0.013367150.005412958-0.034925840.006378672-0.017327950.0053082070.0021951920.0049314651251200.02.00.0081067162624.142-0.0052425540.16149950.016524890.1618515-0.0095926160.16205690.013164620.161286212.23559-2.4985572927961166-2.4985572927961166-2.49855729279611669.9867210.00.015356701801906514-2.513913994598023-2.48320059099421801.79585.321277949060709287497956.15009946287497956.150099462039.61611728311481154.9794899457660.482389437625296288.592435739618180.09.986721-2.4985572927961166287497956.15009946801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
881.97547.1763090.202412123.11912.2265320.17070820.011480297.2917732.1253892062.8115.0457611178.7966.189616-0.042703890.004215570.09871635.449594-2.1397530.031064050.03019989317783808.0319157312.0-21.25533-21.260011687833.02033581.0-0.037301680.00678663-0.021087370.005950856-0.015949440.0056913020.0047847670.0054056711215200.02.00.023420763057.689-0.056122780.20191180.11453310.2064721-0.10341670.20466290.08002310.20299967.291773-2.139752826102393-2.139752826102393-2.1397528261023937.1763090.00.03019989729651007-2.169952723398903-2.1095529288058827881.97545.449593621950523289563353.1902706289563353.19027062039.61611728311481154.9794899457660.482389437625296288.592435739618180.07.176309-2.139752826102393289563353.1902706801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957
970.1734.5467350.1862986121.08682.0407990.21067590.012116187.2917731.8692282070.7575.8697861179.8137.585834-0.032218350.0035536620.11029935.581004-1.6442490.04542430.04359989319291552.0320121728.0-21.26047-21.263291930945.02449127.0-0.048755430.008028769-0.021429560.006246048-0.019955070.0060030350.0071498970.0055434781206200.02.00.14276343520.411-0.079384120.17020320.15587530.1747181-0.14899220.17277710.10790960.17048577.291773-1.6442491067622147-1.6442491067622147-1.64424910676221474.5467350.00.04359986212105782-1.6878489688832725-1.6006492446411569970.1735.581003514475603290961041.1716606290961041.17166062039.61611728311481154.9794899457660.482389437625296288.592435739618180.04.546735-1.6442491067622147290961041.1716606801.2093045826115-21.154358992963957-21.154358992963957-21.154358992963957

In [105]:
# The useful information in the outputs are 
# sma:  distance along the major axis in unit of pixel 
# intens, int_err:  average intensity at different radius along the major axis and associated error 
# x0, y0, x0_err, y0_err:  central coordinates and their errors
# ell, ell_err:  ellipticity and its error
# pa, pa_err:  position angle and its error
# a3, a4, b3, b4:  amplitudes of the higher order Fourier components

# You can visualize the isophotes using 

def display_isophote(img, ell):
    """Visualize the isophotes."""
    fig = plt.figure(figsize=(12, 12))
    fig.subplots_adjust(left=0.0, right=1.0, 
                        bottom=0.0, top=1.0,
                        wspace=0.00, hspace=0.00)
    gs = gridspec.GridSpec(2, 2)
    gs.update(wspace=0.0, hspace=0.00)

    # Whole central galaxy: Step 2
    ax1 = fig.add_subplot(gs[0])
    ax1.yaxis.set_major_formatter(NullFormatter())
    ax1.xaxis.set_major_formatter(NullFormatter())

    ax1 = display_single(img, ax=ax1, scale_bar=False)

    for k, iso in enumerate(ell):
        if k % 2 == 0:
            e = Ellipse(xy=(iso['x0'], iso['y0']),
                        height=iso['sma'] * 2.0,
                        width=iso['sma'] * 2.0 * (1.0 - iso['ell']),
                        angle=iso['pa'])
            e.set_facecolor('none')
            e.set_edgecolor('r')
            e.set_alpha(0.5)
            e.set_linewidth(1.5)
            ax1.add_artist(e)
    ax1.set_aspect('equal')

In [106]:
_ = display_isophote(img_test, ell_1)


  • You can use the following functions to visualize the results in 1-D profiles

In [131]:
def display_center_fourier(ell, x_max=4.0):
    """Display the 1-D profiles."""
    fig = plt.figure(figsize=(10, 10))
    fig.subplots_adjust(left=0.0, right=1.0, 
                        bottom=0.0, top=1.0,
                        wspace=0.00, hspace=0.00)

    ax1 = fig.add_axes([0.08, 0.07, 0.85, 0.23])
    ax2 = fig.add_axes([0.08, 0.30, 0.85, 0.23])
    ax3 = fig.add_axes([0.08, 0.53, 0.85, 0.23])
    ax4 = fig.add_axes([0.08, 0.76, 0.85, 0.23])

    # A3 / B3 profile
    ax1.grid(linestyle='--', alpha=0.4, linewidth=2)

    ax1.errorbar((ell['sma'] ** 0.25), 
                 ell['a3'],
                 yerr=ell['a3_err'],
                 color='k', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)
    
    ax1.errorbar((ell['sma'] ** 0.25), 
                 ell['b3'],
                 yerr=ell['b3_err'],
                 color='r', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)
    
    for tick in ax1.xaxis.get_major_ticks():
        tick.label.set_fontsize(25)
    for tick in ax1.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax1.set_xlim(1.09, x_max)
    ax1.set_ylim(-0.9, 0.9)

    ax1.set_xlabel(r'$R/\mathrm{pixel}^{1/4}$', fontsize=30)
    ax1.set_ylabel(r'${A_3\ {\rm or}\ B_3}$', fontsize=30)

    # A4/ B4 profile
    ax2.grid(linestyle='--', alpha=0.4, linewidth=2)
    
    ax2.errorbar((ell['sma'] ** 0.25), 
                 ell['a4'],
                 yerr=ell['a4_err'],
                 color='k', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)
    
    ax2.errorbar((ell['sma'] ** 0.25), 
                 ell['b4'],
                 yerr=ell['b4_err'],
                 color='r', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)

    ax2.xaxis.set_major_formatter(NullFormatter())
    for tick in ax2.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax2.set_xlim(1.09, x_max)
    ax2.set_ylim(-0.9, 0.9)
    ax2.set_ylabel(r'${A_4\ {\rm or}\ B_4}$', fontsize=30)
    
    # X central coordinate profile
    ax3.grid(linestyle='--', alpha=0.4, linewidth=2)
    
    ax3.errorbar((ell['sma'] ** 0.25), 
                 ell['x0'],
                 yerr=ell['x0_err'],
                 color='k', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)
    
    ax3.xaxis.set_major_formatter(NullFormatter())
    for tick in ax3.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax3.set_xlim(1.09, x_max)
    ax3.set_ylabel(r'$\mathrm{X_0}$', fontsize=32)

    # Position Angle profile
    ax4.grid(linestyle='--', alpha=0.4, linewidth=2)

    ax4.errorbar((ell['sma'] ** 0.25), 
                 ell['y0'], yerr=ell['y0_err'],
                 color='k', alpha=0.7, fmt='o', 
                 capsize=4, capthick=2, elinewidth=2)

    ax4.xaxis.set_major_formatter(NullFormatter())
    for tick in ax4.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax4.set_xlim(1.09, x_max)
    ax4.set_ylabel(r'$\mathrm{Y_0}$', fontsize=25)
    
    return fig


def display_intensity_shape(ell, x_max=4.0):
    """Display the 1-D profiles."""
    fig = plt.figure(figsize=(10, 10))
    fig.subplots_adjust(left=0.0, right=1.0, 
                        bottom=0.0, top=1.0,
                        wspace=0.00, hspace=0.00)

    ax1 = fig.add_axes([0.08, 0.07, 0.85, 0.48])
    ax2 = fig.add_axes([0.08, 0.55, 0.85, 0.20])
    ax3 = fig.add_axes([0.08, 0.75, 0.85, 0.20])

    # 1-D profile
    ax1.grid(linestyle='--', alpha=0.4, linewidth=2)

    yerr = np.log10(ell['intens'] + ell['int_err']) - np.log10(ell['intens'])
    ax1.errorbar((ell['sma'] ** 0.25), 
                 np.log10(ell['intens']),
                 yerr=yerr,
                 color='k', alpha=0.7, fmt='o', 
                 capsize=4, capthick=1, elinewidth=1)

    for tick in ax1.xaxis.get_major_ticks():
        tick.label.set_fontsize(25)
    for tick in ax1.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax1.set_xlim(1.09, x_max)

    ax1.set_xlabel(r'$R/\mathrm{pixel}^{1/4}$', fontsize=30)
    ax1.set_ylabel(r'$\log\ ({\rm Intensity})$', fontsize=30)

    # Ellipticity profile
    ax2.grid(linestyle='--', alpha=0.4, linewidth=2)

    ax2.errorbar((ell['sma'] ** 0.25), 
                 ell['ell'],
                 yerr=ell['ell_err'],
                 color='k', alpha=0.7, fmt='o', capsize=4, capthick=2, elinewidth=2)

    ax2.xaxis.set_major_formatter(NullFormatter())
    for tick in ax2.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax2.set_xlim(1.09, x_max)
    ax2.set_ylabel(r'$e$', fontsize=35)

    # Position Angle profile
    ax3.grid(linestyle='--', alpha=0.4, linewidth=2)

    ax3.errorbar((ell['sma'] ** 0.25), 
                 ell['pa'], yerr=ell['pa_err'],
                 color='k', alpha=0.7, fmt='o', capsize=4, capthick=2, elinewidth=2)

    ax3.xaxis.set_major_formatter(NullFormatter())
    for tick in ax3.yaxis.get_major_ticks():
        tick.label.set_fontsize(25)

    ax3.set_xlim(1.09, x_max)
    ax3.set_ylabel(r'$\mathrm{PA\ [deg]}$', fontsize=25)
    
    return fig

In [126]:
# First, let's see the central coordinates and the higher order shape of the isophote

# Notice that I use r^0.25 as coordinate, you can also use linear for disk galaxy or using log10(r)

# Sudden change of central coordinates and higher order shape can hint significant structural change 
# e.g. impact of dust lane, transition from disk to bulge, overall asymmetric, etc.

_ = display_center_fourier(ell_1, x_max=(1000 ** 0.25))



In [132]:
# Now we can take a look at the intensity profile and the elliptical, positional angle profile 

# The change of PA at large radius clearly suggests the transition between two component. 

# The ellipticity profile also shows a change from a highly elliptical structure (disk) to a round structure (bulge or halo)

_ = display_intensity_shape(ell_1, x_max=(1000 ** 0.25))



In [143]:
# We should not let everything to be free during the fitting once we understand the basic structure 
# of the galaxy. 

# Centeral coordinate 
# We need to fix the center, we can use an average value in the central region
x_cen_fix = np.nanmedian(ell_1['x0'][0:20])
y_cen_fix = np.nanmedian(ell_1['y0'][0:20])
print(x_cen_fix, y_cen_fix)

# Initial guess of axis ratio and position angle 
# Use more appropriate guesses for axis ratio and position angle based on the stage=1 result
ba_ini, pa_ini = 0.3, 90.0

# Initial radius of Ellipse fitting
sma_ini = 10.0

# Minimum and maximum radiuse of Ellipse fitting
sma_min, sma_max = 0.0, 1900.0

# Stepsize of Ellipse fitting
# Use larger stepsize to speed things up a little
step = 0.12

# Behaviour of Ellipse fitting
# Now we fix the center, but still let the shape of the isophote to change
stage = 2

# The rest parameters are the same 


# Start running Ellipse like this 
# Step 2 will take a few minutes
ell_2, bin_2 = galSBP.galSBP(img_fits, 
                             mask=msk_fits,
                             galX=x_cen_fix, galY=y_cen_fix,
                             galQ=ba_ini, galPA=pa_ini,
                             iniSma=sma_ini, 
                             minSma=sma_min, maxSma=sma_max,
                             pix=pix_scale, zpPhoto=zeropoint,
                             expTime=exptime, 
                             stage=stage,
                             ellipStep=step,
                             isophote=ISO, 
                             xttools=TBL, 
                             uppClip=upp_clip, lowClip=low_clip, 
                             nClip=n_clip, 
                             maxTry=3,
                             intMode=integrade_mode, 
                             saveOut=True, plMask=True,
                             verbose=True, savePng=False, 
                             updateIntens=False)


2039.304 1157.591
/Users/song/Downloads/m104_msk.fits -> temp_J41XX.fits.pl
/Users/song/Downloads/m104_msk.fits -> temp_J41XX.pl
----------------------------------------------------------------------------------------------------
###      galX, galY :  2039.304 1157.591
###      galR :  20.0
###      iniSma, maxSma :  10.0 1900.0
###      Stage :  2
###      Step :  0.12
----------------------------------------------------------------------------------------------------
##       Set up the Ellipse configuration
----------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------
##       Start the Ellipse Run: Attempt  1
----------------------------------------------------------------------------------------------------
###      Origin Image  : /Users/song/Downloads/m104_img.fits
###      Input Image   : temp_J41XX.fits
###      Output Binary : /Users/song/Downloads/m104_img_ellip_2.bin
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
###     Input background value   :  0.0
###     1-D SBP background value :  0.0
###     Current outer background :  0.0
----------------------------------------------------------------------------------------------------

In [144]:
# Now we can see that the overall light in M104 is still dominated by the disk components

_ = display_isophote(img_test, ell_2)

_ = display_center_fourier(ell_2, x_max=(1950 ** 0.25))

_ = display_intensity_shape(ell_2, x_max=(1950 ** 0.25))



In [ ]: