Source code for asterism.core.clustering.source_cluster

"""
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))