"""
Overview
--------
This modules provides the implementation of the :class:`.SourceCluster2Dim`, an high level class to handle source clusters objects.
Summary
---------
.. autosummary::
SourceCluster2Dim
Module API
-----------
"""
from __future__ import division, absolute_import
from asterism.core.clustering.cluster_tools import *
from asterism.core.coordinates.geometry_representation import Representation2D
[docs]class SourceCluster2Dim(object):
'''
SourceCluster2Dim implements an high level class to handle source clusters objects.
'''
def __init__(self,ID,geom_repr_cartesian,geom_repr_polar=None,pts_weigth=None,metric='euclidean',parent_ID=None):
"""
Parameters
----------
ID : int
ID of the object
geom_repr_cartesian : `.Representation2D` ,
object storing the cartesian coordinates of each point/pixel in the source cluster
geom_repr_polar : Optional[`.Representation2D`]
object storing the polar coordinates of each point/pixel in the source cluster
pts_weigth : Optional[1dim numpy array]
array storing flux/weight for each point/pixel in the source clusters. The number of
elements in this array must be equal to the number of rows in `geom_repr_cartesian`
and `geom_repr_polar`
metric : Optional[str]
the metric used to comput distances
"""
self.ID=ID
self.parent_ID=parent_ID
self._check_representation_type(geom_repr_cartesian,Representation2D,'cartesian')
self._geom_repr_cartesian=geom_repr_cartesian
self._metric=metric
self._type=Representation2D
if geom_repr_polar is not None:
self._check_representation_type(geom_repr_polar,Representation2D,'polar')
self._geom_repr_polar=geom_repr_polar
self._pts_weight=pts_weigth
self._update()
def _update(self):
"""
updates member of the class
Returns
-------
"""
self.set_cluster_bary(self._geom_repr_cartesian,self._pts_weight)
self._geom_repr_cartesian.rotation_center=(self.x_c,self.y_c)
self.set_cluster_peak()
if self._geom_repr_polar is not None:
self._add_polar_coords()
if self._pts_weight is not None:
self.integ_weigh=self._pts_weight.sum()
self.cl_len=self._geom_repr_cartesian.shape[0]
if self._pts_weight is not None:
peak_id=np.argmax(self.flux)
self.peak_flux_x_c=self.cartesian.x[peak_id]
self.peak_flux_y_c=self.cartesian.y[peak_id]
#self._eval_significance(bkg=self._bkg_level)
self.add_contour_points()
@property
def flux(self):
"""
public getter for private member `_pts_weight`
Returns
-------
"""
return self._pts_weight
@property
def n_points(self):
"""
getter for the number of points/pixels in the cluster
Returns
-------
"""
return self.cartesian.x.size
@property
def cartesian(self):
"""
public getter for the private member `_geom_repr_cartesian`, instance of the :class:`.Representation2D`
Returns
-------
"""
return self._geom_repr_cartesian
@property
def polar(self):
"""
public getter for the private member `_geom_repr_polar`, instance of the :class:`.Representation2D`
Returns
-------
"""
return self._geom_repr_polar
@property
def pts_weight(self):
"""
public getter for private member `_pts_weight`
Returns
-------
"""
return self._pts_weight
[docs] def add_contour_points(self):
"""
Method ot add contour points to the source clusters. This method is using the algorithm in the function :py:func:`.cluster_border`
Returns
-------
"""
if self.cartesian.x.size>1:
self.contour_shape= cluster_border(self.cartesian.x, self.cartesian.y)
else:
self.contour_shape=None
[docs] def merge_with(self,cl):
"""
Method to merge the current cluster with another
Parameters
----------
cl
Returns
-------
"""
new_coords=cl.cartesian.coords
self.cartesian._expand(new_coords)
if self.polar is not None:
new_coords=cl.polar.coords
self.polar._expand(new_coords)
if cl._pts_weight is not None:
self._pts_weight=np.append(self._pts_weight,cl._pts_weight)
self._update()
[docs] def check_is_in_cluster(self,x_test,y_test):
"""
Method to check if a position given by coords (x_test,y_test) is within the source cluster boundary. This methods uses the :py:func:`.check_is_in_cluster`
Parameters
----------
x_test : float
y_test : float
Returns
-------
Boolean True or False
"""
return check_is_in_cluster(x_test,y_test,self.cartesian.x,self.cartesian.y)
[docs] def check_is_within_r_from_center(self,R,x_test,y_test):
"""
Method to check if a position given by coords (x_test,y_test) is within a circle with radius `R` and centered on
the cluster centroid. This methods uses the :py:func:`.check_is_within_r_from_center`
Parameters
----------
R
x_test
y_test
Returns
-------
"""
return check_is_within_r_from_center(self.x_c,self.y_c,R,x_test,y_test,metric=self._metric)
[docs] def get_closest_cluster(self,clusters_list):
return get_closest_cluster(self,clusters_list)
[docs] def get_clusters_within_centroid(self,clusters_list,centre=None,R=None):
if centre is None:
centre=[self.x_c,self.y_c]
if R is None:
R=self.r_cluster
return get_clusters_within_circle(clusters_list,R=R,centre=centre)
[docs] def filter(self,image_filter):
"""
This method is used to apply an image filter :class:`asterism.core.image_processing.filters.ImageFilter` to the cluster. The method
first builds an intermediate image array using the :meth:`.get_cluster_image_array`. Then, it applies the image filter
to this intermediate image array. Finally, it reassigns the cluster `_pts_weight` from the filtered image, by getting the filtered
image values at the same coordinate of the cluster points
Parameters
----------
image_filter : :class:`asterism.core.image_processing.filters.ImageFilter`
filter to apply to the cluster image
Returns
-------
"""
image,off_x,off_y,masked=self.get_cluster_image_array(border=1,bkg=self.flux.min())
image=image_filter.apply(image)
for ID,coords in enumerate(self.cartesian.coords):
self._pts_weight[ID]=image[coords[1]-off_y,coords[0]-off_x]
self._update()
[docs] def get_cluster_image_array(self,border=1,bkg=None):
"""
Method to get the image array from the cluster. This method is using the function :py:func:`get_cluster_image_array`
Parameters
----------
border : int
number of pixels to add to the box enclosing the cluster, and used to build the image
bkg : Optional[float]
value to give to the background
Returns
-------
image : 2dim numpy array
off_set_x : float
the offset between the cluster x cartesian coordinates and the x pixel image coordinate
off_set_y : float
the offset between the cluster y cartesian coordinates and the y pixel image coordinate
masked_pixels : 2dim boolean numpy array
the masked pixels
"""
return get_cluster_image_array(self.cartesian.coords,border,pixel_values=self.flux,bkg=bkg)
[docs] def get_cluster_Image(self,border=1,bkg=None):
"""
Method to get a :class:'asterism.core.image_manager.image.Image' object from the cluster. This method is using the function :py:func:`asterism.core.clustering.cluster_tools.get_cluster_Image`
Parameters
----------
border : int
number of pixels to add to the box enclosing the cluster, and used to build the image
bkg : Optional[float]
value to give to the background
Returns
-------
image : :class:'asterism.core.image_manager.image.Image'
the output Image
off_set_x : float
the offset between the cluster x cartesian coordinates and the x pixel image coordinate
off_set_y : float
the offset between the cluster y cartesian coordinates and the y pixel image coordinate
masked_pixels : 2dim boolean numpy array
the masked pixels
"""
return get_cluster_Image(self.cartesian.coords,border,pixel_values=self.flux,bkg=bkg)
[docs] def set_cluster_bary(self,geom_repr,wehight=None):
self.x_c,\
self.y_c,\
self.sig_x,\
self.sig_y,\
self.r_cluster,\
self.semi_major_angle,\
self.pos_err,\
self.r_max ,\
self.r_mean=eval_cluster_bary(self.cartesian.coords,self._metric,weight=self.flux)
[docs] def set_cluster_peak(self):
id_peak=np.argmax(self.flux)
self.x_p=self.cartesian.x[id_peak]
self.y_p=self.cartesian.y[id_peak]
@classmethod
[docs] def build_from_evt_talbe(cls,ID,event_table,evt_list,parent_ID=None):
"""
Class method to build a source cluster from an :class:`asterism.core.tables.events_table.EventTable` object
Parameters
----------
ID : int
ID of the object
event_table : :class:`asterism.core.tables.events_table.EventTable`
evt_list : list of int
list of the IDs of the events selected from `event_table`
Returns
-------
source cluster : :class:`.SourceCluster2Dim`
"""
new_event_table=event_table.build_new_from_ids(evt_list)
if hasattr(event_table,'polar'):
geom_repr_polar=new_event_table.polar
else:
geom_repr_polar=None
return SourceCluster2Dim(ID, new_event_table.cartesian, geom_repr_polar, pts_weigth=event_table.flux.values[evt_list],parent_ID=parent_ID)
@classmethod
[docs] def build_from_cartesian_position_array(cls,ID,position_array,weight_array=None,parent_ID=None):
"""
Class method to build a source cluster from an 2dim numpy array, storing the coordinates of the cluster points
Parameters
----------
ID : int
ID of the object
position_array : 2dim numpy array
coordinates of the cluster points
weight_array : 1dim numpy array
weight or fluxes of each cluster point
Returns
-------
source cluster : :class:`.SourceCluster2Dim`
"""
if position_array.ndim==1:
position_array=position_array.reshape((1,position_array.size))
return SourceCluster2Dim(ID,Representation2D('cartesian',twodim_matrix_coord=position_array),pts_weigth=weight_array,parent_ID=parent_ID)
def _add_polar_coords(self,center=None):
"""
Method to add polar coords
Parameters
----------
center : Optional[(x,y) tuple of two values]
if not provided, the
Returns
-------
"""
if center is None:
self._geom_repr_polar=self._geom_repr_cartesian.to_polar()
else:
self._geom_repr_polar=self._geom_repr_cartesian.to_polar(x_c=center[0],y_c=center[1])
def _check_representation_type(self,type_to_test,target_type,expected_repr_type):
"""
Parameters
----------
type_to_test
target_type
expected_repr_type
Returns
-------
"""
if isinstance(type_to_test,target_type):
pass
else:
raise TypeError("%s is not of expected type %s"%(type(type_to_test),type(target_type)))
if type_to_test.representation_type!=expected_repr_type:
raise ValueError("the representation is %s, but is expected to be %s "%(type_to_test.representation_type,expected_repr_type))