如何将Gaia恒星测量数据绘制到TESS图像上

14
长话短说:我想在Python中将盖亚天文数据绘制到TESS图像上。这有可能吗?详细情况见下文。
我有一张64x64像素的TESS星图,上面有一颗带有Gaia ID 4687500098271761792的星。根据TESS天文台指南第8页,1个像素约为21角秒。使用Gaia Archive,在“顶部特征”下方点击“搜索”,并提交一个查询以查看1000角秒内的恒星,这大致是我们需要的半径。我用Gaia DR2 4687500098271761792作为搜索名称,如下所示:

enter image description here

提交查询后,我会得到一个包含500颗恒星的列表,其中包括RADEC坐标。选择CSV并点击下载结果,我将获得围绕着4687500098271761792的恒星列表。这个结果文件也可以在这里找到。这是我们想要使用的Gaia输入。

从TESS中,我们有4687500098271761792_med.fits,一张图像文件。我们使用以下命令进行绘制:

from astropy.io import fits
from astropy.wcs import WCS
import matplotlib.pyplot as plt
hdul = fits.open("4687500098271761792_med.fits")[0]
wcs = WCS(hdul.header)
fig = plt.figure(figsize=(12,12))
fig.add_subplot(111, projection=wcs)
plt.imshow(hdul.data)

并获得一张漂亮的图片:

enter image description here

而且有很多警告,其中大部分在这里得到了友好的解释在问题中的警告,在评论中的解释
请注意,确实很好我们使用了WCS投影。为了检查,让我们只是绘制hdul.data中的数据,而不关心投影:
plt.imshow(hdul.data)

结果:

enter image description here

几乎与之前相同,但现在轴的标签只是像素编号,而不是RA和DEC,这是最好的选择。第一个图中的DECRA值分别约为-72°和16°,这很好,因为Gaia目录给出了大约具有这些坐标的4687500098271761792附近的星星。因此,投影似乎还可以。现在让我们尝试在imshow()图上绘制Gaia星星。我们从先前下载的CSV文件中读取并提取对象的RADEC值:
import pandas as pd
df=pd.read_csv("4687500098271761792_within_1000arcsec.csv")
ralist=df['ra'].tolist()
declist=df['dec'].tolist()

需要检查的图表:

plt.scatter(ralist,declist,marker='+')

enter image description here

形状不是预期的圆形,这可能是未来麻烦的指标。

让我们尝试将这些RADEC值转换为WCS,并以此方式绘制它们:

for index, each in enumerate(ralist):
    ra, dec = wcs.all_world2pix([each], [declist[index]], 1)
    plt.scatter(ra, dec, marker='+', c='k')

结果是:{{result}}。

enter image description here

函数all_world2pix来自这里。参数1仅设置原点位置。对all_world2pix的描述如下:

在此处,原点是图像左上角的坐标。 在FITS和Fortran标准中,这是1。在Numpy和C标准中,这是0。

然而,我们得到的点分布形状并不理想。让我们将TESS和Gaia数据组合起来:
hdul = fits.open("4687500098271761792_med.fits")[0]
wcs = WCS(hdul.header)
fig = plt.figure(figsize=(12,12))
fig.add_subplot(111, projection=wcs)
plt.imshow(hdul.data)
for index, each in enumerate(ralist):
    ra, dec = wcs.all_world2pix([each], [declist[index]], 1)
    plt.scatter(ra, dec, marker='+', c='k')

我们得到:

enter image description here

这远远不是理想状态。我希望在一个有许多标记的imshow()图片上有一个基础图像,并且标记应该在TESS图像上的星星位置。我使用的Jupyter笔记本可以在这里找到。
我错过了哪些步骤,或者我做错了什么?
进一步发展回应另一个问题时,keflavich友好地建议使用transform参数进行世界坐标绘图。尝试了一些示例点(下图中弯曲的十字形)。还在不处理数据的情况下将Gaia数据绘制在图上,它们最终集中在一个非常狭窄的空间。对它们应用了transform方法,获得了一个看似非常相似的结果。代码(也可在这里找到):
import pandas as pd
df=pd.read_csv("4687500098271761792_within_1000arcsec.csv")
ralist=df['ra'].tolist()
declist=df['dec'].tolist()

from astropy.io import fits
from astropy.wcs import WCS
import matplotlib.pyplot as plt

