0
# Table Operations
1
2
FITS table data handling functionality supporting both binary and ASCII tables with advanced features including column operations, row filtering, variable-length columns, table modifications, and efficient data access patterns.
3
4
## Capabilities
5
6
### TableHDU Class
7
8
Handler for FITS binary table extensions with comprehensive table operations and data manipulation capabilities.
9
10
```python { .api }
11
class TableHDU:
12
def read(self, columns=None, rows=None, vstorage='fixed', **kwargs):
13
"""
14
Read table data as structured array.
15
16
Parameters:
17
- columns: list/str, column names to read
18
- rows: list/array, specific rows to read
19
- vstorage: str, variable length storage ('fixed' or 'object')
20
- **kwargs: additional read options
21
22
Returns:
23
numpy structured array
24
"""
25
26
def read_column(self, col, rows=None, vstorage='fixed', **kwargs):
27
"""
28
Read single column data.
29
30
Parameters:
31
- col: str/int, column name or number
32
- rows: list/array, specific rows to read
33
- vstorage: str, variable length storage method
34
- **kwargs: additional options
35
36
Returns:
37
numpy array
38
"""
39
40
def read_columns(self, columns, rows=None, **kwargs):
41
"""
42
Read multiple columns efficiently.
43
44
Parameters:
45
- columns: list, column names to read
46
- rows: list/array, specific rows to read
47
- **kwargs: additional options
48
49
Returns:
50
numpy structured array
51
"""
52
53
def read_rows(self, rows, columns=None, **kwargs):
54
"""
55
Read specific rows.
56
57
Parameters:
58
- rows: list/array, row indices to read
59
- columns: list, columns to include
60
- **kwargs: additional options
61
62
Returns:
63
numpy structured array
64
"""
65
66
def read_slice(self, firstrow, lastrow, columns=None, **kwargs):
67
"""
68
Read row range slice.
69
70
Parameters:
71
- firstrow: int, first row index
72
- lastrow: int, last row index
73
- columns: list, columns to include
74
- **kwargs: additional options
75
76
Returns:
77
numpy structured array
78
"""
79
80
def write(self, data, firstrow=0, **kwargs):
81
"""
82
Write/overwrite table data.
83
84
Parameters:
85
- data: structured array/dict/list, table data
86
- firstrow: int, starting row for writing
87
- **kwargs: additional write options
88
"""
89
90
def write_column(self, column, data, firstrow=0, **kwargs):
91
"""
92
Write single column data.
93
94
Parameters:
95
- column: str/int, column name or number
96
- data: array-like, column data
97
- firstrow: int, starting row
98
- **kwargs: additional options
99
"""
100
101
def write_var_column(self, column, data, **kwargs):
102
"""
103
Write variable length column.
104
105
Parameters:
106
- column: str/int, column name or number
107
- data: list/object array, variable length data
108
- **kwargs: additional options
109
"""
110
111
def append(self, data, **kwargs):
112
"""
113
Append rows to existing table.
114
115
Parameters:
116
- data: structured array/dict/list, new rows
117
- **kwargs: additional options
118
"""
119
120
def insert_column(self, name, data, colnum=None, **kwargs):
121
"""
122
Insert new column into table.
123
124
Parameters:
125
- name: str, column name
126
- data: array-like, column data
127
- colnum: int, column position (default: append)
128
- **kwargs: column format options
129
"""
130
131
def delete_rows(self, rows):
132
"""
133
Delete specified rows.
134
135
Parameters:
136
- rows: list/array, row indices to delete
137
"""
138
139
def resize(self, nrows, front=False):
140
"""
141
Change table size.
142
143
Parameters:
144
- nrows: int, new number of rows
145
- front: bool, add/remove rows at front
146
"""
147
148
def where(self, expression, **kwargs):
149
"""
150
Query table with WHERE expression.
151
152
Parameters:
153
- expression: str, SQL-like WHERE clause
154
- **kwargs: additional options
155
156
Returns:
157
numpy array, row indices matching expression
158
"""
159
160
def get_nrows(self):
161
"""
162
Get number of rows.
163
164
Returns:
165
int, number of rows
166
"""
167
168
def get_colnames(self):
169
"""
170
Get column names.
171
172
Returns:
173
list of str, column names
174
"""
175
176
def get_colname(self, colnum):
177
"""
178
Get column name by number.
179
180
Parameters:
181
- colnum: int, column number (0-based)
182
183
Returns:
184
str, column name
185
"""
186
187
def get_vstorage(self):
188
"""
189
Get variable length storage method.
190
191
Returns:
192
str, storage method ('fixed' or 'object')
193
"""
194
195
def get_rec_dtype(self, **kwargs):
196
"""
197
Get record array dtype.
198
199
Parameters:
200
- **kwargs: dtype options
201
202
Returns:
203
numpy dtype, structured array dtype
204
"""
205
206
def get_rec_column_descr(self):
207
"""
208
Get column descriptions for structured array.
209
210
Returns:
211
list, column descriptors
212
"""
213
214
def __getitem__(self, key):
215
"""
216
Access table data by column/row.
217
218
Parameters:
219
- key: str/int/tuple/slice, column name, row index, or slice
220
221
Returns:
222
numpy array or structured array
223
"""
224
225
def __iter__(self):
226
"""
227
Iterate over table rows with buffering.
228
229
Yields:
230
numpy structured array, individual rows
231
"""
232
233
# Inherited from HDUBase
234
def get_info(self):
235
"""Get complete HDU information."""
236
237
def get_offsets(self):
238
"""Get byte offsets (header_start, data_start, data_end)."""
239
240
def get_extnum(self):
241
"""Get extension number."""
242
243
def get_extname(self):
244
"""Get extension name."""
245
246
def get_extver(self):
247
"""Get extension version."""
248
249
def get_exttype(self, num=False):
250
"""Get extension type."""
251
252
def read_header(self):
253
"""Read header as FITSHDR object."""
254
255
def write_key(self, name, value, comment=""):
256
"""Write single header keyword."""
257
258
def write_keys(self, records, clean=True):
259
"""Write multiple header keywords."""
260
261
def write_checksum(self):
262
"""Write DATASUM/CHECKSUM keywords."""
263
264
def verify_checksum(self):
265
"""Verify data integrity."""
266
```
267
268
### AsciiTableHDU Class
269
270
Handler for FITS ASCII table extensions, inheriting from TableHDU with ASCII-specific operations.
271
272
```python { .api }
273
class AsciiTableHDU(TableHDU):
274
"""ASCII table HDU with same interface as TableHDU."""
275
```
276
277
### Table Data Types
278
279
```python { .api }
280
# Supported column data types:
281
# - 'L': Logical (boolean)
282
# - 'B': Unsigned byte (uint8)
283
# - 'I': 16-bit integer (int16)
284
# - 'J': 32-bit integer (int32)
285
# - 'K': 64-bit integer (int64)
286
# - 'A': Character string
287
# - 'E': Single precision float (float32)
288
# - 'D': Double precision float (float64)
289
# - 'C': Single precision complex (complex64)
290
# - 'M': Double precision complex (complex128)
291
# - 'P': Variable length array pointer
292
# - 'Q': Variable length array pointer (64-bit)
293
```
294
295
## HDU Type Constants
296
297
```python { .api }
298
BINARY_TBL = 2
299
ASCII_TBL = 1
300
```
301
302
## Usage Examples
303
304
### Reading Tables
305
306
```python
307
import fitsio
308
import numpy as np
309
310
# Read entire table
311
data = fitsio.read('catalog.fits', ext=1)
312
print(f"Table shape: {data.shape}")
313
print(f"Columns: {data.dtype.names}")
314
315
# Read specific columns
316
coords = fitsio.read('catalog.fits', ext=1, columns=['ra', 'dec'])
317
318
# Read specific rows
319
subset = fitsio.read('catalog.fits', ext=1, rows=[0, 10, 100])
320
321
# Read with FITS object for more control
322
with fitsio.FITS('catalog.fits') as fits:
323
table = fits[1]
324
325
# Get table information
326
nrows = table.get_nrows()
327
colnames = table.get_colnames()
328
329
print(f"Table has {nrows} rows and columns: {colnames}")
330
331
# Read different ways
332
all_data = table.read()
333
single_col = table.read_column('flux')
334
multi_col = table.read_columns(['x', 'y', 'flux'])
335
row_slice = table.read_slice(100, 200)
336
```
337
338
### Table Slicing and Access
339
340
```python
341
import fitsio
342
343
with fitsio.FITS('catalog.fits') as fits:
344
table = fits[1]
345
346
# Column access
347
x_values = table['x'][:] # All x values
348
y_values = table['y'][:] # All y values
349
coords = table['x', 'y'][:] # Multiple columns
350
351
# Row access
352
first_100 = table[:100] # First 100 rows
353
every_10th = table[::10] # Every 10th row
354
specific_rows = table[[5, 15, 25]] # Specific row indices
355
356
# Combined access
357
subset = table['flux'][100:200] # Column slice
358
multi_subset = table['x', 'y'][50:150] # Multiple columns, row range
359
```
360
361
### Writing Tables
362
363
```python
364
import fitsio
365
import numpy as np
366
367
# Create structured array
368
nrows = 1000
369
data = np.zeros(nrows, dtype=[
370
('id', 'i4'),
371
('ra', 'f8'),
372
('dec', 'f8'),
373
('flux', 'f4'),
374
('flag', 'bool'),
375
('name', 'U20')
376
])
377
378
# Fill with data
379
data['id'] = np.arange(nrows)
380
data['ra'] = np.random.uniform(0, 360, nrows)
381
data['dec'] = np.random.uniform(-90, 90, nrows)
382
data['flux'] = np.random.lognormal(0, 1, nrows)
383
data['flag'] = np.random.choice([True, False], nrows)
384
data['name'] = [f'object_{i:04d}' for i in range(nrows)]
385
386
# Write table
387
fitsio.write('new_catalog.fits', data)
388
389
# Write with header
390
header = fitsio.FITSHDR([
391
{'name': 'EXTNAME', 'value': 'CATALOG', 'comment': 'Table name'},
392
{'name': 'COORDSYS', 'value': 'EQUATORIAL', 'comment': 'Coordinate system'}
393
])
394
fitsio.write('catalog_with_header.fits', data, header=header)
395
```
396
397
### Table Modifications
398
399
```python
400
import fitsio
401
import numpy as np
402
403
with fitsio.FITS('catalog.fits', 'rw') as fits:
404
table = fits[1]
405
406
# Append new rows
407
new_data = np.zeros(50, dtype=table.get_rec_dtype())
408
new_data['id'] = np.arange(1000, 1050)
409
table.append(new_data)
410
411
# Insert new column
412
magnitudes = np.random.uniform(15, 25, table.get_nrows())
413
table.insert_column('magnitude', magnitudes)
414
415
# Overwrite specific rows
416
updated_rows = np.zeros(10, dtype=table.get_rec_dtype())
417
table.write(updated_rows, firstrow=100)
418
419
# Write to specific column
420
new_fluxes = np.random.lognormal(0, 1, table.get_nrows())
421
table.write_column('flux', new_fluxes)
422
423
# Delete rows
424
table.delete_rows([5, 15, 25]) # Delete specific rows
425
426
# Resize table
427
table.resize(800) # Truncate to 800 rows
428
```
429
430
### Variable Length Columns
431
432
```python
433
import fitsio
434
import numpy as np
435
436
# Create data with variable length arrays
437
nrows = 100
438
data = np.zeros(nrows, dtype=[
439
('id', 'i4'),
440
('measurements', 'O'), # Object array for variable length
441
('notes', 'O') # Object array for variable strings
442
])
443
444
data['id'] = np.arange(nrows)
445
446
# Variable length numeric arrays
447
for i in range(nrows):
448
n_measurements = np.random.randint(1, 20)
449
data['measurements'][i] = np.random.random(n_measurements)
450
data['notes'][i] = f"Object {i} has {n_measurements} measurements"
451
452
# Write with object storage
453
fitsio.write('variable_length.fits', data)
454
455
# Read with object storage
456
var_data = fitsio.read('variable_length.fits', vstorage='object')
457
print(f"First object measurements: {var_data['measurements'][0]}")
458
459
# Read with fixed storage (padded arrays)
460
fixed_data = fitsio.read('variable_length.fits', vstorage='fixed')
461
```
462
463
### Table Queries and Filtering
464
465
```python
466
import fitsio
467
468
with fitsio.FITS('catalog.fits') as fits:
469
table = fits[1]
470
471
# Query with WHERE clause
472
bright_stars = table.where("flux > 100.0")
473
northern = table.where("dec > 0")
474
complex_query = table.where("flux > 50 && dec > -30 && dec < 30")
475
476
# Use query results to read data
477
bright_data = table.read(rows=bright_stars)
478
479
# Combine with column selection
480
coords_north = table.read(columns=['ra', 'dec'], rows=northern)
481
482
# Multiple conditions
483
good_objects = table.where("flux > 10 && flag == 1")
484
print(f"Found {len(good_objects)} good objects")
485
```
486
487
### Working with Different Table Formats
488
489
```python
490
import fitsio
491
import numpy as np
492
493
# Create different data structures
494
# 1. List of arrays
495
x_data = np.random.random(100)
496
y_data = np.random.random(100)
497
names = [f'star_{i}' for i in range(100)]
498
499
# Write from list with names
500
fitsio.write('from_lists.fits', [x_data, y_data, names],
501
names=['x', 'y', 'name'])
502
503
# 2. Dictionary of arrays
504
data_dict = {
505
'x': x_data,
506
'y': y_data,
507
'name': names
508
}
509
fitsio.write('from_dict.fits', data_dict)
510
511
# 3. Record array (most flexible)
512
rec_data = np.rec.fromarrays([x_data, y_data, names],
513
names=['x', 'y', 'name'])
514
fitsio.write('from_recarray.fits', rec_data)
515
```
516
517
### Table Iteration and Large Tables
518
519
```python
520
import fitsio
521
522
# Efficient iteration over large tables
523
with fitsio.FITS('large_catalog.fits', iter_row_buffer=1000) as fits:
524
table = fits[1]
525
526
# Process table in chunks
527
for i, row in enumerate(table):
528
if i % 10000 == 0:
529
print(f"Processed {i} rows")
530
531
# Process individual row
532
if row['flux'] > 100:
533
# Do something with bright objects
534
pass
535
536
# Alternative: read in chunks manually
537
nrows = table.get_nrows()
538
chunk_size = 10000
539
540
for start in range(0, nrows, chunk_size):
541
end = min(start + chunk_size, nrows)
542
chunk = table.read_slice(start, end)
543
544
# Process chunk
545
bright = chunk[chunk['flux'] > 100]
546
print(f"Chunk {start}-{end}: found {len(bright)} bright objects")
547
```
548
549
### Advanced Table Operations
550
551
```python
552
import fitsio
553
import numpy as np
554
555
with fitsio.FITS('catalog.fits', 'rw') as fits:
556
table = fits[1]
557
558
# Get complete column information
559
dtype = table.get_rec_dtype()
560
column_desc = table.get_rec_column_descr()
561
562
print(f"Table dtype: {dtype}")
563
print(f"Column descriptions: {column_desc}")
564
565
# Case sensitivity control
566
table.case_sensitive = True
567
table.lower = False
568
table.upper = False
569
570
# Work with array columns (multi-dimensional)
571
# Add column with 2D array data
572
array_col = np.random.random((table.get_nrows(), 3, 3))
573
table.insert_column('covariance', array_col)
574
575
# Read array column
576
cov_matrices = table['covariance'][:]
577
print(f"Covariance matrices shape: {cov_matrices.shape}")
578
```