The search for NNs at its end: splitting the roles

We tried and tested the NN-xmatch workflow in past notebooks, first to build the workflow itself, xNN_mock_sources_v1, and then on developing better the algorithm and even testing the ipyparallel engine, xNN_mock_sources_v2-try_parallel.

Now, all we want is to the functions in proper namespaces and test so that we can add it to booq.

TOC:


In [1]:
%matplotlib inline

from matplotlib import pyplot as plt
from matplotlib import cm

import numpy

plt.rcParams['figure.figsize'] = (10.0, 10.0)

Simulation of source catalogs


In [2]:
# first of all, let us define some parameters
#
# size of the images
sx = 5000
sy = 5000

# number of sources on each image
nsrc1 = int( 0.1 * (sx*sy)/(sx+sy) )

#nsrc2 = int( 0.5 * nsrc1 )

# typical error radius (in pixels)
rerr1 = 20
rerr2 = rerr1

In [3]:
class Mock:
    """
    namespace for mock catalogs generation
    """
    @staticmethod
    def generate_positions_2D(npts,img_shape):
        """
        Generates 'npts' points uniformly across 'image_shape'.

        Args:
            npts      : number of points to generate
            img_shape : (y,x) shape where to generate points

        Output:
         - list of (y,x) tuples, position of generated points
        """
        import numpy as np
        _sy,_sx = img_shape
        assert _sy>=5 and _sx>=5 # because I want
        indy = np.random.randint(0,_sy-1,npts)
        indx = np.random.randint(0,_sx-1,npts)
        _inds = zip(indy,indx)
        return _inds


    @staticmethod
    def generate_positions_2D_around(seeds,radius,img_shape,fraction=1.0):
        """
        Generates points around given seeds with a 'fraction' probability
        
        Input:
         - list of (y,x) tuples : [(int,int),...]
                 position of seed/reference points
         - radius : int
                 position is generated using a normal distribution,
                 'radius' is used as the 1-sigma value of the probability function
         - img_shape : (int,int)
                 (y,x) shape where points can be generated
         
        Output:
         - list of (y,x) tuples, position of generated points
        """
        assert 0 < fraction <= 1.0, "ValueError: 'fraction' should be somewhere between [0:1]."

        def _gen_pos_around_individual(seed,radius,img_shape,fraction,distribution='normal'):
            """
            TODO: implement other kinds of distributions
            """
            from random import random
            if random() < fraction:
                import numpy as np
                sy,sx = seed
                y = int(np.random.normal(sy,radius))
                x = int(np.random.normal(sx,radius))
                y = y if y > 0 and y < img_shape[0] else sy
                x = x if x > 0 and x < img_shape[1] else sx
            else:
                y,x = Mock.generate_positions_2D(1,img_shape)[0]
            return y,x

        _inds = []
        for i,seed in enumerate(seeds):
            y,x = _gen_pos_around_individual(seed,radius,img_shape,fraction)
            _inds.append((y,x))
        return _inds

    @staticmethod
    def generate_catalog_2D(number_sources, radius, img_shape):
        """
        """
        import pandas
        import numpy

        sy,sx = img_shape
        rerr = radius
        coords = Mock.generate_positions_2D(number_sources,(sy,sx))
        
        y,x = zip(*coords)
        df = pandas.DataFrame({ 'x':x, 'y':y, 'r':[rerr]*len(coords),
                                'ID':numpy.arange(1,len(coords)+1)})
        return df

    @staticmethod
    def generate_catalog_2D_around(reference_catalog, fraction_neighbors, img_shape):
        """
        """
        import pandas
        import numpy

        sy,sx = img_shape
        rerr = reference_catalog.r[0]
        ref_coords = reference_catalog[['y','x']].values
        fraction = fraction_neighbors
        coords = Mock.generate_positions_2D_around(ref_coords, rerr, (sy,sx), fraction)

        y,x = zip(*coords)
        df = pandas.DataFrame({ 'x':x, 'y':y, 'r':[rerr]*len(coords),
                                'ID':numpy.arange(1,len(coords)+1)})
        return df

class Coordinates:
    
    @staticmethod
    def pixel_to_sky(px, origin_in_sky, pixel_scale):
        """
        Returns the 'sky' values
        
        Pixel values are always 0 <= 'x'.
        The origin defines where 'x'=0 resides in sky (ra).
        The pixel scale is the shifting factor.
        So far, the convertion is a simple, linear function.
        
        Input:
         - px : ~numpy.ndarray
             Image (pixel) coordinates
         - origin_in_sky : float
             RA/Dec value of pixel x=0 (origin)
         - pixel_scale : float
             Pixel resolution, in 'degree/pixel'
             
        Output:
         - sky : ~numpy.ndarray
             Sky coordinates
        """
        sky = (px * float(pixel_scale)) - origin_in_sky
        return sky

    
def normalize_coordinates(A,B,norm_factor):
    """
    """
    def _normalize_coordinates(x, y, norm_fact):
        from astropy.coordinates import SkyCoord
        from astropy import units
        x_norm = x / norm_fact
        y_norm = y / norm_fact
        coord = SkyCoord(ra=x_norm, dec=y_norm, unit=units.deg)
        return coord

    A_coord = _normalize_coordinates(A.x,A.y,norm_factor)
    B_coord = _normalize_coordinates(B.x,B.y,norm_factor)
    return A_coord,B_coord

In [4]:
# # "sources 1"
# coords1 = Mock.generate_positions_2D(nsrc1,(sy,sx))
# # "sources 2"
# coords2 = Mock.generate_positions_2D_around(coords1, rerr1, (sy,sx), fraction=0.75)

# import pandas
# import numpy

# y,x = zip(*coords1)
# df1 = pandas.DataFrame({'x':x, 'y':y, 'r':[rerr1]*len(coords1), 'ID':numpy.arange(1,len(coords1)+1)})

# y,x = zip(*coords2)
# df2 = pandas.DataFrame({'x':x, 'y':y, 'r':[rerr2]*len(coords2), 'ID':numpy.arange(1,len(coords2)+1)})

df1 = Mock.generate_catalog_2D(nsrc1,rerr1,(sy,sx))
df2 = Mock.generate_catalog_2D_around(df1, 0.75, (sy,sx))

In [5]:
class Image:
    """
    namespace for all image-related functions
    """
    
    # create and draw each source on black(null) images
    @staticmethod
    def draw_image_sources(df,img_shape,colormap='colorful'):
        """
        """
        assert len(img_shape)==2
        assert 'x' in df.columns
        assert 'y' in df.columns
        assert 'r' in df.columns
        
        def color_filling(mode='colorful'):
            def _colorful(x,y,size):
                _R = int(255 - ( int(x/256) + int(y/256)*(1 + ceil(size[0]/256)) )) #TODO: restrict total size of image to avoid _R<=0
                _G = x%256
                _B = y%256
                return (_R,_G,_B)

            def _blue(x,y,size):
                _R = 0
                _G = 0
                _B = 255
                return (_R,_G,_B)

            def _green(x,y,size):
                _R = 0
                _G = 255
                _B = 0
                return (_R,_G,_B)

            def _red(x,y,size):
                _R = 255
                _G = 0
                _B = 0
                return (_R,_G,_B)

            foos = {'blue'    : _blue,
                    'red'     : _red,
                    'green'   : _green,
                    'colorful': _colorful}

            try:
                foo = foos[mode]
            except:
                foo = _colorful
            return foo


        from math import ceil
        from PIL import Image,ImageDraw
        
        size = img_shape[::-1]

        # Modification to accomplish color codes ---
        #mode = 'L'
        mode = 'RGB'
        # ---
        color = "black"
        img = Image.new(mode,size,color)
        #
        filling_foo = color_filling(colormap)
        #
        
        dictColorId = {}
        for i,src in df.iterrows():
            draw = ImageDraw.Draw(img)
            x = src.x
            y = src.y
            r = src.r
            fill = filling_foo(x,y,size)
            
            box = (x-r,y-r,x+r,y+r)
            draw.ellipse(box,fill=fill)
            
            dictColorId[str(fill)] = i
            del draw,box,x,y,r
            
        return img,dictColorId

    @staticmethod
    def pil_2_array(img):
        import numpy
        #img_array = numpy.array(list(img.getdata())).reshape(sx,sy,3)
        img_array = numpy.asarray(img)
        return img_array

    @staticmethod
    def array_2_pil(arr):
        from PIL import Image
        imgout = Image.fromarray(numpy.uint8(arr))
        return imgout

    @staticmethod
    def rgb_2_mono(img_arr,chanel='R'):
        chanels = {'R':0,
                   'G':1,
                   'B':2}
        _i = chanels[chanel]
        return img_arr[:,:,_i]

In [6]:
img1,cor2id1 = Image.draw_image_sources(df1,(sy,sx),colormap='blue')
img2,cor2id2 = Image.draw_image_sources(df2,(sy,sx),colormap='red')
# img1.show()
# img2.show()

In [7]:
# cmap reference:
#
# cm api: http://matplotlib.org/api/cm_api.html
# cmaps : http://matplotlib.org/users/colormaps.html
# imshow: http://matplotlib.org/users/image_tutorial.html
#cmap = cm.get_cmap('Blues')

Result of the simulation for the first image


