FITS#

读写表格 FITS 格式支持 format='fits' . 在大多数情况下,现有的FITS文件应该根据文件头自动标识出来,但是如果没有,或者如果写入磁盘,则应该显式指定格式。

阅读#

如果FITS表文件仅包含一个表,则可以如下所示读取它。在这个示例中,我们使用安装了astropy的文件::

>>> from astropy.table import Table
>>> from astropy.utils.data import get_pkg_data_filename
>>> chandra_events = get_pkg_data_filename('data/chandra_time.fits',
...                                        package='astropy.io.fits.tests')
>>> t = Table.read(chandra_events)

使用统一接口读取表的好处是它将重建任何 混合柱 这些都写到了该HDU。

如果文件中存在多个表,您可以按索引或按名称选择HDU::

>>> t = Table.read(chandra_events, hdu="EVENTS")

在这种情况下,如果 hdu 参数,则将读入找到的第一个表,并发出警告。

您还可以从内存中FITS文件的HDU中读取表。:

>>> from astropy.io import fits
>>> with fits.open(chandra_events) as hdul:
...     t = Table.read(hdul["EVENTS"])

如果列包含单位信息,则它将具有关联的 astropy.units 对象::

>>> t["energy"].unit
Unit("eV")

还可以直接获取具有如下列的表 Quantity 对象,通过使用 QTable 班级:

>>> from astropy.table import QTable
>>> t2 = QTable.read(chandra_events, hdu=1)
>>> t2['energy']
<Quantity [7782.7305, 5926.725 ] eV>

写作#

写表格 t 到新文件:

>>> t.write('new_table.fits')

如果文件已经存在并且您想覆盖它,则设置 overwrite 关键词:

>>> t.write('existing_table.fits', overwrite=True)

如果要将表追加到现有文件,请将 append 关键词::

>>> t.write('existing_table.fits', append=True)

或者,您也可以使用便利性函数 table_to_hdu() 要创建单个二进制表HDU并将其插入或附加到现有的 HDUList

支持编写包含以下内容的表 混合柱 比如 TimeSkyCoord 。这使用了配合 COMMENT 用于捕获从FITS回读时完全重建混合列所需的附加信息的卡片。信息是一条 Python dict 结构,该结构使用YAML序列化。

关键词#

与HDU表相关联的FITS关键字在 meta 的有序字典属性 Table . 阅读表格后,您可以使用以下命令以可读格式查看可用关键字:

>>> for key, value in t.meta.items():
...     print(f'{key} = {value}')
EXTNAME = EVENTS
HDUNAME = EVENTS
TLMIN2 = 0
...

这不包括指定FITS表属性所需的“内部”FITS关键字(例如, NAXIS , TTYPE1 ). HISTORYCOMMENT 关键词会被特殊处理,并作为列表返回

>>> t.meta['MY_KEYWD'] = 'my value'
>>> t.meta['COMMENT'] = ['First comment', 'Second comment', 'etc']
>>> t.write('my_table.fits', overwrite=True)

关键字名称(例如。, MY_KEYWD )将在写入前自动大写。

TDISPn关键字#

TDISPn FITS关键字将映射到 Column format 属性,如果显示格式可以转换为Python显示格式和从Python显示格式转换。下面是两个转换方向使用的规则。

TDISPn到Python格式字符串#

TDISPn格式字符定义见下表。

格式

描述

性格

Lw公司

合乎逻辑的

Iw.m

整数

Bw.m

二进制,仅整数

Ow.m

八进制,仅整数

Zw.m

十六进制,仅整数

Fw.d

浮点,固定十进制记数法

Ew.dEe

浮点,指数表示法

ENw.d

工程;指数倍数为3的E格式

ESw.d

科学;与EN相同,但如果不为零,则前导数字不为零

Gw.dEe

一般的;如果意义没有丢失,也就是E

Dw.dEe

浮点,指数表示法,双精度

其中w是显示值的字符宽度,m是显示的最小位数,d是小数点右边的位数,e是指数中的位数。.m和Ee字段是可选的。

