Search code examples
pythonlistastropyfits

Python astropy: table and columns objects


I am playing around with Tables object from astropy.table module.

The piece of code below shows the type of data I am dealing with:

In [44]: table             
Out[44]: 
<Table length=9>
defocus  source   Chi2  xcentroid ycentroid  FWHMx   FWHMy    Peak 
float32 float32 float32  float32   float32  float32 float32 float32
------- ------- ------- --------- --------- ------- ------- -------
   -0.3     0.0 346.648    2056.5     55.82 11.8635 11.8635 182.277
   -0.3     4.0 148.302   2056.49   1911.02 6.66554 6.66554 299.074
   -0.3     8.0 347.208   2056.51   3922.99 6.83129 6.83129 326.476
  -0.26     0.0 318.489    2056.5   55.8803  10.206  10.206 195.055
  -0.26     4.0 152.501   2056.51   1911.02  6.9012  6.9012 244.817
  -0.26     8.0 285.845   2056.49   3922.99  7.7939  7.7939 236.194
  -0.22     0.0 264.113    2056.5   55.9053 8.79704 8.79704 187.376
  -0.22     4.0 163.228    2056.5   1911.02 2.43716 2.43716 402.182
  -0.22     8.0 230.017    2056.5   3922.99 6.70312 6.70312 235.376

In [45]: type(table)       
Out[45]: astropy.table.table.Table

In [46]: cols=table.columns

In [47]: type(cols)
Out[47]: astropy.table.table.TableColumns

In [48]: type(cols[0])
Out[48]: astropy.table.column.Column 

In [50]: mylist_1 = [x for x in cols]

In [51]: mylist_2 = [cols[k] for k in range(len(cols))]

In [52]: type(mylist_1[0])
Out[52]: str

In [53]: type(mylist_2[0])
Out[53]: astropy.table.column.Column

In [54]: mylist_1[0]
Out[54]: 'defocus'

In [55]: mylist_2[0]
Out[55]: 
<Column name='defocus' dtype='float32' length=9>
 -0.3
 -0.3
 -0.3
-0.26
-0.26
-0.26
-0.22
-0.22
-0.22

I was expecting that the two lines:

mylist_1 = [x for x in cols]

and

mylist_2 = [cols[k] for k in range(len(cols))]

would de exactly the same thing (the second one being less elegant), but it doesn't, as you can see in the outputs above (mylist_1 contains only the columns names, and not the columns themselves). Why is that so? Is there something I don't really understand about my "cols" object?

Thanks for your insights.

(I ran into this while trying to write my table to a fits file - using astropy.io.fits - which requires building an appropriate columns list, which isn't as obvious as one would expect...)


Solution

  • Your loops iterate slightly different (but equivalent) over the columns. But you append different things in the list comprehension. The columns are dict-like so they have an index and an associated element:

    Consider a table like this:

    from astropy.table import Table
    
    data_rows = [(1, 2.0, 'x'),
                 (4, 5.0, 'y'),
                 (5, 8.2, 'z')]
    t = Table(rows=data_rows, names=('a', 'b', 'c'), meta={'name': 'first table'},
              dtype=('i4', 'f8', 'S1'))
    cols=t.columns
    

    You iterate over the column indices by using:

    [x for x in cols]
    # ['a', 'b', 'c']
    

    or

    [k for k in range(len(cols))]
    # [0, 1, 2]
    

    These seem different but cols[0] == cols['a'] so these are just two different ways to index your columns.

    But if you want to iterate over the actual columns not their indices you could do:

    [cols[x] for x in cols]
    # [<Column name='a' dtype='int32' length=3>1   4   5, 
    # <Column name='b' dtype='float64' length=3>2.0  5.0   8.2,
    # <Column name='c' dtype='bytes1' length=3> x   y    z]
    

    or:

    [cols[k] for k in range(len(cols))]
    # [<Column name='a' dtype='int32' length=3>1   4   5, 
    # <Column name='b' dtype='float64' length=3>2.0  5.0   8.2,
    # <Column name='c' dtype='bytes1' length=3> x   y    z]
    

    This time we actually insert the indexed column instead of inserting the index.

    This is however no means to your end with the conversion to FITS but you can always save your Table directly into any of their formats see their supported formats.

    For example writing to a fits is as simple as using:

    t.write('new_table.fits')
    

    or

    t.write('new_table.fits', format='fits')