In [8]:
img1_array = Image.pil_2_array(img1)

plt.imshow( Image.rgb_2_mono(img1_array,'B'), cmap='Blues')

print "Catalog A:"
print "----------"
print df1


Catalog A:
----------
      ID   r     x     y
0      1  20  4028  4992
1      2  20   613  1219
2      3  20  4363  4005
3      4  20  2975  4188
4      5  20  3422  4398
5      6  20  4327  2386
6      7  20  2030  1839
7      8  20  4811  1064
8      9  20  4117  3877
9     10  20  2541  4473
10    11  20  1227   153
11    12  20  4980  1336
12    13  20  1434  4163
13    14  20   677  3891
14    15  20  3621  3925
15    16  20  2806  1549
16    17  20  1678  1692
17    18  20   918  2382
18    19  20  4207  4567
19    20  20  1187   913
20    21  20  4340  4465
21    22  20  4490  4726
22    23  20   550   111
23    24  20  2167  4818
24    25  20  1920   997
25    26  20  3121   885
26    27  20   796  2474
27    28  20   528  2417
28    29  20  3587  1844
29    30  20   753  2369
..   ...  ..   ...   ...
220  221  20  3790  1941
221  222  20  2164  3126
222  223  20  2818  3112
223  224  20  3720  2582
224  225  20  1852  1040
225  226  20  3214  1984
226  227  20  2714  4872
227  228  20  1712  1846
228  229  20  4985  1241
229  230  20  4899  4812
230  231  20  3669  4263
231  232  20  4613  2170
232  233  20  1367   123
233  234  20  3667  1840
234  235  20  1230  2024
235  236  20  1271  4053
236  237  20   855  3291
237  238  20  1316  2790
238  239  20  4185  1490
239  240  20   207  2882
240  241  20  3368  1636
241  242  20  1586  1469
242  243  20  4506  3780
243  244  20  1892  4879
244  245  20  2652  3054
245  246  20  1702  4471
246  247  20   757  4387
247  248  20  1641  2213
248  249  20   797  3367
249  250  20  3704  1168

[250 rows x 4 columns]

Result of the simulation for the second image


In [9]:
img2_array = Image.pil_2_array(img2)

plt.imshow( Image.rgb_2_mono(img2_array,'R'), cmap='Reds')

print "Catalog B:"
print "----------"
print df2


Catalog B:
----------
      ID   r     x     y
0      1  20  4044  4986
1      2  20   621  1245
2      3  20  4338  3996
3      4  20  2970  4175
4      5  20  3396  4386
5      6  20  4361  2373
6      7  20  2715  4472
7      8  20  4820  1064
8      9  20  4114  3884
9     10  20  4633  2130
10    11  20  1230   156
11    12  20  4984  1364
12    13  20  1430  4146
13    14  20   716  3888
14    15  20  3617  3936
15    16  20  2802  1566
16    17  20   259  1598
17    18  20   976  4954
18    19  20  2405   437
19    20  20  1155   905
20    21  20  4338  4474
21    22  20  4500  4727
22    23  20   540   109
23    24  20  1521  4620
24    25  20  1906   986
25    26  20  3130   909
26    27  20   810  2477
27    28  20  3035  1729
28    29  20  3548  1826
29    30  20   753  2369
..   ...  ..   ...   ...
220  221  20  3803  1933
221  222  20  2161  3126
222  223  20  2458  4425
223  224  20  3722  2553
224  225  20  1825  1026
225  226  20   992  2621
226  227  20  4868  1480
227  228  20  1737  1838
228  229  20  4929  1246
229  230  20  4891  4858
230  231  20  3668  4291
231  232  20  4612  2150
232  233  20  1371   134
233  234  20  3657  1841
234  235  20  1227  2024
235  236  20  1286  4025
236  237  20   863  3314
237  238  20  1356  2821
238  239  20  4177  1479
239  240  20   200  2866
240  241  20  3385  1652
241  242  20  1612  1449
242  243  20  3477   491
243  244  20  2914  3771
244  245  20  2870  1859
245  246  20  4326  3984
246  247  20   756  4367
247  248  20  1647  2232
248  249  20   808  3373
249  250  20  3710  1174

[250 rows x 4 columns]

Merge images


In [10]:
plt.imshow( Image.array_2_pil( img1_array+img2_array ) )


Out[10]:
<matplotlib.image.AxesImage at 0x7fcde0498c90>

Cross-matching


In [73]:
# ---
class IO:
    @staticmethod
    def read_catalog(filename, column_names=None, format='fits', sample_size=0):
        """
        """
        if format == 'fits':
            data = IO.read_fitsio(filename, column_names=column_names)

        if sample_size:
            data = Data.sample(data, fraction=sample_size)

        return data

    @staticmethod
    def read_fitsio(filename,column_names=None):
        """
        """
        import fitsio
        if column_names:
            catalog_data = fitsio.read(filename, columns=column_names, ext=1)
        else:
            catalog_data = fitsio.read(filename, ext=1)
        return catalog_data


# ---

class Data:
    @staticmethod
    def sample(data_array, fraction=0.1):
        """
        Returns a (normal) random sample from array' rows

        Input:
         - data_array : ~numpy.ndarray
                Array from where rows are randomly chosen
         - fraction : int, float
                Number between (0,array'length); limits are non-inclusive.
                If the number is higher (inclusive) than '1', it is assumed to be
                the absolute value for the sample size; otherwise, if between (0,1)
                it is assumed to be the relative, array-length multiplication factor.
        Output:
         - sampled_array : ~numpy.ndarray
                Rows are randomly chosen from a normal distribution, all same columns
        """
        import numpy
        nrows = len(data_array)

        assert fraction > 0, "ValueError: There is no sense in asking for 'fraction' <= 0"
        assert fraction < nrows, "ValueError: There is no sense in asking for 'fraction' >= array's length"

        nsamp = fraction if fraction >= 1 else fraction*nrows
        nsamp = int(nsamp)
        idx = numpy.random.randint(0, nrows, nsamp)
        sample_data = data_array[idx]

        return sample_data

# ---

class Xmatch:

    @staticmethod
    def xmatch_nn(A_coord, B_coord, parallel=False):
        """
        """
        if parallel:
            match_A_nn_idx, match_A_nn_sep = Xmatch.xmatch_nn_parallel(A_coord,B_coord)
        else:
            match_A_nn_idx, match_A_nn_sep = Xmatch.xmatch_nn_serial(A_coord,B_coord)
        return (match_A_nn_idx, match_A_nn_sep)

    @staticmethod
    def xmatch_nn_serial(pin, neiborhood):
        """
        Nearest-Neighbor search

        Input:
         - pin : ~astropy.coordinates.SkyCoord
                reference catalog (catalog "A")
         - neiborhood : ~astropy.coordinates.SkyCoord
                matching catalog (catalog "B")

        Output:
         - tuple with ~numpy.ndarray , ~astropy.units.Quantity
                array of respective (to 'pin') index entries in 'neiborhood'
                , array of respective pair distances
        """
        A_coord = pin
        B_coord = neiborhood

        from astropy.coordinates import SkyCoord
        assert isinstance(A_coord,SkyCoord)
        assert isinstance(B_coord,SkyCoord)

        from astropy.coordinates import match_coordinates_sky
        match_A_nn_idx, match_A_nn_sep, _d3d = match_coordinates_sky(A_coord,B_coord)

        assert len(match_A_nn_idx) == len(A_coord)
        assert match_A_nn_idx.max() < len(B_coord)

        return (match_A_nn_idx, match_A_nn_sep.value)


    @staticmethod
    def xmatch_nn_parallel(A_coord,B_coord,nprocs=2):
        """
        """

        def parallel_setup(nprocs=2):
            """
            Run xmatch in parallel

            It splits the first array in 'nprocs' for parallel processing,
            then it concatenates the outputs and return that.
            """
            #TODO: do all the verifications for parallel run

            # Lets us see what happens in parallel
            # First, run from the command line:
            #$ ipcluster start -n 2
            try:
                import ipyparallel as ipp
                client = ipp.Client()
                client.ids
                dview = client[:]
            except:
                dview = None
            return dview

        # ---

        dview = parallel_setup(nprocs=2)
        if not dview:
            print "Error: NOT able to run in parallel! See if 'ipcluster' is setup."
            return False

        print "Running in parallel"

        # Encapsulate some variables to send for processing
        def make_nn_search_parallel(foo,cat2):
            def pkg_nn_search(cat1,foo=foo,cat2=cat2):
                return foo(cat1,cat2)
            return pkg_nn_search
        # ---

        # Split array (of coordinates) in N pieces
        def split_array(A_coord,N):
            from numpy import arange,array_split
            index = arange(len(A_coord))
            A_pieces = [ A_coord[idx]   for idx in array_split( index,N ) ]
            return A_pieces

        # Join array/list of tuples in N pieces
        def join_array(A_coord_outs):
            from numpy import append
            match_A_nn_idx = None
            match_A_nn_sep = None
            for each_out in A_coord_outs:
                match_idx, match_sep = each_out
                if match_A_nn_idx is None:
                    assert match_A_nn_sep is None
                    match_A_nn_idx = match_idx
                    match_A_nn_sep = match_sep
                else:
                    match_A_nn_idx = append(match_A_nn_idx,match_idx)
                    match_A_nn_sep = append(match_A_nn_sep,match_sep)
            return (match_A_nn_idx,match_A_nn_sep)
        # ---

        # A-B
        # from astropy.coordinates import match_coordinates_sky
        foo_match_coordinates = make_nn_search_parallel(Xmatch.xmatch_nn_serial, B_coord)

        A_coord_pieces = split_array(A_coord,N=len(dview))

        A_coord_outs = dview.map_sync( foo_match_coordinates, A_coord_pieces )

        match_A_nn_idx,match_A_nn_sep = join_array(A_coord_outs)

        return (match_A_nn_idx,match_A_nn_sep)