A(字符)、L(逻辑)、F(浮点)和G(通用)显示格式可以直接转换为Python格式的字符串。其他格式需要修改以匹配Python显示格式。

对于整数格式(I、B、O和Z),width(w)值用于在列值的左侧添加空格填充。不使用最小数字(m)值。对于E、G、D、EN和ES格式(浮点指数),宽度(w)和精度(D)都使用,但指数(E)没有使用。

Python格式字符串到TDISPn#

从Python格式字符串到TDISPn的转换稍微复杂一些。

如果Python格式化字符串不包含正确的空格填充,则Python字符串映射到TDISP格式A。它将接受左空格填充。逻辑格式L也是如此。

整数格式(十进制整数、二进制、八进制、十六进制)分别映射到I、B、O和Z TDISP格式。整数格式不接受用零填充的格式字符串或没有定义左填充的格式字符串(整数格式的TDISP格式标准要求宽度)。

对于所有浮点值和指数值,不接受零填充。必须至少定义宽度或精度。如果只定义了宽度,则TDISPn格式没有精度设置。如果只定义了一个精度,则宽度设置为精度加上一个额外的填充值(取决于格式类型),两者都以TDISPn格式设置。否则,如果同时存在宽度和精度,则均以TDISPn格式设置。 Python fF 映射到TDISP F格式。 Python gG 映射到TDISP G格式。 Python eE 映射到TDISP E格式。

遮罩柱#

包含 MaskedColumn 列可以按大小写。默认情况下,根据FITS标准,这将用特定的哨兵值替换屏蔽的数据元素:

  • NaN 对于浮动列。

  • 价值 TNULLn 对于整数列,由列定义 fill_value 属性。

  • 字符串列的空字符串(当前未实现)。

回读文件时,这些元素在返回表中被标记为屏蔽,但请参见 issue #4708 在所有三个案例中都存在问题。可以使用以下命令停用掩码 mask_invalid=False

FITS标准有一些限制:

  • 并非所有数据类型都受支持(例如,逻辑/布尔)。

  • 整数列需要选择一个值作为空指示符。如果所有可能的值都用有效数据表示(例如,在有效数据中包含256个可能值的无符号int列),则无法表示缺失的数据。

  • 屏蔽的数据值将永久丢失,从而排除了以后取消屏蔽这些值的可能性。

astropy 提供了一个解决此限制的方法,用户可以选择使用。关键是使用 serialize_method='data_mask' 写入表时的关键字参数。这告诉FITS编写器将每个屏蔽列拆分为两个单独的列,一个用于数据,另一个用于掩码。当它被读回时,这个过程是反向的,两列合并回一个屏蔽列。

>>> from astropy.table.table_helpers import simple_table
>>> t = simple_table(masked=True)
>>> t['d'] = [False, False, True]
>>> t['d'].mask = [True, False, False]
>>> t
<Table masked=True length=3>
  a      b     c     d
int64 float64 str1  bool
----- ------- ---- -----
   --     1.0    c    --
    2     2.0   -- False
    3      --    e  True
>>> t.write('data.fits', serialize_method='data_mask', overwrite=True)
>>> Table.read('data.fits')
<Table length=3>
  a      b      c      d
int64 float64 bytes1  bool
----- ------- ------ -----
   --     1.0      c    --
    2     2.0     -- False
    3      --      e  True

警告

此选项超出了现有的FITS表示缺失数据的标准,因此用户应谨慎选择此选项,尤其是当其他(非“astropy”)用户将要读取文件时。在幕后, astropy 正在将掩码列转换为两个不同的数据列和掩码列,然后将元数据写入 COMMENT 允许重建原始数据的卡。

astropy 本机对象(Mixin列)#

不仅可以存储标准 Column 对象到FITS表HDU,也可以是任何 astropy 本机对象 (混合柱 )在一个 TableQTable . 这包括 TimeQuantitySkyCoord 以及其他许多人。

