参考来源: 这个神奇的英文教程, 据说是Innsbruck University的私货
注意
这篇是一篇搬运+翻译,以后可能也有陆陆续续的该教程的搬运+翻译。
据说来自Innsbruck University的私货。(黑人问号???),感觉挺不错的。
转载者或者引用者,请标注本站域名和该文作者。
该文作者:岐山凤鸣,真名熊楚原,域名ecohnoch.cn
Python天文包
这里我们介绍astropy库和附属的包astroquery
两个官方文档如下:
http://docs.astropy.org/en/stable/index.html#
https://astroquery.readthedocs.io/en/latest/
安装这两个包可以用conda:
conda install astropy
conda install -c astropy astroquery
有很多和astropy相关的包,你可能感兴趣,感兴趣就看看这个表吧:
http://www.astropy.org/affiliated/
FITS 文件
FITS文件是到目前为止天文学数据最喜欢被存储的格式。它来自于两种原料。
- 图片
- 表格
为了读取这两种文件,我们要导入两种不同的附属于astropy的包:
from astropy.io import fits
from astropy.table import Table
FITS 文件可以保存多维数据(2维,3维),任何给定的FITS文件都能包含多个图片或者表格,它们都被叫做扩展。每一个FITS扩展都包含一个头和数据。FITS头包含WCS(世界坐标系统)信息表示一个给定的坐标点在天空的什么地方。
不像Python,FITS习惯将索引值从1开始,并且很重视这一点。
读一个FITS文件
有几个很方便的函数可以让你很轻松读取一个FITS文件:
from astropy.io import fits
img1 = fits.getdata(filename) # 获取图片
head1 = fits.getheader(filename) # 获取头
这打开了一个numpy 数组(关于numpy的话,这是一个python 的科学计算库,有机会我再写博客解释),头是一个很像Python中字典数据结构的东西。
打开其他的扩展在FITS文件中:
img1 = fits.getdata(filename, 0) # 初级扩展
img2 = fits.getdata(filename, 1) # 二级扩展
img2 = fits.getdata(filename, ext = 1) # 等效
对FITS来说,用URL来访问也是可以的,可以和下载文件的函数协同使用:
from astropy.utils.data import download_file
from astropy.io import fits
image_file = download_file('http://data.astropy.org/tutorial/FITS-images/HorseHead.fits', cache = True) # 导入马头星云的图片
为了得到我们刚刚打开的这个文件的信息,我们可以用fits.info这个函数:
fits.info(image_file)
结果如下:
然后我们可以决定打开一个扩展,检查它的形状并且最终用matplotlib(是一款经常和numpy联合在一起使用的东西,可以想象用matlab画图的那种东西把)可视化
image_data = fits.getdata(image_file, ext = 0)
image_data.shape
结果:
(893, 891)
import matplotlib.pyplot as plt
%matplotlob inline
plt.figure()
plt.imshow(image_data, cmap = 'gist_heat', origin = 'lower')
plt.colorbar()
结果如下
用一种通常的方法来读FITS文件
在一种寻常的方法中,定义一个头数据单元(header data unit, hdu)可以保存所有的FITS文件中的goodis列表。
然后,得到我们只需要的那个。
首先,我们先打开列表:
hdulist = fits.open(image_file)
hdulist.info()
结果如下:
然后,我们可以提取出头和数据,从第一个扩展当中,我们可以用这两种方法:
- 通过特定识别扩展的编号
- 通过特定识别扩展的名字,如果这个名字定义了的话
header = hdulist['PRIMARY'].header
data = hudlist['PRIMARY'].data
FITS文件就是这种方法读取,从第一的元素(对天文数据经常是RA)到最后的元素的一个numpy数组,一定要二次确认你有你需要的元素。
我们就可以在这个点上,关闭这个文件了。
hdulist.close()
现在,让我们来探索这个头吧。为了显示出一个人类可以理解的东西,经常用repr这个函数来添加一些换行,在关键字之间:
print(repr(header[: 10])) # 头的开始部分
结果如下:
我们可以获取这个表中的关键字,值,和一些特定的关键字和注释:
print(header[:10].keys())
print(header[:10].values())
print(header['ORIGIN'])
print(header.comments['ORIGIN'])
为了提取天体测定数据,我们可以用wcs包(在astropy中有),这允许我们用图像来显示坐标后的天文数据。
from astropy.wcs import WCS
wcs = WCS(header)
print(wcs)
结果如下:
这里有一个可视化的显示结果,如果想要看更多细节,可以去这个页面
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], projection = wcs)
#ax = plt.subplot(projection = wcs)
ax.set_xlabel('RA')
ax.set_ylabel('Dec')
ax.imshow(data, cmap = 'gist_heat', origin = 'lower')
ra = ax.coords[0]
ra.set_major_formatter('hh:mm:ss')
dec = ax.coords[1]
dec.set_major_formatter('dd:mm:ss')
效果如下:
坐标转换
Astropy提供了一种方法解决坐标,并且自动处理变换:
from astropy.coordinates import SkyCoord
# 制作坐标
c1 = SkyCoord(ra, dec, frame = 'icrs', unit = 'deg')
c2 = SkyCoord(1, b, frame = 'galactic', unit = 'deg')
c3 = SkyCoord('00h12m30s', '+42d12m00s')
# 显示和变换
c1.ra, c1.dec, c1.ra.hour, c2.ra.hms, c3.dec.dms
c2.fk5, c1.galactic # 插入转换
c2.to_string('decimal'), c1.to_string('hmsdms')
举个栗子。让我们计算马头星云的中心坐标:
from astropy.coordinates import SkyCoord
c0 = SkyCoord('5h41m00s', '-2d27m00s', frame = 'icrs')
print(c0)
显示结果:
从点到坐标,反之亦然
这个wcs对象还包含从点到世界坐标的方法,并且反之亦然
# 从点到世界
ra, dec = w.all_pix2world(xpx, ypx, 0) # 可以是一个表
# 第三个参数表示你在开始
# 从0(py标准)或者1(FITS标准)
# 从世界到点
xpx, ypx = w.all_world2pix(ra, dec, 0)
center = wcs.all_world2pix(c0, ra, c0.dec, 0)
print(center)
显示结果:
[array(534.1235215073059), array(475.5504697035576)]
切割
我们偶尔有时候需要一张图像的一小部分,所以,我们可以提取一部分图像并且存储,这里可以用类Cutout2D
这个类允许你创造一个可以剪切的二维数组对象。如果一个WCS对象在输入,之后可以返回一个包含了一个来自源WCS复制品的对象,并且更新可以剪切的那个二维数组对象。
from astropy.nddata import Cutout2D
size = 400
cutout = Cutout2D(data, center, size, wcs = wcs)
print(cutout.bbox_original)
输出结果:
((276, 675), (334, 733))
fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], projection = cutout.wcs)
#ax = plt.subplot(projection = wcs)
ax.set_xlabel('RA')
ax.set_ylabel('Dec')
ax.imshow(cutout.data, cmap = 'gist_heat', origin = 'lower')
ra = ax.coords[0]
ra.set_major_formatter('hh:mm:ss')
dec = ax.coords[1]
dec.set_major_formatter('dd:mm:ss')
结果如下:
保存一个新的FITS文件
为了保存一个新的FITS文件,我们需要创造一个头,然后创造扩展。最后打包所有的扩展到一个表里,然后将表写进文件。
# 制作一个初级头数据单元(header data unit, hdu)(一定要求)
primaryhdu = fits.PrimaryHDU(arr1) # 制作一个头
# 或者如果你有一个创造好的头
primaryhdu = fits.PrimaryHDU(arr1, header = head1)
# 如果你有其他的扩展
secondhdu = fits.ImageHDU(arr2)
# 制作一个新的HDU列表
hdulist1 = fits.HDUList([primaryHDU, secondhdu])
# 写入文件
hdulist1.writeto(filename, clobber = True)
这个clobber = True表明可以覆盖已有的文件,否则Python拒绝覆盖
cheader = cutout.wcs.to_header()
primaryhdu = fits.PrimaryHDU(cutout.data, cheader)
hdulist = fits.HDUList([primaryhdu])
hdulist.writeto('horse.fits', overwrite = True)
astropy中的表
当你在用FITS交互工具打开表时,astropy让这个过程很简单和方便。对于表的更多内容的帮助,你可以看这个页面
from astropy.table import Table
# 得到前一个表
t1 = Table.read(filename.fits)
# 得到第二个表
t2 = Table.read(filename.fits, hdu = 2)
这提供了一个很有灵活性的表来处理。它很方便的就可以访问不同类型的元素,并且读取和输出都有很广泛的格式,比如不一定就是FITS格式。让我们用前一个文件来打开它的扩展1吧。
hdulist = fits.open(image_file)
hdulist.info()
运行结果如下:
一次导入,一个表就能够在一个有趣的notebook中交互了。
from astropy.table import Table
t = Table.read(image_file, hdu = 1)
t[:10].show_in_notebook()
输出结果如下: