扩展孔径光度测量#

用例: 在一个区域内测量星系光度。相关于 JDox 科学用例 #22

数据: WST 模拟的 NIRCam 图像来自 JADES JWST GTO 外星系空白场

(Williams et al. 2018)https://ui.adsabs.harvard.edu/abs/2018ApJS..236…33W。

工具: photutils, matplotlib, scipy, scikit。

跨仪器: 可能涉及 MIRI。

文档: 本笔记本是 STScI 更大 后处理数据分析工具生态系统 的一部分。

引言#

本笔记本使用 photutils 检测 NIRCam 深成像中的物体/星系。首先在 F200W 图像中进行检测,然后在所有 9 个滤光片(F090W, F115W, F150W, F200W, F277W, F335M, F356W, F410M, F444W)中获得等光度光度测量。目录被重新加载,并对完整目录和单个星系进行一些简单分析。

该笔记本仅分析 JADES 模拟的中央 1000 x 1000 像素(30” x 30”)。这些切片已获得 STScI 的授权,并由作者(Williams et al.)提供。

注意: 光度测量是经过孔径匹配的,但未进行 PSF 校正。为了获得更准确的颜色测量,应该实施 PSF 校正,因为波长范围很大(因此 PSF FWHM 跨越 >4 的因子)。

注意: 模拟的 JADES 图像的单位(e-/s)与 JWST 管道产品(MJy/sr)不同。

注意: 缺少曝光图,但计算通量不确定性是必需的。

待办事项#

  • PSF(点扩散函数)校正

  • 检查光度测量的准确性与模拟的JADES(James Webb Space Telescope Advanced Deep Extragalactic Survey)目录的对比

  • 需要曝光图以用于误差计算

  • AB(天文带)磁单位无法写入ecsv文件(即将发布astropy更新)

  • 带文本标签的图表看起来很糟糕(我希望光标悬停时能显示ID号码)

  • 修复图表的次要轴:磁量与通量

  • requirements.txt文件——但我不知道需要哪些版本

  • Robel的其他评论:https://github.com/spacetelescope/dat_pyinthesky/pull/82#pullrequestreview-355206337

下载WEBBPSF数据#

import os  # 导入操作系统模块

import tarfile  # 导入tarfile模块,用于处理tar文件

import urllib.request  # 导入urllib.request模块,用于处理URL请求

boxlink = 'https://stsci.box.com/shared/static/34o0keicz2iujyilg4uz617va46ks6u9.gz'  # 设置文件下载链接

boxfile = './webbpsf-data/webbpsf-data-1.0.0.tar.gz'  # 设置下载后保存的文件路径

webbpsf_folder = './webbpsf-data'  # 设置存放解压文件的文件夹路径

# 检查指定路径是否存在

isExist = os.path.exists(webbpsf_folder)

if not isExist:  # 如果路径不存在

  # 创建一个新目录,因为它不存在 

  os.makedirs(webbpsf_folder)  # 创建目录
    

urllib.request.urlretrieve(boxlink, boxfile)  # 从指定链接下载文件并保存到指定路径

gzf = tarfile.open(boxfile)  # 打开下载的tar.gz文件

gzf.extractall(webbpsf_folder, filter='data')  # 解压所有文件到指定文件夹,使用filter='data'跳过绝对路径或相对路径

导入包#

import os  # 导入操作系统模块,用于文件和目录操作

import numpy as np  # 导入NumPy库,用于数值计算

from astropy.convolution import convolve  # 从Astropy库导入卷积函数
from astropy.io import fits  # 从Astropy库导入FITS文件处理模块
from astropy.stats import gaussian_fwhm_to_sigma  # 导入高斯全宽半高转换函数
from astropy.table import QTable  # 从Astropy库导入QTable类,用于表格数据处理
import astropy.units as u  # 导入Astropy单位模块
from astropy.visualization import make_lupton_rgb, SqrtStretch, ImageNormalize, simple_norm  # 导入图像可视化相关函数
import astropy.wcs as wcs  # 导入Astropy的WCS模块,用于天文坐标转换