通常,mixin列可能包含多个数据组件以及标准列属性之外的对象属性,例如 formatdescription . 遵守FITS标准设置的规则需要将这些数据组件和对象属性映射到适当的FITS表列和关键字。因此,已经开发了一个定义良好的协议,允许在FITS中存储这些mixin列,同时允许对象在不丢失数据或属性的情况下“往返”文件。

数量#

A Quantity mixin列 QTable 在FITS表中使用 TUNITn FITS列关键字用于合并Quantity的单位属性。例如::

>>> from astropy.table import QTable
>>> import astropy.units as u
>>> t = QTable([[1, 2] * u.angstrom])
>>> t.write('my_table.fits', overwrite=True)
>>> qt = QTable.read('my_table.fits')
>>> qt
<QTable length=2>
  col0
Angstrom
float64
--------
     1.0
     2.0

时间#

astropy 阅读和写作具有以下特点 Time

  • 写作和阅读 Time 表格列与表格之间的匹配。

  • 读取FITS表(符合时间标准)中的时间坐标列作为 Time 表列。

写作和阅读 astropy 时间列#

默认情况下,A Time 混合柱 TableQTable 将以完全精确的方式编写。这将通过设置必要的FITS标题关键字来使用FITS时间标准来完成。

将FITS表读入 Table 历史上一直将所有FITS列转换为 Column 对象,它们具有密切匹配的属性。然而,对于某些专栏,更接近原生 astropy 表示是可能的,并且您可以通过传递来指示应该使用这些 astropy_native=True (for向后兼容性,默认情况下不会这样做)。这将将符合FITS时间标准的列转换为 Time 实例,避免任何精度损失,并保留有关时间系统的信息(如果在fits头中设置)。

例子#

读入FITS表 Table

>>> from astropy.time import Time
>>> from astropy.table import Table
>>> from astropy.coordinates import EarthLocation
>>> t = Table()
>>> t['a'] = Time([100.0, 200.0], scale='tt', format='mjd',
...               location=EarthLocation(-2446354, 4237210, 4077985, unit='m'))
>>> t.write('my_table.fits', overwrite=True)
>>> tm = Table.read('my_table.fits', astropy_native=True)
>>> tm['a']
<Time object: scale='tt' format='jd' value=[2400100.5 2400200.5]>
>>> tm['a'].location
<EarthLocation (-2446354., 4237210., 4077985.) m>
>>> all(tm['a'] == t['a'])
True

同样适用于 QTable .

除了二进制表列外,各种全局时间信息拟合关键字都是用 astropy_native=True . 尤其是关键字 DATEDATE-* (ISO 8601日期时间字符串),以及 MJD-* (MJD日期值)将返回为 Time 表中的对象 meta . 有关FITS时间文件和实现的更多详细信息,请参阅 适合具有时间列的表格 .

由于并非所有的FITS阅读器都能使用FITS时间标准,因此也可以存储 Time instances using the _ time_format `. For this case, none of the special header keywords associated with the FITS time standard will be set. When reading this back into ``astropy`, the column will be an ordinary Column instead of a Time object. See the Details 下面是一个例子。

读取适合二进制表中符合标准的时间坐标列#

支持读取符合FITS时间标准的FITS文件 astropy 遵循标准规定的各种规则和惯例。设计该标准的目的是以明确和全面的方式描述时间坐标,并为其多个用例提供灵活性。因此,在读取符合FITS的文件中的时间坐标列时,需要考虑标准的多个方面。

时间坐标列严格符合标准的双矢量JD子集(在 Details 以下部分)可以读为本机 Time 物体。本标准的其他子集也由 astropy 对FITS标准时间相关关键字进行了全面检查,并对时间数据进行了相应的解释。

本标准描述了时间规范中的各个组成部分:

  • 时间坐标

  • 时间单位

  • 更正、错误等。

  • 持续时间

用于指定时间的关键字定义这些组件。使用这些关键字,时间坐标列被标识为 Time 物体。参考 适合具有时间列的表格 对于这些关键字的规范及其描述。

标准有两个方面需要特别注意,因为在处理它们时涉及到微妙的问题。这些是:

  • 名为TIME和TIME unit的列

现有FITS文件中的一个常见约定是FITS二进制表列 TTYPEn = ‘TIME’ 表示时间坐标列。许多天文数据文件,包括来自主要天文台的官方数据产品,都遵循这一先于FITS标准的惯例。FITS时间标准声明这样的列将由全局时间参考帧关键字控制,并且这仍然符合当前标准。

使用已纳入本标准的本公约, astropy 可以从所有这样的FITS表中读取时间坐标列 Time 物体。遵循此约定的FITS文件的常见示例是Chandra、XMM和HST文件。

实例#

以下是Chandra事件列表的标题提取示例:

COMMENT      ---------- Globally valid key words ----------------
DATE    = '2016-01-27T12:34:24' / Date and time of file creation
TIMESYS = 'TT      '           / Time system
MJDREF  =  5.0814000000000E+04 / [d] MJD zero point for times
TIMEUNIT= 's       '           / Time unit
TIMEREF = 'LOCAL   '           / Time reference (barycenter/local)

COMMENT      ---------- Time Column -----------------------
TTYPE1  = 'time    '           / S/C TT corresponding to mid-exposure
TFORM1  = '1D      '           / format of field
TUNIT1  = 's       '

当阅读这样一个适合的表格 astropy_native=Trueastropy 检查列的名称是否为“TIME”/“TIME” (TTYPEn = ‘TIME’ )它的单位是否适合公认的时间单位 (TUNITn 是时间单位)。

例如,读取具有上述标题和时间坐标列的Chandra事件列表 time 作为 [1, 2] 将给予:

>>> from astropy.table import Table
>>> from astropy.time import Time, TimeDelta
>>> from astropy.utils.data import get_pkg_data_filename
>>> chandra_events = get_pkg_data_filename('data/chandra_time.fits',
...                                        package='astropy.io.fits.tests')
>>> native = Table.read(chandra_events, astropy_native=True)
>>> native['time']
<Time object: scale='tt' format='mjd' value=[57413.76033393 57413.76033393]>
>>> non_native = Table.read(chandra_events)
>>> # MJDREF  =  5.0814000000000E+04, TIMESYS = 'TT'
>>> ref_time = Time(non_native.meta['MJDREF'], format='mjd',
...                 scale=non_native.meta['TIMESYS'].lower())
>>> # TTYPE1  = 'time', TUNIT1 = 's'
>>> delta_time = TimeDelta(non_native['time'])
>>> all(ref_time + delta_time == native['time'])
True

默认情况下,FITS表列将作为标准列读取 Column 对象而不考虑FITS时间标准。

  • ISO 8601日期时间格式的字符串时间列

FITS使用iso8601的一个子集(它本身并不意味着一个特定的时间刻度)来表示几个与时间相关的关键字,例如DATE xxx。遵循FITS标准,其值必须以字符串形式写入以下内容 datetime 格式:

[+/-C]CCYY-MM-DD[Thh:mm:ss[.s...]]

时间坐标列可以用这个时间表示来构造。以下是ISO 8601的示例 datetime 设置时间列格式:

TIME
----
1999-01-01T00:00:00
1999-01-01T00:00:40
1999-01-01T00:01:06
.
.
.
1999-01-20T01:10:00

识别ISO 8601格式时间坐标列的标准如下:

使用时间坐标帧关键字标识时间列,如中所述 适合具有时间列的表格 . 一旦它被识别出来,它的数据类型就会被检查以确定它的表示格式。自ISO 8601 datetime 格式是时间的唯一字符串表示形式,具有字符串数据类型的时间坐标列将自动读取为 Time 对象与 format='fits' (“配合”表示符合ISO 8601格式)。

由于此格式不表示特定的时间刻度,因此它是使用标头中的时间刻度关键字确定的 (TCTYPTIMESYS )或者他们的违约。其他时间坐标信息也以同样的方式确定,使用时间坐标帧关键字。所有ISO 8601时间都是相对于全球公认的零点(0年对应于公元前1年),因此与参考时间关键字(MJDREF、JDREF或DATEREF)无关。因此,在处理ISO8601时间列时,这些关键字将被忽略。

备注

读取使文件符合时间坐标列 may 失败。 astropy 支持这些文件的大部分,但仍有一些FITS文件不符合标准的任何方面。如果您有这样的档案,请不要犹豫让我们知道(通过打开一个问题在 issue tracker

还有,读一篇专栏文章 TTYPEn = ‘TIME’ 作为 Time 如果 TUNITn 因为该列不是FITS识别的时间单位。

细节#

在天文数据中,时间作为一个维度,在FITS文件中的表示是一个挑战。因此,该标准被扩展到严格描述 World Coordinate System 框架。参考 FITS WCS paper IV 有关详细信息。

允许 Time 因此,要在FITS表中写入时间坐标列的列需要以确保精度保持的方式存储时间值,并将相关元数据映射到相关的FITS关键字。

根据该标准,该标准规定在二进制表中可以使用双胞胎对, astropy 时间列被写在这样的表中作为两个双打的载体 (TFORMn = ‘2D’) (jd1, jd2) 哪里 JD = jd1 + jd2 .这将时间值复制到双精度,并且是“无损”版本,利用了二进制表中提供的更高精度。注意 jd1 始终是半整或整,而 abs(jd2) < 1 .“往返”的 astropy - 包含时间坐标列的写入FITS二进制表已通过映射选定的元数据部分实现, scale 和奇异 locationTime ,到相应的关键词。

实例#

考虑以下时间列::

>>> t = Table()
>>> t['a'] = Time([100.0, 200.0], scale='tt', format='mjd')

FITS标准需要一个附加的转换层返回到所需的格式。时间列 t['a'] 将接受翻译 Astropy Time --> FITS --> Astropy Time 对应于格式转换 mjd --> (jd1, jd2) --> jd . 因此,从 (jd1, jd2) 需要一个完全符合FITS时间标准的软件实现。

考虑到这一点,可以通过选择以 format 属性 Time 列,而不是 (jd1, jd2) 格式,标头中没有额外的元数据。这是“有损”版本,但有助于增强便携性。对于上面的示例,FITS列对应于 t['a'] 然后将存储 [100.0 200.0] 而不是 [[ 2400100.5, 0. ], [ 2400200.5, 0. ]] .这是通过设置 表序列化方法 对于编写时的时间列,如以下示例所示::

>>> from astropy.time import Time
>>> from astropy.table import Table
>>> from astropy.coordinates import EarthLocation
>>> t = Table()
>>> t['a'] = Time([100.0, 200.0], scale='tt', format='mjd')
>>> t.write('my_table.fits', overwrite=True,
...         serialize_method={Time: 'formatted_value'})
>>> tm = Table.read('my_table.fits')
>>> tm['a']
<Column name='a' dtype='float64' length=2>
100.0
200.0
>>> all(tm['a'] == t['a'].value)
True

默认情况下, serialize_method 对于时间列等于 'jd1_jd2' ,也就是说,时间列将完全精确地写入。

备注

这个 astropy Time 对象未精确映射到FITS时间标准。

  • FORMAT

    FITS格式只考虑三种格式:iso8601、JD和MJD。 astropy 时间允许许多其他格式,如 unixcxcsec 代表价值观。

    因此, format 不存储时间属性。从FITS读取后,用户必须设置 format 根据需要。

  • LOCATION

    在FITS标准中,时间坐标的参考位置是通过关键字表示的标量。但是,矢量化的参考位置或位置可以由 Green Bank Keyword Convention 这是一个注册的FITS大会。在 astropy 时间,位置可以是一个数组,可以广播到时间值。

    因此,矢量化 location 时间属性的存储和读取遵循此约定。