"""Tools to compare two catalog of sources
"""
import numpy as np
import matplotlib.pyplot as plt
import astropy.table as att
[docs]class CompareSrcCatWithECLAIRsCat(object):
"""Compare a sources catalog from IMAG to a simple ECLAIRs catalog used by simulation
"""
def __init__(self, src_cat, ref_cat):
"""**constructor**
:param src_cat: catalog of found x-ray sources by IMAG
:type src_cat: Catalog_Identified_sources
:param ref_cat: reference catalog to compare to
:type ref_cat: CatalogFOV_ECLAIRs
"""
self.src_cat = src_cat
self.ref_cat = ref_cat
[docs] def more_likely_sources_id_pix(self):
"""find the name of the found source based on the ref catalog
the new name is save in the 'name' column of the catalog of the found source
for each found source:
- find the closest x-ray source in the ref catalog
- if the distance is < 2 pix: the name of the found source is set to the
name of the closest source in the ref catalog
"""
self.new_source_flag = 0
for source in self.src_cat.get_catalog():
distance_to_source = np.sqrt(
(self.ref_cat.get_catalog_sky_pix()['sky_y'] - source['Y_fit']) ** 2 +
(self.ref_cat.get_catalog_sky_pix()['sky_z'] - source['Z_fit']) ** 2
)
if np.min(distance_to_source) < 2:
source['name'] = self.ref_cat._catalog['name'][np.argmin(distance_to_source)]
source['dist_src'] = np.min(distance_to_source)
else:
self.new_source_flag = 1
[docs] def all_sources_scatter_plot(self, annotation=False, show=True, save=None): # pragma: no cover
"""plot all sources from both catalogs on the sky in pixels
:param annotation: add the name of the source close to its location
:param show: show the plot
:param save: PATH/name of the file to save the fig. If None, no saving.
:type annotation: bool (default=False)
:type show: bool (default=True)
:type save: string (default=None)
"""
_, ax = plt.subplots()
ax.scatter(
self.ref_cat.get_catalog_sky_pix()['sky_y'],
self.ref_cat.get_catalog_sky_pix()['sky_z'],
s=30,
marker='+',
label='reference catalog')
if annotation == True:
for row in self.ref_cat.get_catalog_sky_pix():
ax.annotate(row['name'], (row['sky_y'], row['sky_z']))
ax.scatter(
self.src_cat._catalog['Y_fit'],
self.src_cat._catalog['Z_fit'],
s=50,
alpha=0.5,
label='identified sources')
if annotation == True:
for row in self.src_cat._catalog:
ax.annotate(row['name'], (row['Y_fit'], row['Z_fit']))
ax.set_xlabel('pixel in Y')
ax.set_ylabel('pixel in Z')
ax.set_title(f"{self.src_cat.get_nb_element()} found sources")
ax.axis([-100, 100, -100, 100])
ax.legend()
plt.grid()
if save:
plt.savefig(save)
if not show:
plt.close()
if show:
plt.show()
plt.close()
[docs] def identified_sources_scatter_plot(self, annotation=True, show=True, save=None): # pragma: no cover
"""plot, from both catalogs, only the sources that has been identified.
:param annotation: add the name of the source close to its location
:param show: show the plot
:param save: PATH/name of the file to save the fig. If None, no saving.
:type annotation: bool (default=True)
:type show: bool (default=True)
:type save: string (default=None)
"""
_, ax = plt.subplots()
common_sources = att.join(self.ref_cat.get_catalog_sky_pix(),
self.src_cat._catalog, keys='name')
ax.scatter(
common_sources['sky_y'],
common_sources['sky_z'],
s=30,
marker='+',
label='reference catalog')
ax.scatter(
common_sources['Y_fit'],
common_sources['Z_fit'],
s=50,
alpha=0.5,
label='identified sources')
if annotation == True:
for row in common_sources:
ax.annotate(row['name'], (row['sky_y'], row['sky_z']))
ax.annotate(row['name'], (row['Y_fit'], row['Z_fit']))
ax.set_xlabel('pixel in Y')
ax.set_ylabel('pixel in Z')
ax.set_title(f"{len(common_sources)} identified sources")
ax.axis('equal')
ax.legend()
plt.grid()
if save:
plt.savefig(save)
if not show:
plt.close()
if show:
plt.show()
[docs] def get_pix_position_diff_stats(self):
"""compute mean, median, stddev of the difference of the positions of the 2 cats
.. note:: only computed for identified sources
:return: mean(y), mean(z), median(y), median(z), std(y), std(z)
:rtype: float, float, float, float, float, float
"""
common_sources = att.join(self.ref_cat.get_catalog_sky_pix(),
self.src_cat._catalog, keys='name')
y_diff = common_sources['sky_y'] - common_sources['Y_fit']
z_diff = common_sources['sky_z'] - common_sources['Z_fit']
# casting to numpy arrays prevents a warning when computing the median.
y_diff = np.array(y_diff)
z_diff = np.array(z_diff)
return np.mean(y_diff), np.mean(z_diff), \
np.median(y_diff), np.median(z_diff), \
np.std(y_diff), np.std(z_diff)