from photutils.background import Background2D, MedianBackground  # 导入背景处理模块
from photutils.segmentation import (detect_sources, deblend_sources, SourceCatalog,  # 导入源检测和分离模块
                                    make_2dgaussian_kernel, SegmentationImage)  # 导入2D高斯核和分割图像相关函数
from photutils.utils import calc_total_error  # 导入计算总误差的函数

Matplotlib 绘图设置#

有两个版本

  • notebook – 提供交互式图形,但会使整个笔记本的滚动变得稍微困难

  • inline – 提供非交互式图形,以便更好地滚动整体内容

import matplotlib.pyplot as plt  # 导入绘图库 matplotlib 的 pyplot 模块

import matplotlib as mpl  # 导入 matplotlib 库

# Use this version for non-interactive plots (easier scrolling of the notebook)
%matplotlib inline  # 设置为非交互式绘图模式,方便在笔记本中滚动查看

# Use this version if you want interactive plots
# %matplotlib notebook  # 如果需要交互式绘图,可以取消注释这一行

# These gymnastics are needed to make the sizes of the figures
# be the same in both the inline and notebook versions
%config InlineBackend.print_figure_kwargs = {'bbox_inches': None}  # 配置图形输出的边界框参数,使得图形在两种模式下大小一致

mpl.rcParams['savefig.dpi'] = 80  # 设置保存图形时的分辨率为 80 dpi
mpl.rcParams['figure.dpi'] = 80  # 设置图形显示时的分辨率为 80 dpi

创建待加载和分析的图像列表#

# 基础URL,用于获取JWST数据分析工具的NIRCam光度数据
baseurl = 'https://data.science.stsci.edu/redirect/JWST/jwst-data_analysis_tools/nircam_photometry/'

# 定义所需的滤光片
filters = 'F090W F115W F150W F200W F277W F335M F356W F410M F444W'.split()

# 数据图像 [电子/秒]
imagefiles = {}  # 创建一个空字典以存储图像文件路径

# 遍历每个滤光片
for filt in filters:
    # 根据滤光片名称生成文件名
    filename = f'jades_jwst_nircam_goods_s_crop_{filt}.fits'
    # 将完整的文件路径存储到字典中
    imagefiles[filt] = os.path.join(baseurl, filename)

# 权重图像(逆方差图;IVM)
weightfiles = {}  # 创建一个空字典以存储权重文件路径

# 遍历每个滤光片
for filt in filters:
    # 根据滤光片名称生成权重文件名
    filename = f'jades_jwst_nircam_goods_s_crop_{filt}_wht.fits'
    # 将完整的权重文件路径存储到字典中
    weightfiles[filt] = os.path.join(baseurl, filename)

加载探测图像:F200W#

filt = 'F200W'  # 定义滤波器类型为'F200W'

infile = imagefiles[filt]  # 从图像文件字典中获取对应滤波器的输入文件

hdu = fits.open(infile)  # 打开输入文件,返回一个HDU列表

data = hdu[0].data  # 获取HDU列表中第一个HDU的图像数据

imwcs = wcs.WCS(hdu[0].header, hdu)  # 创建WCS对象以处理图像的世界坐标系统

weight = fits.open(weightfiles[filt])[0].data  # 打开权重文件并获取其数据

报告图像大小和视场#

ny, nx = data.shape  # 获取数据的行数和列数

pixscale = wcs.utils.proj_plane_pixel_scales(imwcs)[0]  # 计算投影平面像素尺度

pixscale *= imwcs.wcs.cunit[0].to('arcsec')  # 将像素尺度转换为角秒

outline = '%d x %d pixels' % (ny, nx)  # 创建输出字符串,包含像素的行列数

outline += ' = %g" x %g"' % (ny * pixscale, nx * pixscale)  # 添加输出字符串,包含实际尺寸

