top of page

天文中的常用Python操作(FITS)

FITS(Flexible Image Transport System)[1]是一种用来存储、传输和操作天文科学数据和相关信息的通用格式,这些数据可以是一维的光谱、二维的图像、三维或更高维的数据块,也可以是ASCII或二进制的表格。FITS同时会包含数据的观测信息和校准信息,以方便后续的数据处理。


一个FITS文件可能包括一组或多组HDU(Header Data Unit),每一组HDU都包括一个头文件和一个数据单元。第一个HDU被称为主HDU(primary HDU),其它的HDU则被称为FITS扩展(FITS extension),FITS文件的主HDU也有可能是空的,只有扩展HDU中包含数据。


FITS包括三种基本的数据类型:

  • 图像扩展(主HDU中也可以是图像数据):N维数据块,使用统一的数据类型(一共有六种数据类型可供使用:8位无符号整型,16、32、64位有符号整型,32、64位浮点数)。

  • ASCII表格扩展:可以用来储存星表或天文信息列表,每一行都是固定的长度,并被分成固定长度的不同部分,可以存放ASCII字符串,或者字符串格式的数字。

  • 二进制表格扩展:比ASCII表格提供了更多的数字存储特性,即可以存储可变长度的数据,并且占用的空间更小。


FITS的头文件或者数据单元的大小必须是2880字节的整数倍,末尾未使用的空间要用0或者空格来补齐。头文件由很多长度为80字符的关键字记录组成,通用格式为关键字 = 数值 / 注释(KEYNAME = value / comment)。头文件会记录对应数据单元的大小和格式这样的必要信息,以及观测的日期和时间等信息,关键字COMMENT和HISTORY也经常被用来进一步记录数据的内容。


FITS图像数据的直接查看和简单分析可以通过DS9[2]来完成。DS9中显示的FITS文件的数据部分和头文件信息分别如图所示(这个FITS来自HASH,显示了一个Halpha波段的行星状星云):



本教程所需全部Python包:

# 本教程所需的全部Python包
from astropy.table import Table
from astropy.io import fits
import numpy as np


1. 读取FITS:


[3]在Python中,我们使用astropy.io.fits来进行FITS文件的操作。FITS的读取主要有两种形式:


1.1 astropy.io.fits.open()


可以使用fits.open()直接打开FITS文件,并将HDU数据储存在变量hdu中。然后通过使用hdu[0]来索引主HDU(如果有扩展HDU,依次为1,2,3……),并用.header和.data来获取其中的头文件和数据。得到的头文件和数据与hdu.info()输出的信息一致。


读取结束后需要使用hdu.close()关闭文件。(好像很少留意到有人这样做,但还是要尽量符合代码规范。)


读取FITS并输出HDU信息(如果已经import所需的包,不需要重复操作):

from astropy.io import fits

# 这个函数仅用来搜索astropy自带的FITS示例,这一行可以给定自己的路径和文件名fits_image_filename = fits.util.get_testdata_filepath('test0.fits')
# fits_image_filename = '/path/to/your/file.fits'

# 打开FITS文件
hdu = fits.open(fits_image_filename)
# 输出HDU信息
hdu.info()

输出:

Filename: /opt/anaconda3/lib/python3.9/site-packages/astropy/io/fits/tests/data/test0.fits
No.    Name      Ver    Type      Cards   Dimensions   Format
  0  PRIMARY       1 PrimaryHDU     138   ()      
  1  SCI           1 ImageHDU        61   (40, 40)   int16   
  2  SCI           2 ImageHDU        61   (40, 40)   int16   
  3  SCI           3 ImageHDU        61   (40, 40)   int16   
  4  SCI           4 ImageHDU        61   (40, 40)   int16

读取头文件和数据单元,并关闭文件:

# 读出头文件
hd = hdu[1].header
print(len(hd),type(hd))
# 读出数据
data = hdu[1].data
print(len(data),type(data))

# 关闭文件
hdu.close()

输出:

61 <class 'astropy.io.fits.header.Header'>
40 <class 'numpy.ndarray'>

如果不想使用hdu.close()来关闭文件,可以使用如下方法,退出with时文件会被自动关闭:

# 如果不想手动关闭文件,可以使用如下方式
with fits.open(fits_image_filename) as hdu:
    hdu.info()

输出:

Filename: /opt/anaconda3/lib/python3.9/site-packages/astropy/io/fits/tests/data/test0.fits
No.    Name      Ver    Type      Cards   Dimensions   Format
  0  PRIMARY       1 PrimaryHDU     138   ()      
  1  SCI           1 ImageHDU        61   (40, 40)   int16   
  2  SCI           2 ImageHDU        61   (40, 40)   int16   
  3  SCI           3 ImageHDU        61   (40, 40)   int16   
  4  SCI           4 ImageHDU        61   (40, 40)   int16    

1.2 一些便捷的函数


astropy.io.fits也提供了一些方便调用的函数,这样可以直接获得所需的数据,而且不需要关闭文件。但是需要注意的是,这些函数的效率比较低,不适合在复杂的分析脚本和应用程序中使用。近期看到很多程序都直接使用了类似的方法,在应用到大数据量的时候要特别注意。


以下通过几个例子来简单介绍用来获取整个头文件的getheader()、直接获取头文件关键字的getval()、获取数据信息的getdata()的使用:

from astropy.io import fits

# 获取第二个'SCI'扩展的头文件
hd = fits.getheader(fits_image_filename, extname='sci', extver=2)
print(len(hd),type(hd))

# 获取主HDU的观测时间
flt = fits.getval(fits_image_filename, 'date', 0)
print(flt)

# 获取第三个'SCI'扩展的数据
data = fits.getdata(fits_image_filename, 'sci', 3)
print(len(data),type(data))

# 获取第一个扩展HDU的数据和头文件
data, hd = fits.getdata(fits_image_filename, 1, header=True)
print(len(data),type(data))
print(len(hd),type(hd))

输出:

61 <class 'astropy.io.fits.header.Header'>
01/04/99
40 <class 'numpy.ndarray'>
40 <class 'numpy.ndarray'> 
61 <class 'astropy.io.fits.header.Header'>

2. 处理FITS头文件:


头文件包括很多行,每一行都是80个字节,被分为三部分:关键字、数值和注释。其中关键字和注释必须是字符串,数值可以是字符串、整数、浮点数、复数或者布尔值(True/False)。


2.1 读取头文件信息


头文件中记录了数据拍摄和校准的重要信息,除了COMMENT和HISTORY等特殊例子,关键字一般是不会重复的,所以可以根据关键字来调用数值,另外也可以通过索引/行数来调用。这里的索引是按Python的惯例,从0开始计数的。


一般来说,使用关键字来调用比较合理,因为每个关键字所在的行数可能是不固定的,使用行数来调用可能会出现问题,尤其是在修改数值的时候要小心。


头文件中的关键字一般是大写的,但是调用的时候对大小写不敏感。如果这个头文件中不含有所调用的关键字,就会产生报错。


通过关键字和索引来读取头文件信息,以及读出头文件信息的注释:

from astropy.io import fits

# 打开FITS文件
hdu = fits.open(fits_image_filename)

# 通过关键字读取主HDU的日期
date = hdu[0].header['DATE']
# 通过索引来读取主HDU的日期
date1 = hdu[0].header[9]

# 读出头文件注释
hd = hdu[0].header
cmt = hd.comments['DATE']
print(date,date1,cmt)

输出:

01/04/99 01/04/99 Date FITS file was generated

2.2 修改头文件信息


可以用直接赋值的形式来修改头文件信息,如果关键字不存在,这个操作会自动在头文件末尾添加一行,如果是COMMENT和HISTORY的话,则会在对应的关键字末尾添加一行。


另一种修改或新增头文件信息的方法是header.set()。


修改或新增头文件信息:

# 读出头文件
hd = hdu[0].header

# 用关键字修改头文件信息,如果关键字不存在,就会在头文件末尾添加
hd['targname'] = 'NGC121-a'
# 以元组的形式,同时修改数值和注释
hd['targname'] = ('NGC121-a', 'the observation target')

# 用索引修改头文件信息
hd[27] = 99

# 修改或新增关键字的另一种方法
hd.set('observer', 'Edwin Hubble')
print(hd['targname'],hd[27],hd['observer'])

