A full featured python library to read from and write to FITS files
—
FITS header manipulation functionality providing complete control over header keywords, comments, metadata, and FITS header formatting. Supports reading, writing, and modifying headers with proper FITS standards compliance.
Container for FITS header records with dictionary-like interface and complete header management capabilities.
class FITSHDR:
def __init__(self, record_list=None):
"""
Create FITS header object.
Parameters:
- record_list: list/dict/FITSHDR, initial header records
- list of dicts with 'name', 'value', 'comment' keys
- dict of keyword-value pairs (no comments)
- another FITSHDR object
"""
def add_record(self, record):
"""
Add header record.
Parameters:
- record: dict/str/FITSRecord, header record
- dict with 'name', 'value', 'comment' keys
- FITS card string
- FITSRecord object
"""
def get_comment(self, keyword):
"""
Get comment for keyword.
Parameters:
- keyword: str, header keyword name
Returns:
str, comment text
"""
def records(self):
"""
Get all header records.
Returns:
list of dicts with 'name', 'value', 'comment' keys
"""
def keys(self):
"""
Get all keyword names.
Returns:
list of str, keyword names
"""
def delete(self, name):
"""
Delete keyword(s).
Parameters:
- name: str, keyword name to delete
"""
def clean(self, is_table=False):
"""
Remove reserved keywords.
Parameters:
- is_table: bool, whether this is table header
"""
def get(self, keyword, default=None):
"""
Get keyword value with default.
Parameters:
- keyword: str, keyword name
- default: any, default value if keyword not found
Returns:
Keyword value or default
"""
def __setitem__(self, key, value):
"""Set keyword value."""
def __getitem__(self, key):
"""Get keyword value."""
def __contains__(self, key):
"""Check if keyword exists."""
def __len__(self):
"""Number of keywords."""
def __iter__(self):
"""Iterate over keyword names."""Individual FITS header record with name, value, and comment.
class FITSRecord:
def __init__(self, record):
"""
Create FITS record.
Parameters:
- record: dict/str, record data
- dict with 'name', 'value', 'comment' keys
- FITS card string
"""Parser for FITS header card strings (80-character FITS format).
class FITSCard:
def __init__(self, card_string):
"""
Parse FITS card string.
Parameters:
- card_string: str, 80-character FITS card
"""Header operations available on HDU objects for reading and writing keywords.
class HDUBase:
def read_header(self):
"""
Read header as FITSHDR object.
Returns:
FITSHDR object
"""
def read_header_list(self):
"""
Read header as list of dicts.
Returns:
list of dicts with 'name', 'value', 'comment' keys
"""
def write_key(self, name, value, comment=""):
"""
Write single header keyword.
Parameters:
- name: str, keyword name (max 8 characters)
- value: any, keyword value
- comment: str, keyword comment
"""
def write_keys(self, records, clean=True):
"""
Write multiple header keywords.
Parameters:
- records: list/dict/FITSHDR, header records
- clean: bool, remove reserved keywords first
"""
def write_comment(self, comment):
"""
Write COMMENT record.
Parameters:
- comment: str, comment text
"""
def write_history(self, history):
"""
Write HISTORY record.
Parameters:
- history: str, history text
"""TYP_STRUC_KEY = 10 # Structural keywords
TYP_CMPRS_KEY = 20 # Compression keywords
TYP_SCAL_KEY = 30 # Scaling keywords
TYP_NULL_KEY = 40 # Null value keywords
TYP_DIM_KEY = 50 # Dimension keywords
TYP_RANG_KEY = 60 # Range keywords
TYP_UNIT_KEY = 70 # Unit keywords
TYP_DISP_KEY = 80 # Display keywords
TYP_HDUID_KEY = 90 # HDU ID keywords
TYP_CKSUM_KEY = 100 # Checksum keywords
TYP_WCS_KEY = 110 # WCS keywords
TYP_REFSYS_KEY = 120 # Reference system keywords
TYP_COMM_KEY = 130 # Comment keywords
TYP_CONT_KEY = 140 # Continued keywords
TYP_USER_KEY = 150 # User keywordsimport fitsio
# Create empty header
hdr = fitsio.FITSHDR()
# Add simple keyword
hdr['OBJECT'] = 'NGC 1234'
# Add keyword with comment
hdr.add_record({'name': 'EXPTIME', 'value': 300.0, 'comment': 'Exposure time in seconds'})
# Add from card string
hdr.add_record('FILTER = "V " / Filter used')
# Create header from list
records = [
{'name': 'TELESCOP', 'value': 'HST', 'comment': 'Telescope'},
{'name': 'INSTRUME', 'value': 'ACS', 'comment': 'Instrument'}
]
hdr = fitsio.FITSHDR(records)
# Create from dictionary (no comments)
simple_hdr = fitsio.FITSHDR({'NAXIS': 2, 'NAXIS1': 100, 'NAXIS2': 100})import fitsio
# Read header with convenience function
header = fitsio.read_header('data.fits', ext=0)
# Access keyword values
print(f"Object: {header['OBJECT']}")
print(f"Exposure time: {header.get('EXPTIME', 'Unknown')}")
# Get comment
comment = header.get_comment('EXPTIME')
# Iterate over keywords
for keyword in header:
value = header[keyword]
comment = header.get_comment(keyword)
print(f"{keyword} = {value} / {comment}")
# Get all records
all_records = header.records()import fitsio
import numpy as np
# Write data with header
image = np.random.random((100, 100))
header = fitsio.FITSHDR([
{'name': 'OBJECT', 'value': 'Test Image', 'comment': 'Object name'},
{'name': 'EXPTIME', 'value': 600.0, 'comment': 'Exposure time'},
{'name': 'FILTER', 'value': 'R', 'comment': 'Filter name'}
])
fitsio.write('output.fits', image, header=header)
# Modify existing header
with fitsio.FITS('data.fits', 'rw') as fits:
# Write individual keywords
fits[0].write_key('OBSERVER', 'John Doe', 'Observer name')
fits[0].write_key('DATE-OBS', '2023-01-15', 'Observation date')
# Write multiple keywords
new_keys = [
{'name': 'AIRMASS', 'value': 1.2, 'comment': 'Airmass'},
{'name': 'SEEING', 'value': 0.8, 'comment': 'Seeing in arcsec'}
]
fits[0].write_keys(new_keys)
# Write comments and history
fits[0].write_comment('This is a comment')
fits[0].write_history('Processed with custom pipeline')import fitsio
# Work with complex headers
with fitsio.FITS('data.fits') as fits:
hdr = fits[0].read_header()
# Check if keywords exist
if 'BSCALE' in hdr:
scale = hdr['BSCALE']
zero = hdr.get('BZERO', 0.0)
# Clean reserved keywords
hdr.clean(is_table=False)
# Get keyword list
keywords = hdr.keys()
print(f"Header has {len(keywords)} keywords")
# Delete unwanted keywords
for key in ['COMMENT', 'HISTORY']:
if key in hdr:
hdr.delete(key)
# Parse FITS cards manually
card = fitsio.FITSCard("EXPTIME = 600.0 / Exposure time in seconds")
record = fitsio.FITSRecord(card)
# Convert between formats
header_dict = {'NAXIS': 2, 'NAXIS1': 1024, 'NAXIS2': 1024}
hdr = fitsio.FITSHDR(header_dict)
record_list = hdr.records()import fitsio
with fitsio.FITS('data.fits', 'rw') as fits:
# Handle long string values (continued keywords)
long_comment = "This is a very long comment that exceeds the normal FITS card length and will be automatically split across multiple cards"
fits[0].write_key('LONGCMT', long_comment)
# Handle special characters
fits[0].write_key('FILENAME', "file's name with quotes", "File's original name")
# Preserve data types
fits[0].write_key('INTVAL', 42) # Integer
fits[0].write_key('FLOATVAL', 3.14159) # Float
fits[0].write_key('BOOLVAL', True) # Boolean
fits[0].write_key('STRVAL', 'text') # StringInstall with Tessl CLI
npx tessl i tessl/pypi-fitsio