outline += ' (%.2f" / pixel)' % pixscale  # 添加输出字符串,包含每个像素的角度

print(outline)  # 打印最终的输出字符串

创建彩色图像(可选)#

# 3 NIRCam短波长通道图像

r = fits.open(imagefiles['F200W'])[0].data  # 打开F200W图像文件并获取数据

g = fits.open(imagefiles['F150W'])[0].data  # 打开F150W图像文件并获取数据

b = fits.open(imagefiles['F090W'])[0].data  # 打开F090W图像文件并获取数据

rgb = make_lupton_rgb(r, g, b, Q=5, stretch=0.02)  # 创建RGB图像,使用Lupton算法,Q和stretch参数控制图像显示效果

fig = plt.figure(figsize=(8, 8))  # 创建一个8x8英寸的图形

ax = plt.subplot(projection=imwcs)  # 创建一个子图并设置投影为imwcs

plt.imshow(rgb, origin='lower')  # 显示RGB图像,设置原点在左下角

plt.xlabel('Right Ascension')  # 设置x轴标签为“右升角”

plt.ylabel('Declination')  # 设置y轴标签为“赤纬”

fig.tight_layout()  # 调整图形布局以避免重叠

plt.subplots_adjust(left=0.15)  # 调整子图左侧的边距

使用 photutils 检测源和去混叠#

https://photutils.readthedocs.io/en/latest/segmentation.html

# For detection, requiring 5 connected pixels 2-sigma above background
# 检测要求:5个相连的像素点,信号强度需高于背景的2倍标准差

# Measure background and set detection threshold
# 测量背景并设置检测阈值

bkg_estimator = MedianBackground()  # 创建中位数背景估计器

bkg = Background2D(data, (50, 50), filter_size=(3, 3), bkg_estimator=bkg_estimator)  # 计算二维背景

threshold = bkg.background + (2. * bkg.background_rms)  # 设置阈值为背景加上2倍的背景标准差

# Before detection, smooth image with Gaussian FWHM = 3 pixels
# 在检测之前,用FWHM为3像素的高斯函数平滑图像

smooth_kernel = make_2dgaussian_kernel(3.0, size=3)  # 创建高斯平滑核

convolved_data = convolve(data, smooth_kernel)  # 对数据进行卷积处理

# Detect and deblend
# 检测并进行去混叠

segm_detect = detect_sources(convolved_data, threshold, npixels=5)  # 检测源,要求5个相连像素

segm_deblend = deblend_sources(convolved_data, segm_detect, npixels=5, nlevels=32, contrast=0.001)  # 去混叠处理

# Save segmentation map of detected objects
# 保存检测到的物体的分割图

segm_hdu = fits.PrimaryHDU(segm_deblend.data.astype(np.uint32), header=imwcs.to_header())  # 创建分割图的HDU

segm_hdu.writeto('JADES_detections_segm.fits', overwrite=True)  # 将分割图写入FITS文件,覆盖同名文件

在检测图像中测量光度(及更多)#

https://photutils.readthedocs.io/en/latest/segmentation.html#centroids-photometry-and-morphological-properties

#error = bkg.background_rms  # 背景噪声的均方根值

# Input weight should be exposure map. Fudging for now.  # 输入权重应为曝光图。暂时使用简单处理。

error = calc_total_error(data, bkg.background_rms, weight/500)  # 计算总误差,使用数据、背景均方根和权重

#cat = source_properties(data-bkg.background, segm_deblend, wcs=imwcs, background=bkg.background, error=error)  # 原代码:获取源属性

cat = SourceCatalog(data-bkg.background, segm_deblend, wcs=imwcs, background=bkg.background, error=error)  # 创建源目录,包含数据、分割图、WCS、背景和误差

显示检测结果与图像(可选)#

fig, ax = plt.subplots(2, 3, sharex=True, sharey=True, figsize=(9.5, 6))  # 创建一个2行3列的子图,设置共享x和y轴,并指定图形大小