输出:

NGC121-a 99 Edwin Hubble

如果对COMMENT和HISTORY关键字进行同样的操作,只会增加一行,而不会修改已有的信息。如果想修改已有的信息,需要使用索引。


另外,不要混淆COMMENT关键字和每一行的注释(英文也是comment)。


添加和修改HISTORY关键字(如果重复运行这几行代码,会输出四行,读者可以思考一下为什么会这样):

# 添加history关键字
hd['history'] = 'I updated this file on 2/26/09'
print(hd['history'])

# 修改history关键字
hd['history'][0] = 'I updated this file on 2/27/09'
print(hd['history'])

输出:

I updated this file on 2/26/09
I updated this file on 2/27/09

2.3 显示头文件信息


由于很多头文件是不标准的,在调用前有时需要查看所需的关键字,或打印整个头文件来查看。除了用hdu.info()输出HDU信息,以及用关键字和索引来引用单行的头文件信息,还有更多的显示头文件的方法,这里再介绍三种:


使用list(hd.keys())可以获取头文件的关键字,快速找到需要使用的关键字:

# 获取头文件关键字
print(list(hd.keys()))

输出:

['SIMPLE', 'BITPIX', 'NAXIS', 'EXTEND', 'GROUPS', 'NEXTEND', 'BSCALE', 'BZERO', 'ORIGIN', 'DATE', 'IRAF-TLM', '', '', '', '', '', '', '', '', '', '', '', '', 'INSTRUME', 'ROOTNAME', 'FILETYPE', '', '', 'MODE', 'SERIALS', '', '', 'IMAGETYP', 'CDBSFILE', 'PKTFMT', '', '', 'FILTNAM1', 'FILTNAM2', 'FILTER1', 'FILTER2', 'FILTROT', 'LRFWAVE', '', '', 'UCH1CJTM', 'UCH2CJTM', 'UCH3CJTM', 'UCH4CJTM', 'UBAY3TMP', 'KSPOTS', 'SHUTTER', 'ATODGAIN', '', '', 'MASKCORR', 'ATODCORR', 'BLEVCORR', 'BIASCORR', 'DARKCORR', 'FLATCORR', 'SHADCORR', 'DOSATMAP', 'DOPHOTOM', 'DOHISTOS', 'OUTDTYPE', '', '', 'MASKFILE', 'ATODFILE', 'BLEVFILE', 'BLEVDFIL', 'BIASFILE', 'BIASDFIL', 'DARKFILE', 'DARKDFIL', 'FLATFILE', 'FLATDFIL', 'SHADFILE', 'PHOTTAB', 'GRAPHTAB', 'COMPTAB', '', '', 'SATURATE', 'USCALE', 'UZERO', '', '', 'READTIME', '', '', 'PA_V3', 'RA_SUN', 'DEC_SUN', 'EQNX_SUN', 'MTFLAG', 'EQRADTRG', 'FLATNTRG', 'NPDECTRG', 'NPRATRG', 'ROTRTTRG', 'LONGPMER', 'EPLONGPM', 'SURFLATD', 'SURFLONG', 'SURFALTD', '', '', 'PODPSFF', 'STDCFFF', 'STDCFFP', 'RSDPFILL', '', '', 'UEXPODUR', 'NSHUTA17', 'DARKTIME', 'UEXPOTIM', 'PSTRTIME', 'PSTPTIME', '', '', '', '', 'ORIENTAT', 'SUNANGLE', 'MOONANGL', 'SUN_ALT', 'FGSLOCK', '', 'DATE-OBS', 'TIME-OBS', 'EXPSTART', 'EXPEND', 'EXPTIME', 'EXPFLAG', 'FILENAME', 'TARGNAME', 'OBSERVER', 'HISTORY']

使用切片来查看多行头文件(可以参考Python的切片的使用方法):

# 显示头文件前两行,不分行,这里的0可以省略
print(hd[0:2])

# 显示头文件前两行,分行
print(repr(hd[0:2]))

输出(这里调小了字号以显示格式的区别):

SIMPLE  =                    T / file does conform to FITS standard             BITPIX  =                   16 / number of bits per data pixel                  END                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
SIMPLE  =                    T / file does conform to FITS standard             
BITPIX  =                   16 / number of bits per data pixel 

