适合页眉

在接下来的三章中,我们将分别解释处理FITS头、图像/数组数据和表数据的更详细信息,包括示例。

HDU的标头

每个报头数据单元(HDU)通常有两个组件:报头和数据。在 astropy 这两个组件通过HDU的两个属性访问, hdu.headerhdu.data .

而HDU可能有空数据(即 .data 属性是 None ),任何HDU都将始终具有标头。使用构造函数创建HDU时(例如。, hdu = PrimaryHDU(data, header) ),用户可以从现有HDU的报头提供报头值,并从 numpy 数组。如果使用默认值(无),则新的HDU将具有该类型HDU所需的最少关键字:

>>> from astropy.io import fits
>>> hdu = fits.PrimaryHDU()
>>> hdu.header  # show the all of the header cards
SIMPLE  =                    T / conforms to FITS standard
BITPIX  =                    8 / array data type
NAXIS   =                    0 / number of array dimensions
EXTEND  =                    T

用户可以使用任何头和任何数据来构造新的HDU。 astropy 将删除所有描述数据结构的关键字,只留下信息性关键字。稍后,它将重新添加所需的结构关键字,以便与新的HDU和添加到其中的任何数据兼容。因此,用户可以使用表HDU的头来构造图像HDU,反之亦然。构造函数还将确保头中的数据类型和维度信息与数据一致。

Header属性

价值访问、更新和创建

如图所示 Getting Started 教程中,关键字值可以通过HDU头属性的关键字名称或索引访问。您也可以使用通配符 * 以获取与搜索字符串匹配的关键字-值对。下面是一个简短的总结:

>>> fits_image_filename = fits.util.get_testdata_filepath('test0.fits')
>>> hdul = fits.open(fits_image_filename)  # open a FITS file
>>> hdr = hdul[0].header  # the primary HDU header
>>> print(hdr[34])  # get the 2nd keyword's value
96
>>> hdr[34] = 20  # change its value
>>> hdr['DARKCORR']  # get the value of the keyword 'darkcorr'
'OMIT'
>>> hdr['DARKCOR*']  # get keyword values using wildcard matching
DARKCORR= 'OMIT              ' / Do dark correction: PERFORM, OMIT, COMPLETE
>>> hdr['darkcorr'] = 'PERFORM'  # change darkcorr's value

关键字名称不区分大小写,但在一些特殊情况下除外(请参阅有关层次卡和记录值卡的部分)。因此, hdr['abc']hdr['ABC']hdr['aBc'] 都是等价的。

和Python的一样 dict 类型,也可以使用赋值语法将新关键字添加到标头中:

>>> hdr = hdul[1].header
>>> 'DARKCORR' in hdr  # Check for existence
False
>>> hdr['DARKCORR'] = 'OMIT'  # Add a new DARKCORR keyword

也可以添加新值 and 通过将它们指定为元组进行注释::

>>> hdr['DARKCORR'] = ('OMIT', 'Dark Image Subtraction')

注解

在向标题中添加新关键字时,需要注意的一点是,默认情况下不会附加关键字 立即 直到文件的结尾。相反,它们被附加到最后一个非注释关键字之后。这是为了支持始终将所有历史关键字组合在一起的常见用例。一个新的非注释关键字将添加到现有关键字的末尾,但在标题末尾的任何历史/注释关键字之前。

有几种方法可以覆盖此功能:

  • 使用 Header.append() 方法与 end=True 论点:

    >>> hdr.append(('DARKCORR', 'OMIT', 'Dark Image Subtraction'), end=True)
    

    这将强制在标头的实际结尾添加新关键字。

  • 这个 Header.insert() 方法将始终在您要求的位置插入新关键字:

    >>> del hdr['DARKCORR']  # Delete previous insertion for doctest
    >>> hdr.insert(20, ('DARKCORR', 'OMIT', 'Dark Image Subtraction'))
    

    这将在头中的第20个关键字之前插入DARKCORR关键字,而不管它是什么。

可以使用相同的索引/名称语法删除关键字(及其对应的卡片):

>>> del hdr[3]  # delete the 2nd keyword
>>> del hdr['DARKCORR']  # delete the value of the keyword 'DARKCORR'

注意,与常规Python列表一样,索引在每次删除后都会更新,因此如果 del hdr[3] 连续执行两次时,第四个和第五个关键字将从原始标题中删除。同样, del hdr[-1] 将删除页眉中的最后一张卡。

也可以使用slice语法删除整个卡片范围:

>>> del hdr[3:5]

方法 Header.set() 是更新与现有关键字关联的值或注释或创建新关键字的另一种方法。它的大部分功能可以用上面所示的dict类语法复制。但在某些情况下,情况可能会更清楚。它还有一个优点,允许用户在标题中移动卡片,或者指定新卡片相对于现有卡片的位置:

>>> hdr.set('target', 'NGC1234', 'target name')
>>> # place the next new keyword before the 'TARGET' keyword
>>> hdr.set('newkey', 666, before='TARGET')  # comment is optional
>>> # place the next new keyword after the 21st keyword
>>> hdr.set('newkey2', 42.0, 'another new key', after=20)

在FITS标题中,每个关键字也可能有一个与之相关联的注释来解释其用途。与每个关键字关联的注释通过 comments 属性:

>>> hdr['NAXIS']
2
>>> hdr.comments['NAXIS']
'number of data axes'
>>> hdr.comments['NAXIS'] = 'The number of image axes'  # Update
>>> hdul.close()  # close the HDUList again

Comments can be accessed in all of the same ways that values are accessed, whether by keyword name or card index. Slices are also possible. The only difference is that you go through hdr.comments instead of just hdr by itself.

注释、历史记录和空白关键字

FITS标题中的大多数关键字都有唯一的名称。如果有两个以上的卡共享同一个名称,则当按名称引用时,它是第一个被访问的卡。副本只能通过数字索引访问。

有三个特殊的关键字(它们的关联卡片有时被称为评论卡片),它们通常会出现在FITS标题中多次。它们是(1)空白关键字,(2)历史,(3)注释。与其他关键字不同,当访问这些关键字时,它们以列表形式返回:

>>> filename = fits.util.get_testdata_filepath('history_header.fits')
>>> with fits.open(filename) as hdul:  # open a FITS file
...     hdr = hdul[0].header

>>> hdr['HISTORY']
I updated this file on 02/03/2011
I updated this file on 02/04/2011

这些列表可以像其他列表一样进行切片。例如,要只显示最后一个历史条目,请使用 hdr['history'][-1] . 现有的评论卡也可以通过使用该卡的适当索引号进行更新。

通过使用dict-like关键字赋值语法,或使用 Header.set() 我是说。但是,与其他关键字不同,新的评论卡总是添加并附加到最后一个注释卡中,该卡片具有相同的关键字,而不是在标题的末尾。

例子

添加新的评论卡:

>>> hdu.header['HISTORY'] = 'history 1'
>>> hdu.header[''] = 'blank 1'
>>> hdu.header['COMMENT'] = 'comment 1'
>>> hdu.header['HISTORY'] = 'history 2'
>>> hdu.header[''] = 'blank 2'
>>> hdu.header['COMMENT'] = 'comment 2'

修改后的标题中的部分变为:

HISTORY history 1
HISTORY history 2
        blank 1
        blank 2
COMMENT comment 1
COMMENT comment 2

用户还可以使用 Header.insert() 方法。

注解

讽刺的是,评论卡中没有注释,只有字符串值。

未定义的值

FITS头可以有未定义的值,这些值在Python中用特殊值表示 None . None 在将值赋给 HeaderCard .

>>> hdr = fits.Header()
>>> hdr['UNDEF'] = None
>>> hdr['UNDEF'] is None
True
>>> repr(hdr)
'UNDEF   =                                                                       '
>>> hdr.append('UNDEF2')
>>> hdr['UNDEF2'] is None
True
>>> hdr.append(('UNDEF3', None, 'Undefined value'))
>>> str(hdr.cards[-1])
'UNDEF3  =  / Undefined value                                                    '

卡片图像

FITS标题由卡片图像组成。

FITS标题中的卡片图像由关键字名称、值和可选的注释组成。从物理上讲,在FITS文件的存储格式中,它需要80列(字节)-不带回车符。在 astropy ,每个卡片图像都由 Card 对象。还有一些特殊种类的卡片:评论卡片(见上文)和卡片图像,它可以拍摄超过一张80列的卡片图像。后者将在稍后讨论。

大多数时候处理卡片的细节是由 Header 对象,而不必直接操作卡片。事实上,大多数 Header 接受 (keyword, value)(keyword, value, comment) 元组作为参数也可以使用 Card 对象作为参数。 Card 对象只是围绕这样的元组的包装器,这些元组提供解析和格式化头中单个卡的逻辑。手动使用 Card 对象,但在实际将卡添加到标头之前检查它在标头中的显示方式。

创建一个新的Card对象 Card 构造函数: Card(key, value, comment) .

例子

要创建新的卡片对象:

>>> c1 = fits.Card('TEMP', 80.0, 'temperature, floating value')
>>> c2 = fits.Card('DETECTOR', 1)  # comment is optional
>>> c3 = fits.Card('MIR_REVR', True,
...                'mirror reversed? Boolean value')
>>> c4 = fits.Card('ABC', 2+3j, 'complex value')
>>> c5 = fits.Card('OBSERVER', 'Hubble', 'string value')

>>> print(c1); print(c2); print(c3); print(c4); print(c5)  # show the cards
TEMP    =                 80.0 / temperature, floating value
DETECTOR=                    1
MIR_REVR=                    T / mirror reversed? Boolean value
ABC     =           (2.0, 3.0) / complex value
OBSERVER= 'Hubble  '           / string value

卡片有属性 .keyword.value.comment .两者都是 .value.comment 可以改变但不能改变 .keyword 属性。换句话说,一旦创建了一张卡,它就为一个特定的、不可变的关键字创建。

这个 Card() 构造器将检查给定的参数是否符合FITS标准并且具有固定的卡片图像格式。如果用户想要创建一个自定义格式的卡,甚至是一个不符合FITS标准的卡(例如,出于测试目的),则 Card.fromstring() 可以使用类方法。

卡片可以用 Card.verify() . 非标准卡片 c2 在下面的例子中,通过这样的验证来标记。有关验证的详细信息 astropy 将在后面的章节中讨论。

>>> c1 = fits.Card.fromstring('ABC     = 3.456D023')
>>> c2 = fits.Card.fromstring("P.I. ='Hubble'")
>>> print(c1)
ABC     = 3.456D023
>>> print(c2)  
P.I. ='Hubble'
>>> c2.verify()  
Output verification result:
Unfixable error: Illegal keyword name 'P.I.'

一份清单 Card 对象 Header 对象可以通过 Header.cards 属性。不应该仅仅是为了观察而被操纵。事实上,它只是一个拷贝-对它的修改不会影响它来自的头。使用 Header 改为类。

连续卡片

事实上,FITS标准只允许最多8个字符作为关键字名称,80个字符可以包含关键字、值和注释,这对某些应用程序是有限制的。为了允许关键字使用长字符串值,提出了一个建议:

在包含关键字的常规80列之后使用CONTINUE关键字。 astropy 支持此约定,这是自4.0版以来的FITS标准的一部分。

实例

下面的示例显示,对于长字符串值,CONTINUE是自动使用的:

>>> hdr = fits.Header()
>>> hdr['abc'] = 'abcdefg' * 20
>>> hdr
ABC     = 'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcd&'
CONTINUE  'efgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefga&'
CONTINUE  'bcdefg'
>>> hdr['abc']
'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg'
>>> # both value and comments are long
>>> hdr['abc'] = ('abcdefg' * 10, 'abcdefg' * 10)
>>> hdr
ABC     = 'abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcd&'
CONTINUE  'efg&'
CONTINUE  '&' / abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefga
CONTINUE  '' / bcdefg

请注意,当使用CONTINUE卡时,在每个80个字符的卡片图像的末尾,会出现一个与号。和号不是字符串值的一部分。此外,在CONTINUE之后的第九列没有“=”。在第一个示例中,整个240个字符由 astropy 作为一张卡片。因此,如果它是标题中的第n张卡片,(n+1)第张卡片指的是下一个关键字,而不是下一张CONTINUE卡片。因此,CONTINUE卡由 astropy 作为一个单一的逻辑卡,一般不必担心格式的细节。可以像常规关键字一样访问和更新解析为一组CONTINUE卡片的关键字。

等级卡

对于长度超过8个字符的关键字,欧洲南方天文台(ESO)制定了一个惯例,以便于使用。它使用一个特殊的关键字层次结构,后面是实际的长关键字。 astropy 也支持这项公约。

如果关键字包含八个以上的字符 astropy 将自动使用分层卡,但也会发出警告,以防出错。但是,您可以通过在关键字前面加上“HIERARCH”来显式地请求层次结构卡(就像它将出现在标题中一样)。例如, hdr['HIERARCH abcdefghi'] 将创建关键字 abcdefghi 没有显示警告。创建后,可以像访问其他关键字一样访问层次结构关键字: hdr['abcdefghi'] ,而不在关键字前面添加“HIERARCH”。

实例

astropy 当关键字包含超过八个字符时,将使用分层卡并发出警告:

>>> # this will result in a Warning because a HIERARCH card is implicitly created
>>> c = fits.Card('abcdefghi', 10)  
>>> print(c)  
HIERARCH abcdefghi = 10
>>> c = fits.Card('hierarch abcdefghi', 10)
>>> print(c)
HIERARCH abcdefghi = 10
>>> hdu = fits.PrimaryHDU()
>>> hdu.header['hierarch abcdefghi'] =  99
>>> hdu.header['abcdefghi']
99
>>> hdu.header['abcdefghi'] = 10
>>> hdu.header['abcdefghi']
10
>>> hdu.header
SIMPLE  =                    T / conforms to FITS standard
BITPIX  =                    8 / array data type
NAXIS   =                    0 / number of array dimensions
EXTEND  =                    T
HIERARCH abcdefghi = 10

注解

关于 Header 类的大部分设计都是为了抽象出有关FITS格式的怪癖。这就是为什么,例如,它会自动创建CONTINUE和HIERARCH卡。头只是一个数据结构,作为用户,您不必担心它最终如何被序列化为FITS文件中的头。

尽管有些地方几乎不可能隐藏FITS格式的怪癖, astropy 试着让你尽量少去想它。如果有任何地方是模糊的或难以理解的头部是如何构造的,请让我们知道,因为可能有一些领域可以改进,甚至更多。