Skip to content

FITS 裁切图上的暂现源真假甄别与星系形态分类

在科学图像、参考图像和差分图像的 FITS 裁切图上甄别暂现源候选体的真假,附赤经/赤纬(RA/Dec)读数和光变曲线,或用问题树为星系形态分类。

v2.13.0 新增

fits_cutout 显示类型在浏览器中显示 FITS 图像:可以每个条目显示一幅图像,也可以把一个暂现源候选体的科学图像、参考图像和差分图像裁切图(cutout)并排显示,下方附该候选体的光变曲线。时域天文学研究者用这个显示类型做真假甄别(real-bogus vetting)。在真假甄别中,标注者把来自 ZTF 或 Rubin 等巡天的每个候选体判为真实的天体物理暂现源或虚假检测。这些标签成为真假甄别分类器的训练集。例如,ZTF 的 Braai 分类器就是用 30,000 多组已标注的科学、参考和差分图像三联图训练的(Duev et al., MNRAS 489, 3582)。星系形态分类每个条目使用一幅图像,并配一棵 Galaxy Zoo 式的问题树。显示类型本身不存储任何内容,甄别问题是一个普通方案,通常是一道 radio,用 R、B、U 三个键选择 Real、Bogus 和 Unsure。

FITS(Flexible Image Transport System,灵活图像传输系统)是天文图像和表格的标准文件格式。FITS 头部中的世界坐标系(World Coordinate System,WCS)关键字把图像的每个像素映射到天球上的一个位置。差分图像是经过定标的科学曝光减去同一天区的参考图像(模板)得到的图像,真实的暂现源在差分图像中表现为一个新出现的点源。ZTF 警报包以 gzip 压缩的 FITS 图像保存科学、参考和差分裁切图(警报模式),Rubin 的工作人员表示 Rubin 警报也将包含全部三幅裁切图(Rubin 论坛)。

  • 读取: astropy(BSD-3-Clause)在 Potato 服务器上读取 FITS 文件,截取条目位置周围的区域,对裁切图做亮度缩放,再发送一幅 PNG 以及这幅裁切图的 WCS 描述。服务器在读取第一个 FITS 文件时才导入 astropy,启动时不加载 astropy。
  • 格式: .fits、.fit、.fts 以及 gzip 压缩的 .fits.gz。显示类型显示由 hdu 指定的 HDU,否则显示第一个包含二维(或更高维)图像的 HDU;数据立方体显示其第一个平面。以 .fits.gz 名称写入磁盘的 ZTF 裁切图无需解压即可打开。
  • 裁切图: 中心是 FITS 像素坐标(x、y)或天球坐标(ra、dec),尺寸是像素数或 "40 arcsec" 这样的角度。对于未压缩的文件,只读取裁切图覆盖的那些行。
  • 缓存: 每幅转换后的裁切图以一个 PNG 和一个 JSON 文件写入 <task_dir>/.potato_cache/fits/。缓存键涵盖文件的路径、大小、修改时间和缩放选项,未改动的文件只转换一次。缓存保留最近使用的 4,000 项,删除这个文件夹是安全的。
  • 离线: FITS 文件和光变曲线从媒体目录读取。URL 和媒体目录之外的路径一律拒绝,光变曲线图使用 Potato 自带的 Plotly。

这个显示类型需要 astro 可选依赖(astropy>=5.3):

bash
pip install 'potato-annotation[astro]'

配置中有 fits_cutout 字段而没有安装 astropy 时,启动会失败,提示信息中给出安装命令。

配置

下面的配置在裁切图三联图上进行真假甄别。每个候选体都必须给出真假标签;只有在标注者选了 Bogus 之后,才会出现第二个问题,询问虚假检测的原因:

yaml
annotation_task_name: "Transient candidate vetting"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/candidates.json]
item_properties: {id_key: id, text_key: summary}
 
instance_display:
  fields:
    - key: candidate            # item field holding the triplet
      type: fits_cutout
      label: "Cutouts"
      display_options:
        size: 48                # pixels, used when an item gives no size
        interval: zscale
        stretch: linear
        panels:
          - {key: science, label: Science}
          - {key: reference, label: Reference}
          - {key: difference, label: Difference, stretch: asinh}
 
user_config:
  allow_all_users: true
 
annotation_schemes:
  - annotation_type: radio
    name: vetting
    description: "Is this a real astrophysical transient?"
    humanize_labels: false
    labels:
      - {name: "Real", key_value: "r"}
      - {name: "Bogus", key_value: "b"}
      - {name: "Unsure", key_value: "u"}
    label_requirement: {required: true}
 
  - annotation_type: multiselect
    name: bogus_reason
    description: "What makes the candidate bogus?"
    humanize_labels: false
    labels:
      - "Subtraction residual (dipole)"
      - "Cosmic ray or hot pixel"
      - "Satellite or asteroid trail"
      - "Bad column or image edge"
      - "Other"
    display_logic:
      show_when:
        - {schema: vetting, operator: equals, value: "Bogus"}

panels 列表选择显示哪些裁切图及其顺序,每个面板可以设置自己的缩放。这里的差分面板使用 asinh 拉伸,科学面板和参考面板沿用显示类型的 zscale 区间和线性拉伸。humanize_labels: false 让每个标签按原样显示,屏幕上的“Bogus”因此与 display_logic 条件中的值一致。被隐藏的问题在页面和服务器上都不参与必答检查。

每个条目给出三个相对于 media_directory 的 FITS 路径、候选体的位置以及可选的光变曲线:

json
{
  "id": "cand-001",
  "summary": "cand-001: ra 150.11920, dec +2.20583, band r",
  "candidate": {
    "science": "cutouts/cand-001_sci.fits",
    "reference": "cutouts/cand-001_ref.fits",
    "difference": "cutouts/cand-001_diff.fits",
    "ra": 150.11920, "dec": 2.20583,
    "size": 48,
    "light_curve": "lightcurves/cand-001.csv"
  }
}

对于星系形态分类,存放单个路径的条目字段显示一幅图像:

json
{"id": "gal-17", "image": "galaxies/gal-17.fits"}

ZTF 光变曲线

Potato 按常见的列名查找光变曲线的各列,而 ZTF 的测光列 magpsf 和 sigmapsf 不在这些名称之中。不做映射时,一条含有 jd, fid, magpsf, sigmapsf, diffmaglim 列的 ZTF 光变曲线会把每个带 diffmaglim 的行画成上限。下面这段部分配置为上文配置中的 fits_cutout 字段添加两个选项,并逐一指定各列:

yaml
instance_display:
  fields:
    - key: candidate
      type: fits_cutout
      display_options:
        light_curve_columns: {time: jd, band: fid, mag: magpsf, err: sigmapsf, limit: diffmaglim}
        time_label: JD

图上的“this image”标记取自科学图像的 MJD-OBS,只有当 MJD-OBS 落在第一个点之前 1,000 个时间单位到最后一个点之后 1,000 个时间单位的范围内时,Potato 才画出这个标记。在 JD 坐标轴上,MJD-OBS 比每个时间都小约 2,400,000,因此不会画出标记;在每个条目上以 JD 给出 epoch 即可放置标记。ZTF 的滤光片编号 1、2、3 会成为波段名“1”“2”“3”;如果在波段列中改写为 g、r 和 i,每个波段就会使用其惯用的颜色。

用问题树做星系形态分类

Galaxy Zoo 式的决策树按固定顺序提问,每个答案决定下一个问题。Galaxy Zoo DECaLS 的决策树以“Smooth or Featured?”开头(Walmsley et al., MNRAS 509, 3966)。在 Potato 中,树上的每个问题是一个 radio 方案,每个后续问题上的 display_logic 只在出现引向该问题的答案之后才显示这个问题。

display_logic 的两条规则决定了树的写法。第一,被隐藏的问题会保留标注者在它被隐藏之前给出的答案。第二,问题是否可见只根据答案计算,与父问题是否显示在屏幕上无关。因此每个条件都要用 all 列出从第一个问题开始的整条路径。只写父问题的条件,会在标注者更改前面的某个答案之后,让后面的问题仍留在屏幕上。

下面的配置在单幅星系图像上提出一棵含四个问题的树:

yaml
annotation_task_name: "Galaxy morphology"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/galaxies.json]
item_properties: {id_key: id, text_key: id}
 
instance_display:
  fields:
    - key: image
      type: fits_cutout
      label: "Galaxy"
      display_options:
        interval: percentile
        percentile: 99.5
        stretch: asinh
 
user_config:
  allow_all_users: true
 
annotation_schemes:
  - annotation_type: radio
    name: shape
    description: "Is the galaxy simply smooth and rounded, with no sign of a disk?"
    humanize_labels: false
    labels: ["Smooth", "Features or a disk", "Star or artifact"]
    label_requirement: {required: true}
 
  - annotation_type: radio
    name: edge_on
    description: "Could this be a disk viewed edge-on?"
    labels: ["Yes", "No"]
    label_requirement: {required: true}
    display_logic:
      show_when:
        - {schema: shape, operator: equals, value: "Features or a disk"}
 
  - annotation_type: radio
    name: bulge_edge_on
    description: "Does the edge-on disk have a bulge at its center? If so, what shape?"
    humanize_labels: false
    labels: ["Rounded", "Boxy", "No bulge"]
    label_requirement: {required: true}
    display_logic:
      show_when:
        - all:
            - {schema: shape, operator: equals, value: "Features or a disk"}
            - {schema: edge_on, operator: equals, value: "Yes"}
 
  - annotation_type: radio
    name: spiral
    description: "Is there any sign of a spiral arm pattern?"
    labels: ["Yes", "No"]
    label_requirement: {required: true}
    display_logic:
      show_when:
        - all:
            - {schema: shape, operator: equals, value: "Features or a disk"}
            - {schema: edge_on, operator: equals, value: "No"}

条目中没有位置时,显示类型显示整幅图像。百分位区间加 asinh 拉伸可以在同一视图中同时显示星系暗弱的外盘和明亮的核心。zscale 区间是为暗弱源调校的,可能使明亮的核心饱和。YAML 中要给 "Yes" 和 "No" 加引号,因为不加引号的 Yes 和 No 会被读作布尔值。上游示例在甄别问题之后放了一棵同类的树,这棵树询问每个真实候选体的宿主星系。

条目数据

条目的字段是一个 FITS 路径,或带有下列键的映射:

键含义
science、reference、difference、image,或任何 panels 项指定的键媒体目录中的 FITS 路径,或对某一幅图像使用不同缩放的映射 {path: ..., stretch: ..., interval: ...}
ra、dec裁切图中心,单位为度,也可以写成六十进制文本(赤经(RA)以时为单位,如 "10:00:28.6";赤纬(Dec)如 "+02:12:21")。按 ICRS 读取;图像自身的坐标系(FK5、银道坐标)不同时,转换到图像的坐标系
x、y裁切图中心的 FITS 像素坐标。第一个像素的中心为 (1, 1),与 ds9 和 CRPIX 相同。条目给出 x 和 y,或给出 ra 和 dec,二者不能同时给出
size裁切图尺寸,以像素或角度("30 arcsec"、"0.5 arcmin"、"0.01 deg")表示
stretch、interval、percentile、asinh_a、log_a、invert、hdu作用于该条目每幅图像的缩放
light_curve媒体目录中的 CSV、TSV 或 JSON 文件,或者 [{"mjd": 60600.0, "band": "g", "mag": 20.21, "magerr": 0.07}] 这样的点列表
epoch要在光变曲线上标出的时间,代替科学图像的 MJD-OBS