# For RA,Dec axes instead of pixels, add: , subplot_kw={'projection': imwcs})
# 如果需要使用RA和Dec坐标轴而不是像素,可以添加: , subplot_kw={'projection': imwcs})

# Color image
ax[0, 0].imshow(rgb, origin='lower')  # 显示RGB彩色图像,原点在下方
ax[0, 0].set_title('Color Image')  # 设置子图标题为“彩色图像”

# Data
norm = simple_norm(data, 'sqrt', percent=99.)  # 使用平方根归一化数据,99%分位数
ax[0, 1].imshow(data, origin='lower', cmap='Greys_r', norm=norm)  # 显示数据图像,使用灰度反转色图
ax[0, 1].set_title('Detection Image F200W')  # 设置子图标题为“检测图像 F200W”

# Segmentation map
cmap = segm_deblend.make_cmap(seed=12345)  # 创建分割图的颜色映射,使用随机种子
ax[0, 2].imshow(segm_deblend, origin='lower', cmap=cmap, interpolation='nearest')  # 显示分割图像,使用最近邻插值
ax[0, 2].set_title('Detections (Segmentation Image)')  # 设置子图标题为“检测(分割图像)”

# Weight
ax[1, 0].imshow(weight, origin='lower', cmap='Greys_r', vmin=0)  # 显示权重图像,使用灰度反转色图,最小值为0
ax[1, 0].set_title('Weight Image F200W')  # 设置子图标题为“权重图像 F200W”

# RMS
ax[1, 1].imshow(bkg.background_rms, origin='lower', norm=None)  # 显示背景RMS图像
ax[1, 1].set_title('Background RMS')  # 设置子图标题为“背景RMS”

# Total error including Poisson noise
norm = simple_norm(error, 'sqrt', percent=99.)  # 使用平方根归一化误差数据,99%分位数
ax[1, 2].imshow(error, origin='lower', norm=norm)  # 显示误差图像
ax[1, 2].set_title('RMS + Poisson noise')  # 设置子图标题为“RMS + 泊松噪声”

fig.tight_layout()  # 调整子图布局以避免重叠

查看探测图像中的所有测量量(可选)#

# 将cat对象转换为表格格式
table = cat.to_table()  # 将cat对象转换为表格

仅保留某些量#

# 定义要提取的列名
columns = 'label xcentroid ycentroid sky_centroid area semimajor_sigma semiminor_sigma ellipticity orientation gini'.split()

# 从cat对象中提取指定列并转换为表格格式
tbl = cat.to_table(columns=columns)

# 将列名'semimajor_sigma'重命名为'a'
tbl.rename_column('semimajor_sigma', 'a')

# 将列名'semiminor_sigma'重命名为'b'
tbl.rename_column('semiminor_sigma', 'b')
看起来您提供的内容不完整似乎是一个表格的标题或标识符如果您有特定的Python代码或JWST数据处理的代码需要我添加中文注释请提供完整的代码片段我将很乐意帮助您添加注释并保持代码结构不变

将测量的通量(数据单位)转换为星等#

https://docs.astropy.org/en/stable/units/

https://docs.astropy.org/en/stable/units/equivalencies.html#photometric-zero-point-equivalency

https://docs.astropy.org/en/stable/units/logarithmic_units.html#logarithmic-units

# 未探测:mag = 99;magerr = 1-sigma 上限假设零通量

# 未观察:mag = -99;magerr = 0

def fluxes2mags(flux, fluxerr):
    nondet = flux < 0  # 如果通量为负,则为未探测
    unobs = (fluxerr <= 0) + (fluxerr == np.inf)  # 如果通量不确定性为负或无穷大,则为未观察

    mag = flux.to(u.ABmag)  # 将通量转换为AB星等

    magupperlimit = fluxerr.to(u.ABmag)  # 如果通量=0,则为1-sigma上限

    mag = np.where(nondet, 99 * u.ABmag, mag)  # 对于未探测的情况,将星等设置为99

    mag = np.where(unobs, -99 * u.ABmag, mag)  # 对于未观察的情况,将星等设置为-99

    magerr = 2.5 * np.log10(1 + fluxerr/flux)  # 计算星等的不确定性
    magerr = magerr.value * u.ABmag  # 将不确定性转换为AB星等

    magerr = np.where(nondet, magupperlimit, magerr)  # 对于未探测的情况,使用上限值
    magerr = np.where(unobs, 0*u.ABmag, magerr)  # 对于未观察的情况,将不确定性设置为0

    return mag, magerr  # 返回星等和不确定性

# 包含我在astropy中找不到的特性:

# 对于未探测/未观察的情况,mag = 99 / -99

# 通量不确定性 -> 星等不确定性

使用在检测图像中定义的等光度孔径进行多波段光度测量#

(类似于以双图像模式运行SourceExtractor)

filters = 'F090W F115W F150W F200W F277W F335M F356W F410M F444W'.split()  # 定义过滤器列表

for filt in filters:  # 遍历每个过滤器

    infile = imagefiles[filt]  # 获取对应过滤器的输入文件

    print(filt)  # 打印当前过滤器名称

    print(infile)  # 打印当前输入文件路径

    print(weightfiles[filt])  # 打印当前过滤器的权重文件路径

    hdu = fits.open(infile)  # 打开输入文件

    data = hdu[0].data  # 获取数据部分

    zp = hdu[0].header['ABMAG'] * u.ABmag  # 获取零点(AB magnitude)

    weight = fits.open(weightfiles[filt])[0].data  # 打开权重文件并获取数据

    # Measure background  # 测量背景

    bkg = Background2D(data, (50, 50), filter_size=(3, 3), bkg_estimator=bkg_estimator)  # 计算二维背景

    #error = bkg.background_rms  # 计算背景的均方根误差(注释掉)

    error = calc_total_error(data, bkg.background_rms, weight/500)  # 计算总误差

    # Measure properties in each image of previously detected objects  # 测量先前检测到的物体在每幅图像中的属性

    filtcat = SourceCatalog(data-bkg.background, segm_deblend, wcs=imwcs, background=bkg.background, error=error)  # 创建源目录

    # Convert measured fluxes to fluxes in nJy and to AB magnitudes  # 将测量的通量转换为nJy和AB星等

    filttbl = filtcat.to_table()  # 将源目录转换为表格

    tbl[filt+'_flux']    = flux    = filttbl['segment_flux']     * zp.to(u.nJy)  # 计算并存储通量

    tbl[filt+'_fluxerr'] = fluxerr = filttbl['segment_fluxerr'] * zp.to(u.nJy)  # 计算并存储通量误差

    mag, magerr = fluxes2mags(flux, fluxerr)  # 将通量和通量误差转换为星等和星等误差

    #mag = mag * u.ABmag  # incompatible with file writing  # 注释掉的行,表示与文件写入不兼容

    tbl[filt+'_mag']    = mag.value  # 存储星等

    tbl[filt+'_magerr'] = magerr.value  # 存储星等误差

查看完整结果(可选)#

看起来您提供的信息不完整您提到的tbl似乎是一个表格或数据结构的名称但没有具体的代码或上下文如果您能提供更多的代码或具体的内容我将能够更好地帮助您添加中文注释并保持代码的结构和功能请提供相关的Python代码或数据处理的示例谢谢

将光度数据保存为输出目录#

tbl.write('JADESphotometry.ecsv', overwrite=True)  # 将表格数据写入名为'JADESphotometry.ecsv'的文件中,设置overwrite=True以允许覆盖现有文件
!head -175 JADESphotometry.ecsv  # 显示前175行
 

这段代码使用了shell命令`head`来显示文件`JADESphotometry.ecsv`的前175行

重新格式化输出目录以提高可读性(可选)#

# 移除面积的单位(像素)
tbl['area'] = tbl['area'].value.astype(int)  # 将'area'列的值转换为整数类型

# 用ra和dec替换sky_centroid
tbl['ra'] = tbl['sky_centroid'].ra.degree  # 提取sky_centroid的RA值并转换为度
tbl['dec'] = tbl['sky_centroid'].dec.degree  # 提取sky_centroid的Dec值并转换为度

# 获取当前表格的列名
columns = list(tbl.columns)  # 将表格的列名转换为列表

# 重新排列列名,将ra和dec插入到适当的位置
columns = columns[:3] + ['ra', 'dec'] + columns[4:-2]  # 保留前3列,插入ra和dec,然后保留剩余列

# 根据新的列顺序重新构建表格
tbl = tbl[columns]  # 重新排列表格的列
for column in columns:  # 遍历所有列
    tbl[column].info.format = '.4f'  # 设置每列的格式为浮点数,保留四位小数

tbl['ra'].info.format = '11.7f'  # 设置'ra'列的格式为浮点数,总宽度11,保留7位小数
tbl['dec'].info.format = '11.7f'  # 设置'dec'列的格式为浮点数,总宽度11,保留7位小数

tbl['label'].info.format = 'd'  # 设置'label'列的格式为整数
tbl['area'].info.format = 'd'  # 设置'area'列的格式为整数
tbl.write('JADESphotometry.cat', format='ascii.fixed_width_two_line', delimiter=' ', overwrite=True)  # 将表格数据写入文件,格式为固定宽度两行,使用空格作为分隔符,允许覆盖已有文件
!head -10 JADESphotometry.cat  # 显示文件 JADESphotometry.cat 的前10行

开始新会话并分析结果#

加载目录和分割图#

# Catalog: ecsv格式保留单位以便在Python笔记本中加载
tbl = QTable.read('JADESphotometry.ecsv')  # 读取JADESphotometry.ecsv文件并存储为表格

# 重新构建滤光片列表
filters = []  # 初始化滤光片列表

for param in tbl.columns:  # 遍历表格中的每一列
    if param[-4:] == '_mag':  # 检查列名是否以'_mag'结尾
        filters.append(param[:-4])  # 将列名去掉'_mag'后添加到滤光片列表中

# 分割图像文件
segmfile = 'JADES_detections_segm.fits'  # 定义分割图像文件名
segm = fits.open(segmfile)[0].data  # 打开FITS文件并获取数据部分
segm = SegmentationImage(segm)  # 将数据转换为分割图像对象

绘制数量计数与亮度的关系#

fig = plt.figure(figsize=(8, 4))  # 创建一个8x4英寸的图形

filt = 'F200W'  # 设置滤光片为F200W

mag1 = tbl[filt + '_mag']  # 从表格中提取对应滤光片的星等数据

mag1 = mag1[(0 < mag1) & (mag1 < 90)]  # 仅保留有效的观测数据(星等在0到90之间)

n = plt.hist(mag1, histtype='step', label=filt)  # 绘制星等的直方图,使用线条样式并添加标签

plt.xlabel('AB magnitude')  # 设置x轴标签为AB星等

plt.ylabel('Number counts')  # 设置y轴标签为数量计数

plt.legend()  # 显示图例

绘制 F200W 与 F090W 亮度并寻找缺失值#

#import mplcursors  # 导入mplcursors库(注释掉,可能是为了后续使用)

# Would love a better solution here!  # 这里希望有更好的解决方案!

mag1 = tbl['F090W_mag']  # 获取F090W波段的星等数据

mag2 = tbl['F200W_mag']  # 获取F200W波段的星等数据

# Only plot detections in F200W  # 仅绘制F200W波段的检测数据

det2 = (0 < mag2) & (mag2 < 90)  # 筛选出F200W波段星等在0到90之间的检测

mag1 = mag1[det2]  # 根据det2筛选F090W波段的星等
mag2 = mag2[det2]  # 根据det2筛选F200W波段的星等
ids = tbl['label'][det2]  # 获取对应的标签

plt.figure(figsize=(8, 4))  # 创建一个8x4英寸的图形

plt.plot(mag1, mag2, '.')  # 绘制F090W与F200W星等的散点图

for i in range(len(mag1)):  # 遍历每个点
    plt.text(mag1[i], mag2[i], ids[i])  # 在每个点旁边添加对应的标签

plt.xlabel('F090W AB magnitude')  # 设置x轴标签
plt.ylabel('F200W AB magnitude')  # 设置y轴标签

查看一个天体#

# 可以通过位置选择对象

# x, y = 905, 276  # 定义x和y坐标

# id = segm.data[y,x]  # 根据坐标获取对象的ID

# 通过ID号选择对象
id = 261  # F090W dropout,定义要选择的对象ID

obj = tbl[id-1]  # 从表格中获取对应ID的对象
看起来您提供的信息不完整请提供您希望我添加中文注释的Python代码以便我可以帮助您
# 获取对象的椭圆率属性
ellipticity = obj['ellipticity']  # 从对象中提取椭圆率
# 从segm对象中获取指定id的段对象
segmobj = segm.segments[segm.get_index(id)]

# 输出获取的段对象
segmobj

在所有图像中显示对象#

fig, ax = plt.subplots(2, len(filters)+1, figsize=(9.5, 3.5), sharex=True, sharey=True)  # 创建一个2行(len(filters)+1)列的子图,设置图形大小和共享坐标轴

ax[0, 0].imshow(rgb[segmobj.slices], origin='lower', extent=segmobj.bbox.extent)  # 在第一个子图中显示RGB图像
ax[0, 0].set_title('Color')  # 设置第一个子图的标题为'Color'

cmap = segm.make_cmap(seed=12345)  # 创建一个颜色映射,使用固定的随机种子

ax[1, 0].imshow(segm.data[segmobj.slices], origin='lower', extent=segmobj.bbox.extent, cmap=cmap,  # 在第二个子图中显示分段数据
               interpolation='nearest')  # 使用最近邻插值
ax[1, 0].set_title('Segment')  # 设置第二个子图的标题为'Segment'

for i in range(1, len(filters)+1):  # 遍历所有过滤器

    filt = filters[i-1]  # 获取当前过滤器

    # Show data on top row
    data = fits.open(imagefiles[filt])[0].data  # 打开当前过滤器对应的图像文件并读取数据
    stamp = data[segmobj.slices]  # 根据分段对象的切片获取数据
    norm = ImageNormalize(stretch=SqrtStretch())  # 创建一个归一化对象,使用平方根拉伸
    ax[0, i].imshow(stamp, extent=segmobj.bbox.extent, cmap='Greys_r', norm=norm, origin='lower')  # 在上方子图中显示数据
    ax[0, i].set_title(filt.upper())  # 设置当前子图的标题为过滤器名称(大写)

    # Show weights on bottom row
    weight = fits.open(weightfiles[filt])[0].data  # 打开当前过滤器对应的权重文件并读取数据
    stamp = weight[segmobj.slices]  # 根据分段对象的切片获取权重数据
    # set black to zero weight (no exposure time / bad pixel)
    ax[1, i].imshow(stamp, extent=segmobj.bbox.extent, vmin=0, cmap='Greys_r', origin='lower')  # 在下方子图中显示权重数据

ax[0, 0].set_ylabel('Data')  # 设置第一行第一个子图的y轴标签为'Data'
ax[1, 0].set_ylabel('Weight')  # 设置第二行第一个子图的y轴标签为'Weight'

绘制 SED(光谱能量分布)#

fig, ax = plt.subplots(figsize=(8, 6))  # 创建一个8x6英寸的图形和坐标轴

for filt in filters:  # 遍历所有过滤器

    lam = int(filt[1:4]) / 100  # 提取波长并转换为微米

    plt.errorbar(lam, obj[filt+'_flux'].value, obj[filt+'_fluxerr'].value, marker='.', c='b')  # 绘制带误差条的光谱数据点

plt.axhline(0, c='k', ls=':')  # 绘制y=0的水平线