hdul = fits.open("4687500098271761792_med.fits")[0]
wcs = WCS(hdul.header)

fig = plt.figure(figsize=(12,12))
fig.add_subplot(111, projection=wcs)
plt.imshow(hdul.data)

ax = fig.gca()
ax.scatter([16], [-72], transform=ax.get_transform('world'))
ax.scatter([16], [-72.2], transform=ax.get_transform('world'))
ax.scatter([16], [-72.4], transform=ax.get_transform('world'))
ax.scatter([16], [-72.6], transform=ax.get_transform('world'))
ax.scatter([16], [-72.8], transform=ax.get_transform('world'))
ax.scatter([16], [-73], transform=ax.get_transform('world'))


ax.scatter([15], [-72.5], transform=ax.get_transform('world'))
ax.scatter([15.4], [-72.5], transform=ax.get_transform('world'))
ax.scatter([15.8], [-72.5], transform=ax.get_transform('world'))
ax.scatter([16.2], [-72.5], transform=ax.get_transform('world'))
ax.scatter([16.6], [-72.5], transform=ax.get_transform('world'))
ax.scatter([17], [-72.5], transform=ax.get_transform('world'))

for index, each in enumerate(ralist):
    ax.scatter([each], [declist[index]], transform=ax.get_transform('world'),c='k',marker='+')

for index, each in enumerate(ralist):
    ax.scatter([each], [declist[index]],c='b',marker='+')

并生成相应的图表:

enter image description here

这种弯曲的十字形是预料之中的,因为TESS与恒定的纬度和经度线不对齐(即十字架的臂不必与TESS图像的边平行,用imshow()绘制)。现在让我们尝试绘制恒定的RA和DEC线(或者说,恒定的纬度和经度线),以更好地理解为什么来自Gaia的数据点错位。通过添加几行代码扩展上面的代码:

ax.coords.grid(True, color='green', ls='solid')

overlay = ax.get_coords_overlay('icrs')
overlay.grid(color='red', ls='dotted')

结果令人鼓舞:

enter image description here

(请在此处查看笔记本here。)


world2pix将世界坐标(RA,Dec)转换为像素坐标(x,y)。您的变量“ra”和“dec”实际上包含x,y坐标。 - keflavich
是的,这看起来很合理,但在实践中结果甚至更糟: https://github.com/zabop/GaiaToTESS/blob/master/UseGaiaAsIs.ipynb - zabop
2个回答

9

首先,我必须说,这是一个很好的问题!非常详细和可重复。我阅读了您的问题,并尝试从您的git repo开始重新执行练习,并从GAIA档案中下载目录。

编辑

从程序上来说,您的代码没问题(请参见下面的旧部分以获取稍微不同的方法)。缺失点的问题在于,从GAIA档案下载csv文件时只能获得500个数据点。因此,似乎所有查询点都被塞进了一个奇怪的形状中。但是,如果将搜索半径限制在较小的值范围内,就可以看到存在位于TESS图像内的点:

enter image description here

请与下面的旧版本进行比较。代码与下面相同,只是下载的csv文件半径较小。因此,当导出到csv时,似乎您只下载了GAIA存档中所有可用数据的一部分。解决这个问题的方法是像您所做的那样进行搜索。然后,在结果页面上单击底部的在ADQL表单中显示查询,在以SQL格式显示的查询中更改:

Select Top 500

Select

在查询开始时。

旧部分(代码可以正常工作,但我的结论是错误的):

为了绘制图表,我使用了aplpy - 它在后台使用matplotlib - 最终得到了以下代码:

from astropy.io import fits
from astropy.wcs import WCS
import aplpy
import matplotlib.pyplot as plt
import pandas as pd
from astropy.coordinates import SkyCoord
import astropy.units as u
from astropy.io import fits 


fits_file = fits.open("4687500098271761792_med.fits")
central_coordinate = SkyCoord(fits_file[0].header["CRVAL1"],
                              fits_file[0].header["CRVAL2"], unit="deg")

figure = plt.figure(figsize=(10, 10))
fig = aplpy.FITSFigure("4687500098271761792_med.fits", figure=figure)
cmap = "gist_heat"
stretch = "log"

fig.show_colorscale(cmap=cmap, stretch=stretch)
fig.show_colorbar()

df = pd.read_csv("4687500098271761792_within_1000arcsec.csv")    

# the epoch found in the dataset is J2015.5
df['coord'] = SkyCoord(df["ra"], df["dec"], unit="deg", frame="icrs",
                       equinox="J2015.5")
coords = df["coord"].tolist()
coords_degrees = [[coord.ra.degree, coord.dec.value] for coord in df["coord"]]
ra_values = [coord[0] for coord in coords_degrees]
dec_values = [coord[1] for coord in coords_degrees]

width = (40*u.arcmin).to(u.degree).value
height = (40*u.arcmin).to(u.degree).value
fig.recenter(x=central_coordinate.ra.degree, y=central_coordinate.dec.degree, 
             width=width, height=height)
fig.show_markers(central_coordinate.ra.degree,central_coordinate.dec.degree, 
                 marker="o", c="white", s=15, lw=1)
fig.show_markers(ra_values, dec_values, marker="o", c="blue", s=15, lw=1)
fig.show_circles(central_coordinate.ra.degree,central_coordinate.dec.degree, 
                 radius=(1000*u.arcsec).to(u.degree).value, edgecolor="black")
fig.save("GAIA_TESS_test.png")

然而,这将导致一个类似于您的绘图的结果:

enter image description here

为了确认GAIA存档中的坐标是否正确显示,我从TESS图像的中心画了一个1000弧秒的圆。如您所见,它与GAIA位置数据点云的外部(从图像中心看)圆形形状大致对齐。我认为这些都是在您搜索的区域内的GAIA DR2存档中的所有点。数据云甚至在内部似乎有一个方形边界,这可能来自于一个方形视场。

2
非常好的例子。只是要提到,您还可以使用astropy中包含的astroquery.gaia模块将查询集成到Gaia存档中。这样,您将能够运行与Gaia存档UI内部相同的查询,并更轻松地切换不同的来源。最初的回答:

非常不错的示例。只是要提到,您还可以使用astropy中包含的astroquery.gaia模块将查询集成到Gaia存档中。

https://astroquery.readthedocs.io/en/latest/gaia/gaia.html

这样,您将能够运行与Gaia存档UI内部相同的查询,并更轻松地切换不同的来源。

from astroquery.simbad import Simbad
import astropy.units as u
from astropy.coordinates import SkyCoord
from astroquery.gaia import Gaia

result_table = Simbad.query_object("Gaia DR2 4687500098271761792")
raValue = result_table['RA']
decValue = result_table['DEC']

coord = SkyCoord(ra=raValue, dec=decValue, unit=(u.hour, u.degree), frame='icrs')

query = """SELECT TOP 1000 * FROM gaiadr2.gaia_source 
           WHERE CONTAINS(POINT('ICRS',gaiadr2.gaia_source.ra,gaiadr2.gaia_source.dec), 
           CIRCLE('ICRS',{ra},{dec},0.2777777777777778))=1 ORDER BY random_index""".format(ra=str(coord.ra.deg[0]),dec=str(coord.dec.deg[0]))


job = Gaia.launch_job_async(query)  
r = job.get_results()

ralist = r['ra'].tolist()
declist = r['dec'].tolist()

import matplotlib.pyplot as plt
plt.scatter(ralist,declist,marker='+')
plt.show()

按随机索引排序的前1000行

请注意,我已经添加了按随机索引排序的功能,这将消除这种奇怪的非循环行为。这个索引非常有用,可以不强制在初始测试中输出全部结果。

此外,我已经声明了来自Simbad的赤经坐标输出为小时。

最后,我使用了异步查询,它在执行时间和响应中的最大行数方面具有更少的限制。

您也可以更改查询为

query = """SELECT * FROM gaiadr2.gaia_source 
               WHERE CONTAINS(POINT('ICRS',gaiadr2.gaia_source.ra,gaiadr2.gaia_source.dec), 
               CIRCLE('ICRS',{ra},{dec},0.2777777777777778))=1""".format(ra=str(coord.ra.deg[0]),dec=str(coord.dec.deg[0]))

(去除1000行的限制)在这种情况下,不需要使用随机索引就可以从服务器获得完整的响应。

当然,这个查询需要一些时间来执行(大约1.5分钟)。完整的查询将返回103574行。

所有来源。103574行


注:Original Answer翻译成“最初的回答”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接