缩放选项分四个层级生效,从低到高依次为:(1) 显示选项,(2) panels 项,(3) 条目,(4) 条目中针对某一幅图像的映射。后面的层级覆盖前面的层级。有位置但各处都没有给出尺寸的条目得到 64 像素的裁切图,裁切图每边最多 4,096 像素。没有位置的条目显示整幅图像,上限为 max_image_pixels;宽或高超过 1,024 像素的图像按块平均缩小到 1,024。只有尺寸而没有位置会报错。没有 panels 列表时,显示类型显示条目中具有的 science、reference 和 difference,否则显示 image。

光变曲线文件

光变曲线文件每个点一行:

csv
mjd,band,mag,magerr,limit
60570.0,r,,,21.3
60600.0,g,20.21,0.07,
60603.0,g,19.37,0.05,

有星等的行是一次检测,没有星等但有 limit 的行是一个上限。没有可用时间的行会被跳过并计数。没有 light_curve_columns 时,列名按下列名单依次匹配,不区分大小写:

角色尝试的名称
timemjd、time、jd、hjd、bjd、t
magmag、magnitude、flux、value、y
errmagerr、mag_err、err、error、sigma、fluxerr、flux_err、dy
bandband、filter、fid、passband
limitlimit、upper_limit、diffmaglim、maglim、lim

JSON 光变曲线是点对象的列表,或一个把列表放在 points 或 data 下的对象。TSV 文件依据 .tsv 扩展名或文件中的制表符识别,以 # 开头的行会被跳过。超过 2 MB 的文件会被拒绝,第 20,000 行之后的行会被丢弃。波段按 u、g、r、i、z、y、J、H、K、W1、W2、c、o 的顺序排列,其他波段名排在这些波段之后。

显示选项

选项写在 display_options 下,或直接写在字段上,服务器在启动时检查每个值:

选项默认值含义
panels条目的 science、reference 和 difference,否则为 image最多 6 个面板,写成 {key, label},按顺序排列。面板也可以设置下面任何一个缩放选项。没有 label 的面板以其键为标题
size无条目未给出尺寸时的裁切图尺寸,以像素或角度表示。有位置但各处都没有给出尺寸时为 64 像素
intervalzscaleminmax、zscale(IRAF 的 zscale,与 ds9 相同)或 percentile
percentile99.5使用 interval: percentile 时落在上下限之内的像素所占百分比,大于 0 且不超过 100
stretchlinearlinear、sqrt、log 或 asinh
asinh_a0.1asinh 拉伸的 a 参数。值越小,亮像素被压缩得越多
log_a1000对数拉伸的 a 参数
invertfalse在浅色背景上显示深色的源
hdu第一个图像 HDUHDU 编号(0 为主 HDU)或 EXTNAME
max_file_mb100可读取的最大 FITS 文件(无论是否压缩),单位为 MB
max_image_pixels25000000条目未给出位置时可整幅显示的最大图像
light_curvetrue条目有光变曲线时画出光变曲线
light_curve_columns自动检测按角色指定列名,写成 {time, mag, err, band, limit}
light_curve_unitsmagmag(越亮越靠上)或 flux
light_curve_height260图的像素高度
time_labelMJD时间轴标题
crosshairtrue显示共享的十字准线
compasstrue根据 WCS 显示北向和东向箭头
panel_size18rem(单个面板时为 30rem)面板的最大宽度,写成 CSS 长度。纯数字表示像素

engine 选项只接受 potato 一个值。由于 FITS 文件总是在服务器上读取,这个显示类型拒绝 allow_remote。

查看器控件

各面板共享缩放、平移和同一个十字准线,缩放级别从 1× 到 16×:

操作效果
把指针移到裁切图上在每个面板上移动十字准线,读数显示赤经和赤纬(六十进制和度)、原始图像的 FITS 像素以及所在面板
点击或轻触固定十字准线。再次点击或按 Escape 解除固定
+、− 和 Reset 按钮同时缩放所有面板,或恢复到 1× 并清除十字准线
按住 Ctrl 或 Cmd 滚动滚轮,或在触控板上双指捏合以指针为中心缩放
放大后拖动同时平移所有面板
用 Tab 切换到某幅裁切图,再按方向键把十字准线移动一个像素。+ 和 − 缩放,0 复位