# ---

def compile_coordinates(ra, dec, unit='degree'):
    from astropy.coordinates import SkyCoord
    from astropy import units
    unit = units.Unit(unit)
    return SkyCoord(ra=ra, dec=dec, unit=unit)

# ---

def match_pairs(match_A_nn_idx, match_B_nn_idx, match_A_nn_sep):
    import numpy
    A_matched_pairs = zip(numpy.arange(len(match_A_nn_idx)),
                          match_A_nn_idx )
    B_matched_pairs = set(zip(match_B_nn_idx,
                          numpy.arange(len(match_B_nn_idx))))

    matched_pairs = []
    matched_dists = []
    for i,p in enumerate(A_matched_pairs):
        if p in B_matched_pairs:
            matched_pairs.append(p)
            matched_dists.append(match_A_nn_sep[i])

    A_matched_idx,B_matched_idx = zip(*matched_pairs)
    
    return (A_matched_idx, B_matched_idx, matched_dists)

# ---

def assemble_indexes(A_matched_idx,B_matched_idx,matched_dists):
    import pandas
    df_matched_idx = pandas.DataFrame({ 'A_idx':A_matched_idx,
                                        'B_idx':B_matched_idx,
                                        'separation':matched_dists})
    df_matched_idx = df_matched_idx.set_index('A_idx')
    return df_matched_idx

# ---

def merge_catalogs(A,B,df_matched_idx):

#     A_new_columns = { col:'A_'+col for col in A.columns }
#     B_new_columns = { col:'B_'+col for col in B.columns }
#     new_column_names = A_new_columns
#     new_column_names.update(B_new_columns)
#     print new_column_names
    
    B_matched = B.iloc[df_matched_idx.B_idx]
    B_matched['A_idx'] = df_matched_idx.index
    B_matched = B_matched.set_index('A_idx')

    from pandas import DataFrame
    dist = DataFrame({'dist':numpy.asarray(df_matched_idx.separation)},
                     index=B_matched.index)

    df = pandas.concat([ A,B_matched,dist ], axis=1, keys=['A','B','AB'])

    return df

# ---

Serial run


In [12]:
# ---
# A_filename = 'cs82/cs82.fits'
# B_filename = 'spies/spies.fits'

# column_names = (['OBJID','RA','DEC'],['id','RA_ch1','DEC_ch1'])
# A_data, B_data = read_catalogs(A_filename,B_filename,column_names)

# from astropy.table import Table
# A = Table(A_data)
# B = Table(B_data)

# A_coord = get_coordinates(A['RA'],A['DEC'])
# B_coord = get_coordinates(B['RA_ch1'],B['DEC_ch1'])

import pandas
assert isinstance(df1,pandas.DataFrame)
assert isinstance(df2,pandas.DataFrame)
A = df1.copy()
B = df2.copy()
norm_factor=500

A_coord,B_coord = normalize_coordinates(A, B, norm_factor)

match_A_nn_idx, match_A_nn_sep = Xmatch.xmatch_nn(A_coord, B_coord, parallel=False)
match_B_nn_idx, match_B_nn_sep = Xmatch.xmatch_nn(B_coord, A_coord, parallel=False)
del A_coord,B_coord

A_matched_idx, B_matched_idx, matched_dists = match_pairs(match_A_nn_idx, match_B_nn_idx, match_A_nn_sep)

import numpy
matched_dists = numpy.asarray([ _d * norm_factor for _d in matched_dists ], dtype=int)

df_matched_idx = assemble_indexes(A_matched_idx, B_matched_idx, matched_dists)
del A_matched_idx, B_matched_idx, matched_dists

matched_catalog_serial = merge_catalogs(A,B,df_matched_idx)
del df_matched_idx


/home/chbrandt/.conda/envs/booq-dev/lib/python2.7/site-packages/ipykernel/__main__.py:230: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

In [13]:
# from astropy.table import Table
# tab = Table.from_pandas(matched_catalog_serial)
# tab.show_in_notebook()

Parallel run


In [14]:
import pandas
assert isinstance(df1,pandas.DataFrame)
assert isinstance(df2,pandas.DataFrame)
A = df1.copy()
B = df2.copy()
norm_factor=500

A_coord,B_coord = normalize_coordinates(A, B, norm_factor)

match_A_nn_idx, match_A_nn_sep = Xmatch.xmatch_nn(A_coord, B_coord, parallel=True)
match_B_nn_idx, match_B_nn_sep = Xmatch.xmatch_nn(B_coord, A_coord, parallel=True)
del A_coord,B_coord

A_matched_idx, B_matched_idx, matched_dists = match_pairs(match_A_nn_idx, match_B_nn_idx, match_A_nn_sep)

import numpy
matched_dists = numpy.asarray([ _d * norm_factor for _d in matched_dists ], dtype=int)

df_matched_idx = assemble_indexes(A_matched_idx, B_matched_idx, matched_dists)
del A_matched_idx, B_matched_idx, matched_dists

matched_catalog_parallel = merge_catalogs(A,B,df_matched_idx)
del df_matched_idx


Running in parallel
Running in parallel
/home/chbrandt/.conda/envs/booq-dev/lib/python2.7/site-packages/ipykernel/__main__.py:230: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

Are the output catalogs from serial and parallel equal to each other?


In [15]:
matched_catalog_parallel.equals(matched_catalog_serial)


Out[15]:
True

Merging all the steps


In [21]:
def xmatch(catalog_A, catalog_B, parallel_run=False, algorithm='NN'):
    """
    Input:
     - catalog_A, catalog_B : ~pandas.DataFrame
             DFs containing (at least) the columns 'ra','dec','id'
             
    Output:
     - matched_catalog : ~pandas.DataFrame
    """
    from pandas import DataFrame
    assert isinstance(catalog_A,DataFrame)
    assert isinstance(catalog_B,DataFrame)
    
    def check_columns(column_names):
        mandatory_cols = ['ra','dec','id']
        return set(filter(lambda x:str(x) in mandatory_cols, column_names)) == set(mandatory_cols)
    assert check_columns(catalog_A.columns),"Error: columns ['ra','dec','id'] not present in catalog_A"
    assert check_columns(catalog_B.columns),"Error: columns ['ra','dec','id'] not present in catalog_B"
    
    A_coord = compile_coordinates(catalog_A['ra'],catalog_A['dec'])
    B_coord = compile_coordinates(catalog_B['ra'],catalog_B['dec'])
    
    match_A_nn_idx, match_A_nn_sep = Xmatch.xmatch_nn(A_coord, B_coord, parallel=parallel_run)
    match_B_nn_idx, match_B_nn_sep = Xmatch.xmatch_nn(B_coord, A_coord, parallel=parallel_run)
    del A_coord,B_coord

    A_matched_idx, B_matched_idx, matched_dists = match_pairs(match_A_nn_idx, match_B_nn_idx, match_A_nn_sep)

    df_matched_idx = assemble_indexes(A_matched_idx, B_matched_idx, matched_dists)
    del A_matched_idx, B_matched_idx, matched_dists

    matched_catalog = merge_catalogs(catalog_A, catalog_B, df_matched_idx)
    del df_matched_idx
    
    return matched_catalog

In [74]:
# Generate catalog A
A_image_catalog = Mock.generate_catalog_2D(nsrc1,rerr1, (sy,sx))
ra = Coordinates.pixel_to_sky(A_image_catalog.x, 0, 1.0/sx)
dec = Coordinates.pixel_to_sky(A_image_catalog.y, 0, 1.0/sy)
A = A_image_catalog.copy()
A.loc[:,'ra'] = ra
A.loc[:,'dec'] = dec
A.rename(columns={'ID':'id'}, inplace=True)

# Generate catalog B
B_image_catalog = Mock.generate_catalog_2D_around(A_image_catalog, 0.75, (sy,sx))
ra = Coordinates.pixel_to_sky(B_image_catalog.x, 0, 1.0/sx)
dec = Coordinates.pixel_to_sky(B_image_catalog.y, 0, 1.0/sy)
B = B_image_catalog.copy()
B.loc[:,'ra'] = ra
B.loc[:,'dec'] = dec
B.rename(columns={'ID':'id'}, inplace=True)

In [77]:
# X-match the catalogs
matched_catalog = xmatch(A, B)
matched_catalog