用合适的格式查看整个头文件(如果直接打印整个头文件,格式会比较混乱,加上repr()之后,能比较清楚地分行显示):

# 显示整个头文件,不加repr()也可以显示,但是不会分行
print(repr(hd))

部分输出:

SIMPLE  =                    T / file does conform to FITS standard             
BITPIX  =                   16 / number of bits per data pixel                  
NAXIS   =                    0 / number of data axes                            
EXTEND  =                    T / FITS dataset may contain extensions            
GROUPS  =                    F / data has groups                                
NEXTEND =                    4 / Number of standard extensions                  
BSCALE  =           1.000000E0 / REAL = TAPE*BSCALE + BZERO                     
BZERO   =           3.276800E4 /                                                
ORIGIN  = 'NOAO-IRAF FITS Image Kernel Aug 1 1997' / FITS file originator       
DATE    = '01/04/99  '         / Date FITS file was generated                   
IRAF-TLM= 'xxx     '              / Time of last modification         
......

3. 处理FITS数据:


FITS的数据单元是FITS中重点处理的部分,后面的文章还会进行更多的介绍,这里只介绍一些基本操作。


前文已经介绍过如何简单地用索引来读取数据单元,还可以使用拓展名(EXTNAME)来引用,如果有多个同名的拓展,第一个拓展仍然可以只使用拓展名来引用,但是需要同时使用索引(EXTVER)来引用后面的拓展。(NAME和VER见hdu.info()的输出。)


在这个例子里,主HDU是hdu[0],第一个拓展HDU是hdu[1]或hdu['sci']或hdu['sci',1],第二个拓展HDU是hdu[2]或hdu['sci',2],以此类推。这里的'SCI'也是大小写不敏感的。


另外,要特别注意FITS的x和y与Python中是相反的,可以自己检查一下。


3.1 处理图像数据


读出图像数据并获得数据形状、数据类型、像素值的信息:

# 使用拓展名和索引来读出数据,如果不引起歧义,可以省略其中之一
data = hdu['SCI',2].data

# 获得数据的形状、数据类型信息
print(data.shape,data.dtype.name)
# 查看x=5,y=2的像素值
print(data[1, 4])
# 查看x=11到20,y=31到40的像素值
print(data[30:40, 10:20])

输出:

(40, 40) int16
348
[[350 349 349 348 349 348 349 347 350 348]
 [348 348 348 349 348 349 347 348 348 349]
 [348 348 347 349 348 348 349 349 349 349]
 [349 348 349 349 350 349 349 347 348 348]
 [348 348 348 348 349 348 350 349 348 349]
 [348 347 349 349 350 348 349 348 349 347]
 [347 348 347 348 349 349 350 349 348 348]
 [349 349 350 348 350 347 349 349 349 348]
 [349 348 348 348 348 348 349 347 349 348]
 [349 349 349 348 350 349 349 350 348 350]]

3.2 处理表格数据


我们经常用Pandas来处理表格数据,所以这里也只是简单介绍一下astropy.io.fits中的一些基本的处理方法。


表格的每一行都是一个FITS_record对象,由不同数据类型的元素组成,所以表格就是由这些记录组成的数组。可以通过索引来读取表格中的行,或者通过列名来读出表格中的列,也可以使用field()方法,通过索引或者列名来获得表格的每一列:

from astropy.io import fits

# 读取表格数据
fits_table_filename = fits.util.get_testdata_filepath('tb.fits')
hdu = fits.open(fits_table_filename)
data = hdu[1].data

# 使用索引来读出表格的第一行
print(data[0])
# 使用列名来读出表格的第一列
print(data['c1'])

# field()方法,使用索引读出表格的第一列
print(data.field(0))
# field()方法,用列名读出表格的第一列
print(data.field('c1'))

输出:

(1, 'abc', 3.7000000715255736, False)
[1 2]
[1 2]
[1 2]

我们更推荐使用列名来获得表格中的列,这样不会受到顺序的影响,另外,列名也是大小写不敏感的。如何知道表格中有哪些列名,以及获得其它信息:

# 获得表格中列的信息
cols = hdu[1].columns
print(cols)

# 获得某一项列信息,比如列名
print(cols.names)

输出:

ColDefs(
    name = 'c1'; format = '1J'; null = -2147483647; disp = 'I11'
    name = 'c2'; format = '3A'; disp = 'A3'
    name = 'c3'; format = '1E'; bscale = 3; bzero = 0.4; disp = 'G15.7'
    name = 'c4'; format = '1L'; disp = 'L6'
)
['c1', 'c2', 'c3', 'c4']

另一种获得表格中的列信息的方法:

# 另一种获得表格中的列信息的方法
print(cols.info())

部分输出:

name:
    ['c1', 'c2', 'c3', 'c4']
format:
    ['1J', '3A', '1E', '1L']
unit:
    ['', '', '', '']
null:
    [-2147483647, '', '', '']
bscale:
    ['', '', 3, '']
bzero:
    ['', '', 0.4, '']
disp:
    ['I11', 'A3', 'G15.7', 'L6']
......

因为这些列都是Numpy对象,所以可以对其进行各种Numpy的操作,比如修改表格,以及对表格信息进行统计:

# 修改表格,比如将第四列赋值为0(变为False)
print(data['c4'])
data['c4'][:] = 0
print(data['c4'])

# 求第三列的平均值
print(data['c3'].mean())

输出:

[False False]
[False False]
5.19999989271164

4.写入FITS:


4.1 写入修改的结果


在对FITS进行操作之后,我们可以对结果进行保存,仍然写入FITS中。


使用hdu.writeto()可以将内存中的数据和头文件版本写入一个新的FITS文件:

# 将内存中的数据和头文件写入新的FITS,如果文件已存在则覆盖原文件hdu.writeto('newtable.fits', overwrite=True)

也可以通过添加overwrite=True,来写入原文件,但是为了保留备份,还是比较推荐写入新的文件。另外,设置这个参数也可以方便重复运行这个命令,不然会因为文件已存在而报错。


4.2 建立一个新的FITS文件


我们经常需要从头开始建立一个FITS文件,并写入需要保存的数据,这里我们用一个新建的Numpy数组来作为数据单元:

from astropy.io import fits
import numpy as np

# 建立一个从0到99的浮点数数组作为数据单元
n = np.arange(100.0)
print(n)

# 建立一个PrimaryHDU对象
hdu = fits.PrimaryHDU(n)
# 建立一个HDU列表并写入一个新文件
hdul = fits.HDUList([hdu])
hdul.writeto('new1.fits', overwrite=True)
# 也可以直接将HDU对象写入文件,等同于以上两行
hdu.writeto('new2.fits', overwrite=True)

输出:

[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17.
 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35.
 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53.
 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71.
 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89.
 90. 91. 92. 93. 94. 95. 96. 97. 98. 99.]

我们也可以新建一个新的表格文件,如果只想新建一个二进制FITS表格,不需要其它扩展,可以使用astropy.table中的Table包,然后写入FITS,这个方法会比astropy.io.fits的方法更简洁

from astropy.table import Table

# 使用Table包,新建一个二进制表格,并写入FITS
# 建立二进制表格
t = Table([[1, 2], [4, 5], [7, 8]], names=('a', 'b', 'c'))
print(t)
# 写入FITS
t.write('table1.fits', format='fits', overwrite=True)

输出:

 a   b   c 
--- --- ---
  1   4   7
  2   5   8

使用astropy.io.fits的方法如下:

from astropy.io import fits
import numpy as np

# 新建一个表格并写入FITS
# 分别建立每一列,输入列名、数据和格式
c1 = fits.Column(name='a', array=np.array([1, 2]), format='K')
c2 = fits.Column(name='b', array=np.array([4, 5]), format='K')
c3 = fits.Column(name='c', array=np.array([7, 8]), format='K')
# 建立二进制表格HDU
t = fits.BinTableHDU.from_columns([c1, c2, c3])
print([c1, c2, c3])
print(t)
# 写入FITS
t.writeto('table2.fits', overwrite=True)

输出:

[name = 'a'; format = 'K', name = 'b'; format = 'K', name = 'c'; format = 'K']
<astropy.io.fits.hdu.table.BinTableHDU object at 0x7fd980c7bbe0>

注意表格只能作为扩展HDU,而不能作为主HDU,所以新建的FITS的主HDU中不会包含数据,读者可以自行用本文开头介绍的hdu.info()方法来查看。


4.3 建立多扩展的FITS


同一个FITS中可以同时包括不同类型、不同大小的主HDU和扩展HDU:

from astropy.io import fits
import numpy as np

# 新建一个多扩展的FITS
# 新建图像数组
n = np.ones((3, 3))
n2 = np.ones((100, 100))
# 新建头文件,并添加一些信息
hdr = fits.Header()
hdr['OBSERVER'] = 'Edwin Hubble'
hdr['COMMENT'] = "Here's some commentary about this FITS file."

# 建立HDU对象(主HDU和图像扩展HDU)
primary_hdu = fits.PrimaryHDU(n, header=hdr)
image_hdu = fits.ImageHDU(n2)

# 建立二进制表格HDU对象(同上)
c1 = fits.Column(name='a', array=np.array([1, 2]), format='K')
c2 = fits.Column(name='b', array=np.array([4, 5]), format='K')
c3 = fits.Column(name='c', array=np.array([7, 8]), format='K')
table_hdu = fits.BinTableHDU.from_columns([c1, c2, c3])

# 建立HDU列表
hdul = fits.HDUList([primary_hdu, image_hdu, table_hdu])
# 也可以追加更多的HDU
n3 = np.ones((10, 10, 10))
image_hdu2 = fits.ImageHDU(n3)
hdul.append(image_hdu2)
print(hdul.info())

# 写入FITS
hdul.writeto('new3.fits', overwrite=True)

输出:

Filename: (No file associated with this HDUList)
No.    Name      Ver    Type      Cards   Dimensions   Format
  0  PRIMARY       1 PrimaryHDU       8   (3, 3)   float64   
  1                1 ImageHDU         7   (100, 100)   float64   
  2                1 BinTableHDU     14   2R x 3C   ['K', 'K', 'K']   
  3                1 ImageHDU         8   (10, 10, 10)   float64   
None

有时候我们也需要建立一个空的主HDU,只包含一些基本的头文件信息,这时候primary_hdu = fits.PrimaryHDU(header=hdr)只输入头文件即可。在这一步,函数会自动建立一个包含基本信息(比如SIMPLE和NAXIS等关键字)的头文件,读者只需要处理观测相关的关键字即可。


4.4 一些便捷的函数


除了之前介绍的一些获取信息的便捷函数,还有一些可以用来修改和写入FITS文件。因为不太常见,所以这里只做简单介绍:

from astropy.io import fits

# 写入FITS,这里的data和hdr是之前读出的,可以改成自己的数据fits.writeto('out.fits', data, hdr, overwrite=True)
# 追加写FITS,如果不存在,则新建,每次运行都会追加写一次
fits.append('out1.fits', data, hdr)
# 比较两个FITS版本的差别
fits.printdiff('out.fits', 'out1.fits')
# 可以比较指定的HDU的差别
fits.printdiff('out.fits', 'out1.fits', ext=0)

第一次运行输出:

 fitsdiff: 5.0.4
 a: out.fits
 b: out1.fits
 Maximum number of different data values to be reported: 10
 Relative tolerance: 0.0, Absolute tolerance: 0.0

No differences found.

 No differences found.

第二次运行输出:

 fitsdiff: 5.0.4
 a: out.fits
 b: out1.fits
 Maximum number of different data values to be reported: 10
 Relative tolerance: 0.0, Absolute tolerance: 0.0

Files contain different numbers of HDUs:
 a: 2
 b: 3
No differences found between common HDUs.

 No differences found.

这里out.fits每次运行都会被重复写一次,而out1.fits每次运行都会追加写一次,于是使用printdiff可以查看HDU数量的差别,而HDU的内容并没有差别。


扩展阅读:

[3]FITS File Handling (astropy.io.fits): https://docs.astropy.org/en/stable/io/fits/index.html


欢迎提需求、给意见、催更、进群、合作联系等~

感谢联系!

© 2023 by Train of Thoughts. Proudly created with Wix.com

bottom of page