裁切图获得焦点时,标注按键(甄别配置中的 R、B 和 U)照常可用。方向键只在裁切图获得焦点时移动十字准线,在其他地方,方向键照常在条目之间切换。空白像素(NaN 或 BLANK)以及裁切图中超出图像边缘的部分是透明的,显示为棋盘格,面板下方的状态行会说明属于哪种情况。

面板尺寸相同、像素比例尺相差在 1% 以内、天球上的中心相差不到半个像素时,各面板视为已对齐。对于未对齐的面板,会有一条说明指出这一点,十字准线按天球位置放到每个面板上,所用的是各面板的线性 TAN WCS。光变曲线图把科学图像的历元标为“this image”,把上限画成空心的向下三角形,并在图下方的表格中列出每个点。

发送给浏览器的 WCS

浏览器从不读取 FITS。对每幅裁切图,服务器发送 PNG 的 URL 和一份 WCS 描述,其中包括裁切图的 CRPIX、CRVAL 和 CD 矩阵、像素比例尺、北向和东向,以及在整幅裁切图上每隔 16 个输出像素采样一次的天球位置网格。读数对网格做插值,因此能跟随 astropy 能读取的任何投影,包括 SIP 畸变。网格把每个天球位置存为单位向量,对单位向量插值能让读数在赤经 0/360 处和天极附近保持连续。线性关键字不含 SIP 项,未对齐面板的十字准线放置使用的就是这些线性关键字。银道坐标图像把坐标轴标为 l 和 b,黄道坐标图像标为 λ 和 β。

存储的答案与导出

显示类型不存储任何内容。页面上的每个方案像任何 radio 或 multiselect 问题一样存储标注者的答案,这些答案通过通用格式导出:

bash
python -m potato.export -c config.yaml -f csv -o exports/csv

CSV 中每位标注者、每个条目一行,每个方案和标签一列,例如 vetting.Real 和 bogus_reason.Cosmic ray or hot pixel。-f jsonl 以 JSON lines 写出同样的记录。树中某个问题后来被隐藏时,它的答案仍保留在存储的标注中。分析前,请根据前面答案的路径筛选后续问题的答案。

Potato 的一致性指标覆盖这些方案。vetting 这样的 radio 问题可以得到百分比一致率、Cohen's kappa、Fleiss' kappa 和 Krippendorff's alpha;bogus_reason 这样的 multiselect 问题可以得到平均 Jaccard 系数和使用 MASI 距离的 Krippendorff's alpha。2.13 新增的 consensus 导出同样覆盖 radio 和 multiselect,这个导出列出每个候选体的得票比例,以及根据 consensus_aggregation 块中的阈值给出的 retired 或 needs_review 状态。一致性指标和共识导出都不检查 display_logic,隐藏问题上保留的答案在两者中都会被计入。请把 num_annotators_per_item 设为甄别每个候选体的标注者人数。

示例

bash
python potato/flask_server.py start examples/image/astronomy-real-bogus/config.yaml -p 8000

这个示例有四个合成的候选体:盘星系中的一颗超新星、一个减除偶极子、一个宇宙线和一个无宿主的点源。每个候选体有三幅 96 × 96 的 FITS 图像,共用一个每像素 1″ 的 TAN WCS,另有一条光变曲线。第四个候选体的图像经过 gzip 压缩,同一文件夹中的 generate_data.py 会重新写出这些文件。

用编程智能体搭建研究

potato-skill 1.2.0 面向 Potato 2.13.1,认得 fits_cutout 这个显示类型名称,并指导研究设计这一侧,例如向标注者问什么、每个候选体由几名标注者甄别、培训和注意力检查,以及导出。这个技能目前还没有记录 FITS 条目格式、显示选项和 astro 可选依赖。安装 potato-skill,把研究描述给你的智能体,再让智能体参考本页的 Markdown 副本 https://www.potatoannotator.com/docs/annotation-types/astronomy.md,以了解格式和选项。

延伸阅读

有关实现细节,请参阅源文档。