/home/chbrandt/.conda/envs/booq-dev/lib/python2.7/site-packages/ipykernel/__main__.py:233: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
Out[77]:
A B AB
id r x y ra dec id r x y ra dec dist
0 1 20 4463 4592 0.8926 0.9184 NaN NaN NaN NaN NaN NaN NaN
1 2 20 4409 4116 0.8818 0.8232 NaN NaN NaN NaN NaN NaN NaN
2 3 20 4248 1770 0.8496 0.3540 3.0 20.0 4213.0 1776.0 0.8426 0.3552 0.007102
3 4 20 1895 3786 0.3790 0.7572 4.0 20.0 1884.0 3742.0 0.3768 0.7484 0.009071
4 5 20 1876 2236 0.3752 0.4472 5.0 20.0 1890.0 2214.0 0.3780 0.4428 0.005215
5 6 20 2760 602 0.5520 0.1204 NaN NaN NaN NaN NaN NaN NaN
6 7 20 2302 3081 0.4604 0.6162 NaN NaN NaN NaN NaN NaN NaN
7 8 20 4724 4615 0.9448 0.9230 8.0 20.0 4729.0 4650.0 0.9458 0.9300 0.007071
8 9 20 4340 4628 0.8680 0.9256 9.0 20.0 4323.0 4629.0 0.8646 0.9258 0.003405
9 10 20 1666 1103 0.3332 0.2206 NaN NaN NaN NaN NaN NaN NaN
10 11 20 3525 4308 0.7050 0.8616 NaN NaN NaN NaN NaN NaN NaN
11 12 20 4261 3614 0.8522 0.7228 12.0 20.0 4266.0 3592.0 0.8532 0.7184 0.004512
12 13 20 2491 4539 0.4982 0.9078 13.0 20.0 2505.0 4534.0 0.5010 0.9068 0.002973
13 14 20 4731 4549 0.9462 0.9098 14.0 20.0 4743.0 4501.0 0.9486 0.9002 0.009895
14 15 20 2152 20 0.4304 0.0040 NaN NaN NaN NaN NaN NaN NaN
15 16 20 1704 3985 0.3408 0.7970 NaN NaN NaN NaN NaN NaN NaN
16 17 20 1381 241 0.2762 0.0482 17.0 20.0 1421.0 173.0 0.2842 0.0346 0.015778
17 18 20 1070 4391 0.2140 0.8782 18.0 20.0 1059.0 4403.0 0.2118 0.8806 0.003256
18 19 20 3192 4104 0.6384 0.8208 19.0 20.0 3158.0 4086.0 0.6316 0.8172 0.007694
19 20 20 4237 343 0.8474 0.0686 73.0 20.0 4318.0 338.0 0.8636 0.0676 0.016231
20 21 20 1422 804 0.2844 0.1608 231.0 20.0 1417.0 801.0 0.2834 0.1602 0.001166
21 22 20 1766 562 0.3532 0.1124 NaN NaN NaN NaN NaN NaN NaN
22 23 20 1035 4141 0.2070 0.8282 23.0 20.0 1018.0 4145.0 0.2036 0.8290 0.003493
23 24 20 354 1921 0.0708 0.3842 24.0 20.0 347.0 1942.0 0.0694 0.3884 0.004427
24 25 20 4551 84 0.9102 0.0168 NaN NaN NaN NaN NaN NaN NaN
25 26 20 2936 1099 0.5872 0.2198 26.0 20.0 2940.0 1097.0 0.5880 0.2194 0.000894
26 27 20 4325 3844 0.8650 0.7688 27.0 20.0 4355.0 3826.0 0.8710 0.7652 0.006997
27 28 20 445 1083 0.0890 0.2166 28.0 20.0 466.0 1097.0 0.0932 0.2194 0.005048
28 29 20 639 2002 0.1278 0.4004 NaN NaN NaN NaN NaN NaN NaN
29 30 20 4070 986 0.8140 0.1972 155.0 20.0 4091.0 1084.0 0.8182 0.2168 0.020045
... ... ... ... ... ... ... ... ... ... ... ... ... ...
220 221 20 2285 3073 0.4570 0.6146 7.0 20.0 2286.0 3068.0 0.4572 0.6136 0.001020
221 222 20 4790 3585 0.9580 0.7170 NaN NaN NaN NaN NaN NaN NaN
222 223 20 2557 313 0.5114 0.0626 20.0 20.0 2431.0 365.0 0.4862 0.0730 0.027262
223 224 20 4185 2669 0.8370 0.5338 NaN NaN NaN NaN NaN NaN NaN
224 225 20 1458 3944 0.2916 0.7888 NaN NaN NaN NaN NaN NaN NaN
225 226 20 732 4329 0.1464 0.8658 NaN NaN NaN NaN NaN NaN NaN
226 227 20 2742 2004 0.5484 0.4008 227.0 20.0 2738.0 1984.0 0.5476 0.3968 0.004079
227 228 20 1962 2562 0.3924 0.5124 228.0 20.0 1958.0 2574.0 0.3916 0.5148 0.002530
228 229 20 2725 1683 0.5450 0.3366 229.0 20.0 2750.0 1678.0 0.5500 0.3356 0.005099
229 230 20 1543 3607 0.3086 0.7214 230.0 20.0 1556.0 3606.0 0.3112 0.7212 0.002607
230 231 20 1415 807 0.2830 0.1614 NaN NaN NaN NaN NaN NaN NaN
231 232 20 302 2438 0.0604 0.4876 232.0 20.0 262.0 2428.0 0.0524 0.4856 0.008246
232 233 20 3962 3221 0.7924 0.6442 233.0 20.0 3948.0 3201.0 0.7896 0.6402 0.004883
233 234 20 2140 3582 0.4280 0.7164 234.0 20.0 2165.0 3614.0 0.4330 0.7228 0.008121
234 235 20 831 3066 0.1662 0.6132 NaN NaN NaN NaN NaN NaN NaN
235 236 20 644 3564 0.1288 0.7128 NaN NaN NaN NaN NaN NaN NaN
236 237 20 827 3722 0.1654 0.7444 237.0 20.0 845.0 3679.0 0.1690 0.7358 0.009323
237 238 20 1028 1509 0.2056 0.3018 238.0 20.0 1044.0 1533.0 0.2088 0.3066 0.005769
238 239 20 820 2463 0.1640 0.4926 239.0 20.0 816.0 2486.0 0.1632 0.4972 0.004669
239 240 20 1145 4373 0.2290 0.8746 240.0 20.0 1185.0 4339.0 0.2370 0.8678 0.010499
240 241 20 2950 3818 0.5900 0.7636 NaN NaN NaN NaN NaN NaN NaN
241 242 20 1431 2497 0.2862 0.4994 242.0 20.0 1414.0 2507.0 0.2828 0.5014 0.003945
242 243 20 4689 1859 0.9378 0.3718 NaN NaN NaN NaN NaN NaN NaN
243 244 20 4519 3139 0.9038 0.6278 244.0 20.0 4511.0 3161.0 0.9022 0.6322 0.004682
244 245 20 2062 1063 0.4124 0.2126 245.0 20.0 2073.0 1077.0 0.4146 0.2154 0.003561
245 246 20 176 4677 0.0352 0.9354 NaN NaN NaN NaN NaN NaN NaN
246 247 20 461 3241 0.0922 0.6482 247.0 20.0 460.0 3255.0 0.0920 0.6510 0.002807
247 248 20 1852 3374 0.3704 0.6748 248.0 20.0 1866.0 3373.0 0.3732 0.6746 0.002807
248 249 20 3272 4471 0.6544 0.8942 249.0 20.0 3287.0 4479.0 0.6574 0.8958 0.003400
249 250 20 17 381 0.0034 0.0762 NaN NaN NaN NaN NaN NaN NaN

250 rows × 13 columns


In [80]:
matched_catalog_parallel = xmatch(A,B,parallel_run=True)
matched_catalog_parallel