plt.xlim(0, 5)  # 设置x轴范围为0到5微米

plt.xlabel('Wavelength ($\mu$m)')  # 设置x轴标签为波长(微米)

plt.ylabel('Flux (nJy)')  # 设置y轴标签为通量(nJy)

mlim = 31.4  # 设置AB星等的限制值
flim = mlim * u.ABmag  # 将限制值转换为AB星等
flim = flim.to(u.nJy).value  # 将限制值转换为nJy单位

# 添加AB星等作为右侧的次坐标轴
# https://matplotlib.org/gallery/subplots_axes_and_figures/secondary_axis.html#sphx-glr-gallery-subplots-axes-and-figures-secondary-axis-py
def AB2nJy(mAB):  # 定义AB星等到nJy的转换函数
    m = mAB * u.ABmag  # 将输入的AB星等转换为ABmag单位
    f = m.to(u.nJy)  # 转换为nJy单位
    f = f.value  # 获取数值部分
    f = np.where(f > flim, f, flim)  # 如果小于flim,则使用flim
    return f  # 返回nJy值

def nJy2AB(F_nJy):  # 定义nJy到AB星等的转换函数
    f = F_nJy * u.nJy  # 将输入的nJy值转换为nJy单位
    m = f.to(u.ABmag)  # 转换为AB星等
    m = m.value  # 获取数值部分
    m = np.where(m < mlim, m, mlim)  # 如果大于mlim,则使用mlim
    return m  # 返回AB星等值

plt.ylim(flim, plt.ylim()[1])  # 设置y轴下限为flim,上限保持不变

secax = ax.secondary_yaxis('right', functions=(nJy2AB, AB2nJy))  # 创建右侧次坐标轴并设置转换函数
secax.set_ylabel('magnitude (AB)')  # 设置右侧坐标轴标签为AB星等

当通量 <= 0 时,星等转换失败#

fig, ax = plt.subplots(figsize=(8, 6))  # 创建一个8x6英寸的图形和坐标轴

for filt in filters:  # 遍历每个过滤器

    lam = int(filt[1:4]) / 100  # 提取波长并转换为微米

    plt.errorbar(lam, obj[filt+'_flux'].value, obj[filt+'_fluxerr'].value, marker='.', c='b')  # 绘制带误差条的光谱数据

plt.axhline(0, c='k', ls=':')  # 绘制y=0的水平线

plt.xlim(0, 5)  # 设置x轴范围为0到5微米

plt.xlabel('Wavelength ($\mu$m)')  # 设置x轴标签为波长(微米)

plt.ylabel('Flux (nJy)')  # 设置y轴标签为通量(nJy)

f0 = 10**(0.4 * 31.4)  # 零星等时的通量(nJy)

b0 = 1.e-12  # 这个值应该依赖于过滤器

# 添加AB星等作为右侧的次坐标轴
# https://matplotlib.org/gallery/subplots_axes_and_figures/secondary_axis.html#sphx-glr-gallery-subplots-axes-and-figures-secondary-axis-py
def AB2nJy(m):  # 定义从AB星等到nJy的转换函数
    f = np.sinh(-0.4 * m * np.log(10) - np.log(b0)) * 2 * b0 * f0  # 计算nJy
    return f  # 返回计算结果

# Luptitudes
# https://www.sdss.org/dr12/algorithms/magnitudes/
def nJy2AB(f):  # 定义从nJy到AB星等的转换函数
    m = -2.5 / np.log(10) * (np.arcsinh((f / f0) / (2 * b0)) + np.log(b0))  # 计算AB星等
    return m  # 返回计算结果

#plt.ylim(flim, plt.ylim()[1])  # 可选:设置y轴范围

secax = ax.secondary_yaxis('right', functions=(nJy2AB, AB2nJy))  # 创建右侧的次坐标轴并设置转换函数
secax.set_ylabel('asinh magnitude (AB)')  # 设置次坐标轴的标签为asinh星等(AB)