Running in parallel
Running in parallel
/home/chbrandt/.conda/envs/booq-dev/lib/python2.7/site-packages/ipykernel/__main__.py:233: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
Out[80]:
A B AB
id r x y ra dec id r x y ra dec dist
0 1 20 4463 4592 0.8926 0.9184 NaN NaN NaN NaN NaN NaN NaN
1 2 20 4409 4116 0.8818 0.8232 NaN NaN NaN NaN NaN NaN NaN
2 3 20 4248 1770 0.8496 0.3540 3.0 20.0 4213.0 1776.0 0.8426 0.3552 0.007102
3 4 20 1895 3786 0.3790 0.7572 4.0 20.0 1884.0 3742.0 0.3768 0.7484 0.009071
4 5 20 1876 2236 0.3752 0.4472 5.0 20.0 1890.0 2214.0 0.3780 0.4428 0.005215
5 6 20 2760 602 0.5520 0.1204 NaN NaN NaN NaN NaN NaN NaN
6 7 20 2302 3081 0.4604 0.6162 NaN NaN NaN NaN NaN NaN NaN
7 8 20 4724 4615 0.9448 0.9230 8.0 20.0 4729.0 4650.0 0.9458 0.9300 0.007071
8 9 20 4340 4628 0.8680 0.9256 9.0 20.0 4323.0 4629.0 0.8646 0.9258 0.003405
9 10 20 1666 1103 0.3332 0.2206 NaN NaN NaN NaN NaN NaN NaN
10 11 20 3525 4308 0.7050 0.8616 NaN NaN NaN NaN NaN NaN NaN
11 12 20 4261 3614 0.8522 0.7228 12.0 20.0 4266.0 3592.0 0.8532 0.7184 0.004512
12 13 20 2491 4539 0.4982 0.9078 13.0 20.0 2505.0 4534.0 0.5010 0.9068 0.002973
13 14 20 4731 4549 0.9462 0.9098 14.0 20.0 4743.0 4501.0 0.9486 0.9002 0.009895
14 15 20 2152 20 0.4304 0.0040 NaN NaN NaN NaN NaN NaN NaN
15 16 20 1704 3985 0.3408 0.7970 NaN NaN NaN NaN NaN NaN NaN
16 17 20 1381 241 0.2762 0.0482 17.0 20.0 1421.0 173.0 0.2842 0.0346 0.015778
17 18 20 1070 4391 0.2140 0.8782 18.0 20.0 1059.0 4403.0 0.2118 0.8806 0.003256
18 19 20 3192 4104 0.6384 0.8208 19.0 20.0 3158.0 4086.0 0.6316 0.8172 0.007694
19 20 20 4237 343 0.8474 0.0686 73.0 20.0 4318.0 338.0 0.8636 0.0676 0.016231
20 21 20 1422 804 0.2844 0.1608 231.0 20.0 1417.0 801.0 0.2834 0.1602 0.001166
21 22 20 1766 562 0.3532 0.1124 NaN NaN NaN NaN NaN NaN NaN
22 23 20 1035 4141 0.2070 0.8282 23.0 20.0 1018.0 4145.0 0.2036 0.8290 0.003493
23 24 20 354 1921 0.0708 0.3842 24.0 20.0 347.0 1942.0 0.0694 0.3884 0.004427
24 25 20 4551 84 0.9102 0.0168 NaN NaN NaN NaN NaN NaN NaN
25 26 20 2936 1099 0.5872 0.2198 26.0 20.0 2940.0 1097.0 0.5880 0.2194 0.000894
26 27 20 4325 3844 0.8650 0.7688 27.0 20.0 4355.0 3826.0 0.8710 0.7652 0.006997
27 28 20 445 1083 0.0890 0.2166 28.0 20.0 466.0 1097.0 0.0932 0.2194 0.005048
28 29 20 639 2002 0.1278 0.4004 NaN NaN NaN NaN NaN NaN NaN
29 30 20 4070 986 0.8140 0.1972 155.0 20.0 4091.0 1084.0 0.8182 0.2168 0.020045
... ... ... ... ... ... ... ... ... ... ... ... ... ...
220 221 20 2285 3073 0.4570 0.6146 7.0 20.0 2286.0 3068.0 0.4572 0.6136 0.001020
221 222 20 4790 3585 0.9580 0.7170 NaN NaN NaN NaN NaN NaN NaN
222 223 20 2557 313 0.5114 0.0626 20.0 20.0 2431.0 365.0 0.4862 0.0730 0.027262
223 224 20 4185 2669 0.8370 0.5338 NaN NaN NaN NaN NaN NaN NaN
224 225 20 1458 3944 0.2916 0.7888 NaN NaN NaN NaN NaN NaN NaN
225 226 20 732 4329 0.1464 0.8658 NaN NaN NaN NaN NaN NaN NaN
226 227 20 2742 2004 0.5484 0.4008 227.0 20.0 2738.0 1984.0 0.5476 0.3968 0.004079
227 228 20 1962 2562 0.3924 0.5124 228.0 20.0 1958.0 2574.0 0.3916 0.5148 0.002530
228 229 20 2725 1683 0.5450 0.3366 229.0 20.0 2750.0 1678.0 0.5500 0.3356 0.005099
229 230 20 1543 3607 0.3086 0.7214 230.0 20.0 1556.0 3606.0 0.3112 0.7212 0.002607
230 231 20 1415 807 0.2830 0.1614 NaN NaN NaN NaN NaN NaN NaN
231 232 20 302 2438 0.0604 0.4876 232.0 20.0 262.0 2428.0 0.0524 0.4856 0.008246
232 233 20 3962 3221 0.7924 0.6442 233.0 20.0 3948.0 3201.0 0.7896 0.6402 0.004883
233 234 20 2140 3582 0.4280 0.7164 234.0 20.0 2165.0 3614.0 0.4330 0.7228 0.008121
234 235 20 831 3066 0.1662 0.6132 NaN NaN NaN NaN NaN NaN NaN
235 236 20 644 3564 0.1288 0.7128 NaN NaN NaN NaN NaN NaN NaN
236 237 20 827 3722 0.1654 0.7444 237.0 20.0 845.0 3679.0 0.1690 0.7358 0.009323
237 238 20 1028 1509 0.2056 0.3018 238.0 20.0 1044.0 1533.0 0.2088 0.3066 0.005769
238 239 20 820 2463 0.1640 0.4926 239.0 20.0 816.0 2486.0 0.1632 0.4972 0.004669
239 240 20 1145 4373 0.2290 0.8746 240.0 20.0 1185.0 4339.0 0.2370 0.8678 0.010499
240 241 20 2950 3818 0.5900 0.7636 NaN NaN NaN NaN NaN NaN NaN
241 242 20 1431 2497 0.2862 0.4994 242.0 20.0 1414.0 2507.0 0.2828 0.5014 0.003945
242 243 20 4689 1859 0.9378 0.3718 NaN NaN NaN NaN NaN NaN NaN
243 244 20 4519 3139 0.9038 0.6278 244.0 20.0 4511.0 3161.0 0.9022 0.6322 0.004682
244 245 20 2062 1063 0.4124 0.2126 245.0 20.0 2073.0 1077.0 0.4146 0.2154 0.003561
245 246 20 176 4677 0.0352 0.9354 NaN NaN NaN NaN NaN NaN NaN
246 247 20 461 3241 0.0922 0.6482 247.0 20.0 460.0 3255.0 0.0920 0.6510 0.002807
247 248 20 1852 3374 0.3704 0.6748 248.0 20.0 1866.0 3373.0 0.3732 0.6746 0.002807
248 249 20 3272 4471 0.6544 0.8942 249.0 20.0 3287.0 4479.0 0.6574 0.8958 0.003400
249 250 20 17 381 0.0034 0.0762 NaN NaN NaN NaN NaN NaN NaN

250 rows × 13 columns


In [81]:
matched_catalog_parallel.equals(matched_catalog)


Out[81]:
True

In [139]:
def table_2_dataframe(df):
    from astropy.table import Table

    from pandas import MultiIndex
    multiindex = True if isinstance(df.columns,MultiIndex) else False

    if not multiindex:
        return Table.from_pandas(df)

    levels = df.columns.levels
    labels = df.columns.labels
    assert len(levels)==len(labels)

    if len(levels) != 2:
        print "Error: sorry, I only know how to work with 2-leveled MultiIndex"
        return None

    plain_columns = [ levels[0][t[0]] +'_'+ levels[1][t[1]] for t in zip(*labels) ]

    tab = Table(df.values, names=plain_columns)
    return tab


from astropy.table import Table
class aTable(Table):
    @classmethod
    def from_pandas(cls,df):
        """
        """
        from pandas import MultiIndex
        multiindex = True if isinstance(df.columns,MultiIndex) else False
        if not multiindex:
            return super(aTable,cls).from_pandas(df)
        return table_2_dataframe(df)

In [142]:
aTable.from_pandas(matched_catalog).show_in_notebook()


Out[142]:
<Table length=250>
A_idA_rA_xA_yA_raA_decB_idB_rB_xB_yB_raB_decAB_dist
1.020.04463.04592.00.89260.9184nannannannannannannan
2.020.04409.04116.00.88180.8232nannannannannannannan
3.020.04248.01770.00.84960.3543.020.04213.01776.00.84260.35520.00710198022933
4.020.01895.03786.00.3790.75724.020.01884.03742.00.37680.74840.0090707863228
5.020.01876.02236.00.37520.44725.020.01890.02214.00.3780.44280.00521531658504
6.020.02760.0602.00.5520.1204nannannannannannannan
7.020.02302.03081.00.46040.6162nannannannannannannan
8.020.04724.04615.00.94480.9238.020.04729.04650.00.94580.930.00707104932363
9.020.04340.04628.00.8680.92569.020.04323.04629.00.86460.92580.00340543429273
10.020.01666.01103.00.33320.2206nannannannannannannan
11.020.03525.04308.00.7050.8616nannannannannannannan
12.020.04261.03614.00.85220.722812.020.04266.03592.00.85320.71840.00451218814223
13.020.02491.04539.00.49820.907813.020.02505.04534.00.5010.90680.0029728831483
14.020.04731.04549.00.94620.909814.020.04743.04501.00.94860.90020.00989538089453
15.020.02152.020.00.43040.004nannannannannannannan
16.020.01704.03985.00.34080.797nannannannannannannan
17.020.01381.0241.00.27620.048217.020.01421.0173.00.28420.03460.0157784652703
18.020.01070.04391.00.2140.878218.020.01059.04403.00.21180.88060.00325558902656
19.020.03192.04104.00.63840.820819.020.03158.04086.00.63160.81720.00769353966766
20.020.04237.0343.00.84740.068673.020.04318.0338.00.86360.06760.0162308234309
21.020.01422.0804.00.28440.1608231.020.01417.0801.00.28340.16020.00116618701459
22.020.01766.0562.00.35320.1124nannannannannannannan
23.020.01035.04141.00.2070.828223.020.01018.04145.00.20360.8290.00349250375351
24.020.0354.01921.00.07080.384224.020.0347.01942.00.06940.38840.00442717866186
25.020.04551.084.00.91020.0168nannannannannannannan
26.020.02936.01099.00.58720.219826.020.02940.01097.00.5880.21940.000894421935384
27.020.04325.03844.00.8650.768827.020.04355.03826.00.8710.76520.00699668128921
28.020.0445.01083.00.0890.216628.020.0466.01097.00.09320.21940.00504774649025
29.020.0639.02002.00.12780.4004nannannannannannannan
30.020.04070.0986.00.8140.1972155.020.04091.01084.00.81820.21680.0200449437411
31.020.0886.01343.00.17720.268631.020.0903.01310.00.18060.2620.00742426778477
32.020.04448.0776.00.88960.1552nannannannannannannan
33.020.01635.0142.00.3270.0284nannannannannannannan
34.020.01887.01472.00.37740.2944nannannannannannannan
35.020.01662.04513.00.33240.902635.020.01656.04520.00.33120.9040.00184381184329
36.020.01069.03703.00.21380.740664.020.01144.03591.00.22880.71820.0269578102732
37.020.04172.02046.00.83440.409237.020.04178.02056.00.83560.41120.00233236493548
38.020.01914.03478.00.38280.6956nannannannannannannan
39.020.0112.03617.00.02240.723439.020.0128.03610.00.02560.7220.00349261662646
40.020.01667.03586.00.33340.717240.020.01688.03570.00.33760.7140.00527989095375
41.020.0326.04229.00.06520.845841.020.0333.04232.00.06660.84640.00152301431762
42.020.04465.01525.00.8930.30542.020.04456.01535.00.89120.3070.00269070763657
43.020.03227.04037.00.64540.807443.020.03229.04039.00.64580.80780.000565657328956
44.020.02252.02915.00.45040.58344.020.02254.02874.00.45080.57480.00820974930596
45.020.03840.03587.00.7680.717445.020.03852.03561.00.77040.71220.00572705016136
46.020.01601.0149.00.32020.0298nannannannannannannan
47.020.04370.02672.00.8740.5344nannannannannannannan
48.020.0238.0668.00.04760.133648.020.0233.0651.00.04660.13020.00354400828161
49.020.02690.0918.00.5380.183649.020.02669.0901.00.53380.18020.0054036859828
50.020.0883.0713.00.17660.142650.020.0860.0682.00.1720.13640.007720095501
51.020.01412.04451.00.28240.890251.020.01423.04449.00.28460.88980.00223580684823
52.020.02237.04133.00.44740.826652.020.02214.04105.00.44280.8210.00724676658449
53.020.03545.04136.00.7090.827253.020.03556.04138.00.71120.82760.00223584228981
54.020.01075.02052.00.2150.4104nannannannannannannan
55.020.01650.054.00.330.0108nannannannannannannan
56.020.0708.02605.00.14160.52156.020.0732.02592.00.14640.51840.00545876400532
57.020.02849.0645.00.56980.12957.020.02868.0646.00.57360.12920.00380524988512
58.020.02534.0741.00.50680.1482nannannannannannannan
59.020.01330.04846.00.2660.9692nannannannannannannan
60.020.01964.0269.00.39280.053860.020.02015.0275.00.4030.0550.010270341095
61.020.02018.0428.00.40360.085661.020.02043.0471.00.40860.09420.00994786099647
62.020.04559.02931.00.91180.586262.020.04560.02919.00.9120.58380.00240831805006
63.020.03528.04396.00.70560.879263.020.03517.04416.00.70340.88320.00456495950004
64.020.01029.04764.00.20580.9528nannannannannannannan
65.020.03408.03916.00.68160.7832nannannannannannannan
66.020.0618.03491.00.12360.698266.020.0646.03475.00.12920.6950.00644944685287
67.020.0910.0249.00.1820.049867.020.0928.0270.00.18560.0540.00553172571267
68.020.02871.04099.00.57420.819868.020.02857.04093.00.57140.81860.00304604619378
69.020.02141.03948.00.42820.789669.020.02131.03940.00.42620.7880.00256110169833
70.020.04718.02645.00.94360.529nannannannannannannan
71.020.02361.04959.00.47220.991871.020.02343.04949.00.46860.98980.00411778154464
72.020.02914.01056.00.58280.2112nannannannannannannan
73.020.02147.01589.00.42940.3178nannannannannannannan
74.020.04914.0737.00.98280.147474.020.04900.0706.00.980.14120.00680293688521
75.020.0555.02867.00.1110.5734nannannannannannannan
76.020.0543.02566.00.10860.513276.020.0540.02594.00.1080.51880.00563204854403
77.020.02485.02598.00.4970.5196nannannannannannannan
78.020.04207.04240.00.84140.84878.020.04223.04224.00.84460.84480.00452523651624
79.020.01704.03078.00.34080.615679.020.01712.03097.00.34240.61940.0041230695677
80.020.04972.04103.00.99440.820680.020.04976.04120.00.99520.8240.00349283096995
81.020.04226.04269.00.84520.8538nannannannannannannan
82.020.0534.02746.00.10680.5492142.020.0588.02775.00.11760.5550.012258432608
83.020.04548.0877.00.90960.1754nannannannannannannan
84.020.04871.02267.00.97420.4534250.020.04743.02251.00.94860.45020.025798435044
85.020.04807.03409.00.96140.681885.020.04819.03410.00.96380.6820.00240814953293
86.020.02852.0775.00.57040.15586.020.02848.0782.00.56960.15640.00161245008412
87.020.04096.0122.00.81920.024488.020.04120.0247.00.8240.04940.0254566295899
88.020.0648.01482.00.12960.2964nannannannannannannan
89.020.0637.02113.00.12740.4226nannannannannannannan
90.020.04689.02370.00.93780.47490.020.04718.02389.00.94360.47780.00693380697867
91.020.01143.01699.00.22860.339891.020.01152.01692.00.23040.33840.00228032596612
92.020.04729.03539.00.94580.7078nannannannannannannan
93.020.02895.04691.00.5790.938270.020.02824.04730.00.56480.9460.0161995521055
94.020.03432.02150.00.68640.4394.020.03467.02166.00.69340.43320.00769657193813
95.020.01776.04978.00.35520.995695.020.01790.04989.00.3580.99780.00356056565364
96.020.0736.01040.00.14720.20896.020.0756.01058.00.15120.21160.00538142968614
97.020.04816.01152.00.96320.230497.020.04789.01156.00.95780.23120.00545889428692
98.020.01335.04510.00.2670.90298.020.01313.04531.00.26260.90620.00608236630605
99.020.03554.02551.00.71080.5102nannannannannannannan
100.020.04642.03258.00.92840.6516100.020.04626.03215.00.92520.6430.00917598458289
101.020.02531.02695.00.50620.539nannannannannannannan
102.020.0825.01007.00.1650.2014102.020.0849.01001.00.16980.20020.00494769815313
103.020.0695.02449.00.1390.4898103.020.0671.02437.00.13420.48740.00536640704181
104.020.0210.03688.00.0420.7376104.020.0210.03710.00.0420.7420.0044
105.020.02437.01300.00.48740.26105.020.02454.01318.00.49080.26360.00495174299064
106.020.04295.01378.00.8590.2756nannannannannannannan
107.020.02282.01087.00.45640.2174nannannannannannannan
108.020.03193.01144.00.63860.2288nannannannannannannan
109.020.04598.03757.00.91960.7514226.020.04533.03791.00.90660.75820.0146700603939
110.020.049.01849.00.00980.3698110.020.080.01843.00.0160.36860.00631493498902
111.020.01559.04795.00.31180.959111.020.01558.04802.00.31160.96040.00141420959502
112.020.02132.04572.00.42640.9144112.020.02127.04575.00.42540.9150.00116608111019
113.020.02842.03278.00.56840.6556224.020.02812.03324.00.56240.66480.0109834065913
114.020.04419.03222.00.88380.6444114.020.04419.03244.00.88380.64880.0044
115.020.03312.0620.00.66240.124115.020.03349.0642.00.66980.12840.00860928186941
116.020.0646.04607.00.12920.9214116.020.0644.04598.00.12880.91960.00184389769407
117.020.02094.04550.00.41880.91117.020.02083.04580.00.41660.9160.00639052197622
118.020.0610.02872.00.1220.5744nannannannannannannan
119.020.03912.0428.00.78240.0856119.020.03944.0412.00.78880.08240.00715541137537
120.020.03140.0855.00.6280.171120.020.03136.0856.00.62720.17120.000824617664535
121.020.0618.023.00.12360.0046nannannannannannannan
122.020.03076.01281.00.61520.2562nannannannannannannan
123.020.03381.03846.00.67620.7692nannannannannannannan
124.020.04429.01761.00.88580.3522124.020.04429.01769.00.88580.35380.0016
125.020.0222.02495.00.04440.499125.020.0238.02489.00.04760.49780.00341748813918
126.020.03675.01236.00.7350.2472126.020.03684.01234.00.73680.24680.00184389256381
127.020.01021.02789.00.20420.5578127.020.01018.02800.00.20360.560.00228034333948
128.020.04788.03720.00.95760.744128.020.04812.03756.00.96240.75120.00865309641552
129.020.0468.01781.00.09360.3562129.020.0471.01798.00.09420.35960.00345253326605
130.020.03131.04340.00.62620.868130.020.03129.04342.00.62580.86840.000565652954483
131.020.02040.0764.00.4080.1528131.020.02070.0766.00.4140.15320.00601329720636
132.020.03307.02587.00.66140.5174132.020.03324.02575.00.66480.5150.00416161767933
133.020.02060.0648.00.4120.1296133.020.02049.0602.00.40980.12040.0094593856541
134.020.0226.0882.00.04520.1764134.020.0220.0832.00.0440.16640.0100717420097
135.020.02843.037.00.56860.0074135.020.02836.037.00.56720.00740.00139999998832
136.020.04128.04031.00.82560.8062136.020.04160.04038.00.8320.80760.00655071574949
137.020.0955.02218.00.1910.4436137.020.0942.02197.00.18840.43940.00493959498525
138.020.0947.01516.00.18940.3032138.020.0966.01480.00.19320.2960.00814122872537
139.020.03252.02119.00.65040.4238139.020.03243.02109.00.64860.42180.00269069202511
140.020.01619.03052.00.32380.6104140.020.01625.03033.00.3250.60660.00398495139067
141.020.03056.02389.00.61120.4778141.020.03067.02407.00.61340.48140.00421896443246
142.020.0211.04728.00.04220.9456nannannannannannannan
143.020.0155.0819.00.0310.1638143.020.0140.0810.00.0280.1620.00349856073956
144.020.0402.01670.00.08040.334144.020.0394.01687.00.07880.33740.00375764715198
145.020.0294.03925.00.05880.785145.020.0292.03924.00.05840.78480.000447180025796
146.020.01930.02472.00.3860.4944nannannannannannannan
147.020.02910.01532.00.5820.3064147.020.02911.01509.00.58220.30180.00460434565092
148.020.03276.02650.00.65520.53148.020.03271.02633.00.65420.52660.00354399703486
149.020.03409.03209.00.68180.6418149.020.03362.03212.00.67240.64240.00941854039664
150.020.01040.0675.00.2080.135150.020.01046.0680.00.20920.1360.00156204735724
151.020.03379.04633.00.67580.9266nannannannannannannan
152.020.03974.0804.00.79480.160833.020.03976.0775.00.79520.1550.00581377663698
153.020.03982.02532.00.79640.5064153.020.03979.02564.00.79580.51280.00642806125686
154.020.02136.01049.00.42720.2098154.020.02139.01063.00.42780.21260.00286356335855
155.020.03510.01202.00.7020.2404157.020.03515.01252.00.7030.25040.0100498747083
156.020.03611.01029.00.72220.2058156.020.03617.01026.00.72340.20520.00134163388292
157.020.03459.01249.00.69180.2498nannannannannannannan
158.020.01897.01721.00.37940.3442nannannannannannannan
159.020.0362.03752.00.07240.7504nannannannannannannan
160.020.03971.04496.00.79420.8992206.020.04052.04445.00.81040.8890.0191419982301
161.020.02603.02286.00.52060.4572161.020.02626.02299.00.52520.45980.00528380970463
162.020.04729.04238.00.94580.8476nannannannannannannan
163.020.01813.0747.00.36260.1494nannannannannannannan
164.020.03436.0176.00.68720.0352164.020.03436.0194.00.68720.03880.0036
165.020.01970.04763.00.3940.9526nannannannannannannan
166.020.01404.03837.00.28080.7674166.020.01409.03827.00.28180.76540.00223602797115
167.020.01757.02636.00.35140.5272167.020.01796.02628.00.35920.52560.00796208921852
168.020.01075.03935.00.2150.787181.020.0972.03890.00.19440.7780.022478453078
169.020.02828.03974.00.56560.7948169.020.02809.03953.00.56180.79060.00566367691166
170.020.0297.01156.00.05940.2312nannannannannannannan
171.020.0622.04037.00.12440.8074171.020.0609.04029.00.12180.80580.00305264808916
172.020.03741.01896.00.74820.3792172.020.03739.01904.00.74780.38080.0016492401166
173.020.0961.04913.00.19220.9826173.020.0987.04903.00.19740.98060.00557064307296
174.020.01115.01024.00.2230.2048174.020.01127.01029.00.22540.20580.00259998577829
175.020.0776.04783.00.15520.9566175.020.0774.04828.00.15480.96560.00900888200518
176.020.04265.02283.00.8530.4566nannannannannannannan
177.020.02403.03866.00.48060.7732177.020.02445.03843.00.4890.76860.00957638905057
178.020.04830.02492.00.9660.4984178.020.04827.02477.00.96540.49540.00305940728311
179.020.01771.01416.00.35420.2832179.020.01758.01386.00.35160.27720.00653910072732
180.020.04508.03953.00.90160.7906180.020.04496.03935.00.89920.7870.0043265353746
181.020.0762.0850.00.15240.17nannannannannannannan
182.020.02628.03103.00.52560.6206nannannannannannannan
183.020.02690.0815.00.5380.163nannannannannannannan
184.020.01565.04224.00.3130.8448184.020.01567.04228.00.31340.84560.000894407728799
185.020.0138.01009.00.02760.2018185.020.0146.0998.00.02920.19960.00272028832815
186.020.03591.0342.00.71820.0684186.020.03597.0355.00.71940.0710.00286356384052
187.020.03891.0226.00.77820.0452187.020.03906.0222.00.78120.04440.00310483405312
188.020.02653.03270.00.53060.654188.020.02620.03238.00.5240.64760.00919317030075
189.020.04093.01771.00.81860.3542189.020.04099.01758.00.81980.35160.00286355467414
190.020.01824.02990.00.36480.598190.020.01827.02998.00.36540.59960.0017087892441
191.020.02555.03211.00.5110.6422191.020.02581.03191.00.51620.63820.00656023049936
192.020.03858.01677.00.77160.3354192.020.03869.01627.00.77380.32540.0102391327291
193.020.0665.02906.00.1330.5812193.020.0686.02909.00.13720.58180.00424242655462
194.020.0226.04757.00.04520.9514194.020.0207.04762.00.04140.95240.00392886938782
195.020.04134.02905.00.82680.581195.020.04101.02877.00.82020.57540.0086553777527
196.020.02044.02495.00.40880.499nannannannannannannan
197.020.02518.03228.00.50360.6456197.020.02493.03207.00.49860.64140.00652968962728
198.020.02370.02214.00.4740.4428198.020.02366.02214.00.47320.44280.00079997610936
199.020.02695.0189.00.5390.0378199.020.02690.0149.00.5380.02980.00806225772662
200.020.02536.0590.00.50720.118200.020.02520.0588.00.5040.11760.00322489638814
201.020.03937.0333.00.78740.0666201.020.03904.0335.00.78080.0670.00661210562452
202.020.0741.04069.00.14820.8138202.020.0760.04060.00.1520.8120.00420441357633
203.020.04799.04146.00.95980.8292203.020.04804.04141.00.96080.82820.00141413960431
204.020.04926.04669.00.98520.9338nannannannannannannan
205.020.02259.03962.00.45180.7924205.020.02279.03970.00.45580.7940.00430777595923
206.020.01125.02598.00.2250.5196nannannannannannannan
207.020.01552.069.00.31040.0138207.020.01550.077.00.310.01540.00164924224709
208.020.03039.03116.00.60780.6232208.020.03051.03103.00.61020.62060.00353826531208
209.020.04291.02278.00.85820.4556209.020.04279.02265.00.85580.4530.00353831003137
210.020.04919.04270.00.98380.854210.020.04956.04278.00.99120.85560.00757019236787
211.020.0353.03582.00.07060.7164211.020.0379.03613.00.07580.72260.00809170786303
212.020.01781.0644.00.35620.1288212.020.01784.0649.00.35680.12980.00116618959291
213.020.0616.04046.00.12320.8092nannannannannannannan
214.020.02966.02475.00.59320.495nannannannannannannan
215.020.0261.02146.00.05220.4292215.020.0275.02141.00.0550.42820.0029731399388
216.020.04198.04509.00.83960.9018216.020.04214.04489.00.84280.89780.00512225289375
217.020.03671.02677.00.73420.5354217.020.03638.02725.00.72760.5450.0116497265147
218.020.03042.0992.00.60840.1984218.020.03051.0978.00.61020.19560.00332865764184
219.020.03601.04397.00.72020.8794219.020.03583.04387.00.71660.87740.00411788223917
220.020.01572.01247.00.31440.2494nannannannannannannan
221.020.02285.03073.00.4570.61467.020.02286.03068.00.45720.61360.00101980164988
222.020.04790.03585.00.9580.717nannannannannannannan
223.020.02557.0313.00.51140.062620.020.02431.0365.00.48620.0730.0272616783971
224.020.04185.02669.00.8370.5338nannannannannannannan
225.020.01458.03944.00.29160.7888nannannannannannannan
226.020.0732.04329.00.14640.8658nannannannannannannan
227.020.02742.02004.00.54840.4008227.020.02738.01984.00.54760.39680.00407921181042
228.020.01962.02562.00.39240.5124228.020.01958.02574.00.39160.51480.00252981196437
229.020.02725.01683.00.5450.3366229.020.02750.01678.00.550.33560.00509893515797
230.020.01543.03607.00.30860.7214230.020.01556.03606.00.31120.72120.00260747554195
231.020.01415.0807.00.2830.1614nannannannannannannan
232.020.0302.02438.00.06040.4876232.020.0262.02428.00.05240.48560.00824593135825
233.020.03962.03221.00.79240.6442233.020.03948.03201.00.78960.64020.00488252138699
234.020.02140.03582.00.4280.7164234.020.02165.03614.00.4330.72280.00812133343269
235.020.0831.03066.00.16620.6132nannannannannannannan
236.020.0644.03564.00.12880.7128nannannannannannannan
237.020.0827.03722.00.16540.7444237.020.0845.03679.00.1690.73580.00932297364972
238.020.01028.01509.00.20560.3018238.020.01044.01533.00.20880.30660.00576885702247
239.020.0820.02463.00.1640.4926239.020.0816.02486.00.16320.49720.00466904189864
240.020.01145.04373.00.2290.8746240.020.01185.04339.00.2370.86780.01049881918
241.020.02950.03818.00.590.7636nannannannannannannan
242.020.01431.02497.00.28620.4994242.020.01414.02507.00.28280.50140.00394450481909
243.020.04689.01859.00.93780.3718nannannannannannannan
244.020.04519.03139.00.90380.6278244.020.04511.03161.00.90220.63220.00468184691125
245.020.02062.01063.00.41240.2126245.020.02073.01077.00.41460.21540.0035608892822
246.020.0176.04677.00.03520.9354nannannannannannannan
247.020.0461.03241.00.09220.6482247.020.0460.03255.00.0920.6510.00280713285373
248.020.01852.03374.00.37040.6748248.020.01866.03373.00.37320.67460.00280694012999
249.020.03272.04471.00.65440.8942249.020.03287.04479.00.65740.89580.0033996770615
250.020.017.0381.00.00340.0762nannannannannannannan

In [141]:
aTable.from_pandas(A).show_in_notebook()


Out[141]:
<aTable length=250>
idrxyradec
120446345920.89260.9184
220440941160.88180.8232
320424817700.84960.354
420189537860.3790.7572
520187622360.37520.4472
62027606020.5520.1204
720230230810.46040.6162
820472446150.94480.923
920434046280.8680.9256
1020166611030.33320.2206
1120352543080.7050.8616
1220426136140.85220.7228
1320249145390.49820.9078
1420473145490.94620.9098
15202152200.43040.004
1620170439850.34080.797
172013812410.27620.0482
1820107043910.2140.8782
1920319241040.63840.8208
202042373430.84740.0686
212014228040.28440.1608
222017665620.35320.1124
2320103541410.2070.8282
242035419210.07080.3842
25204551840.91020.0168
2620293610990.58720.2198
2720432538440.8650.7688
282044510830.0890.2166
292063920020.12780.4004
302040709860.8140.1972
312088613430.17720.2686
322044487760.88960.1552
332016351420.3270.0284
3420188714720.37740.2944
3520166245130.33240.9026
3620106937030.21380.7406
3720417220460.83440.4092
3820191434780.38280.6956
392011236170.02240.7234
4020166735860.33340.7172
412032642290.06520.8458
4220446515250.8930.305
4320322740370.64540.8074
4420225229150.45040.583
4520384035870.7680.7174
462016011490.32020.0298
4720437026720.8740.5344
48202386680.04760.1336
492026909180.5380.1836
50208837130.17660.1426
5120141244510.28240.8902
5220223741330.44740.8266
5320354541360.7090.8272
5420107520520.2150.4104
55201650540.330.0108
562070826050.14160.521
572028496450.56980.129
582025347410.50680.1482
5920133048460.2660.9692
602019642690.39280.0538
612020184280.40360.0856
6220455929310.91180.5862
6320352843960.70560.8792
6420102947640.20580.9528
6520340839160.68160.7832
662061834910.12360.6982
67209102490.1820.0498
6820287140990.57420.8198
6920214139480.42820.7896
7020471826450.94360.529
7120236149590.47220.9918
7220291410560.58280.2112
7320214715890.42940.3178
742049147370.98280.1474
752055528670.1110.5734
762054325660.10860.5132
7720248525980.4970.5196
7820420742400.84140.848
7920170430780.34080.6156
8020497241030.99440.8206
8120422642690.84520.8538
822053427460.10680.5492
832045488770.90960.1754
8420487122670.97420.4534
8520480734090.96140.6818
862028527750.57040.155
872040961220.81920.0244
882064814820.12960.2964
892063721130.12740.4226
9020468923700.93780.474
9120114316990.22860.3398
9220472935390.94580.7078
9320289546910.5790.9382
9420343221500.68640.43
9520177649780.35520.9956
962073610400.14720.208
9720481611520.96320.2304
9820133545100.2670.902
9920355425510.71080.5102
10020464232580.92840.6516
10120253126950.50620.539
1022082510070.1650.2014
1032069524490.1390.4898
1042021036880.0420.7376
10520243713000.48740.26
10620429513780.8590.2756
10720228210870.45640.2174
10820319311440.63860.2288
10920459837570.91960.7514
110204918490.00980.3698
11120155947950.31180.959
11220213245720.42640.9144
11320284232780.56840.6556
11420441932220.88380.6444
1152033126200.66240.124
1162064646070.12920.9214
11720209445500.41880.91
1182061028720.1220.5744
1192039124280.78240.0856
1202031408550.6280.171
12120618230.12360.0046
12220307612810.61520.2562
12320338138460.67620.7692
12420442917610.88580.3522
1252022224950.04440.499
12620367512360.7350.2472
12720102127890.20420.5578
12820478837200.95760.744
1292046817810.09360.3562
13020313143400.62620.868
1312020407640.4080.1528
13220330725870.66140.5174
1332020606480.4120.1296
134202268820.04520.1764
135202843370.56860.0074
13620412840310.82560.8062
1372095522180.1910.4436
1382094715160.18940.3032
13920325221190.65040.4238
14020161930520.32380.6104
14120305623890.61120.4778
1422021147280.04220.9456
143201558190.0310.1638
1442040216700.08040.334
1452029439250.05880.785
14620193024720.3860.4944
14720291015320.5820.3064
14820327626500.65520.53
14920340932090.68180.6418
1502010406750.2080.135
15120337946330.67580.9266
1522039748040.79480.1608
15320398225320.79640.5064
15420213610490.42720.2098
15520351012020.7020.2404
15620361110290.72220.2058
15720345912490.69180.2498
15820189717210.37940.3442
1592036237520.07240.7504
16020397144960.79420.8992
16120260322860.52060.4572
16220472942380.94580.8476
1632018137470.36260.1494
1642034361760.68720.0352
16520197047630.3940.9526
16620140438370.28080.7674
16720175726360.35140.5272
16820107539350.2150.787
16920282839740.56560.7948
1702029711560.05940.2312
1712062240370.12440.8074
17220374118960.74820.3792
1732096149130.19220.9826
17420111510240.2230.2048
1752077647830.15520.9566
17620426522830.8530.4566
17720240338660.48060.7732
17820483024920.9660.4984
17920177114160.35420.2832
18020450839530.90160.7906
181207628500.15240.17
18220262831030.52560.6206
1832026908150.5380.163
18420156542240.3130.8448
1852013810090.02760.2018
1862035913420.71820.0684
1872038912260.77820.0452
18820265332700.53060.654
18920409317710.81860.3542
19020182429900.36480.598
19120255532110.5110.6422
19220385816770.77160.3354
1932066529060.1330.5812
1942022647570.04520.9514
19520413429050.82680.581
19620204424950.40880.499
19720251832280.50360.6456
19820237022140.4740.4428
1992026951890.5390.0378
2002025365900.50720.118
2012039373330.78740.0666
2022074140690.14820.8138
20320479941460.95980.8292
20420492646690.98520.9338
20520225939620.45180.7924
20620112525980.2250.5196
207201552690.31040.0138
20820303931160.60780.6232
20920429122780.85820.4556
21020491942700.98380.854
2112035335820.07060.7164
2122017816440.35620.1288
2132061640460.12320.8092
21420296624750.59320.495
2152026121460.05220.4292
21620419845090.83960.9018
21720367126770.73420.5354
2182030429920.60840.1984
21920360143970.72020.8794
22020157212470.31440.2494
22120228530730.4570.6146
22220479035850.9580.717
2232025573130.51140.0626
22420418526690.8370.5338
22520145839440.29160.7888
2262073243290.14640.8658
22720274220040.54840.4008
22820196225620.39240.5124
22920272516830.5450.3366
23020154336070.30860.7214
2312014158070.2830.1614
2322030224380.06040.4876
23320396232210.79240.6442
23420214035820.4280.7164
2352083130660.16620.6132
2362064435640.12880.7128
2372082737220.16540.7444
23820102815090.20560.3018
2392082024630.1640.4926
24020114543730.2290.8746
24120295038180.590.7636
24220143124970.28620.4994
24320468918590.93780.3718
24420451931390.90380.6278
24520206210630.41240.2126
2462017646770.03520.9354
2472046132410.09220.6482
24820185233740.37040.6748
24920327244710.65440.8942
25020173810.00340.0762

In [ ]: