Edit a FITS header#
Learning Goals#
Read a FITS file
Retrieve FITS header metadata
Edit the FITS header
Write the modified file as a FITS file
Keywords#
FITS, file input/output
Companion Content#
To learn more about the FITS file format check out: astropy.fits.io
For interacting with simple image FITS files see the CCDATA.read() function.
Summary#
FITS is a useful way of storing and archiving information through multidimensional arrays. Within a FITS file format, the header contains “cards” of information including a keyword, a value, and a comment as a way to introduce the data block that follows. Together, the header and data are contained together as a header data unit, or HDU.
In this tutorial we will begin with exploring the different ways we can read information from a FITS file, how to read and edit the header, and then write it out back to disk. For this example we’re going to change the OBJECT keyword.
from astropy.io import fits
The astropy.io.fits package provides a lot of flexibility for reading FITS files and headers. fits.getheader() is a dedicated function for reading the header. In this example, we are reading the primary HDU (which has the HDU number 0). The output will show you all the cards that the primary HDU has.
hdu_number = 0 # HDU means header data unit
fits.getheader("input_file.fits", hdu_number)
SIMPLE = T / conforms to FITS standard
BITPIX = -64 / array data type
NAXIS = 2 / number of array dimensions
NAXIS1 = 100
NAXIS2 = 100
EXTEND = T
OBJECT = 'KITTEN '
MYHDRKW = 'My Header Keyword'
Thought Question: How many cards does the primary HDU have?
When all you need is to read in part of the FITS file, convenience functions are available to facilitare this. fits.getdata() reads only the data from a FITS file, but with the header=True argument, it will also read the header.
data, header = fits.getdata("input_file.fits", header=True)
Now we know getdata() can get both the data and the header, so it’s a useful
command to remember. The primary HDU of a FITS file can contain image data,
so the data is now stored in a numpy array. The header is stored in an
object that acts like a standard Python dictionary, except that the keys are case-insensitive.
If the FITS file you’re examining and editing might have multiple HDU’s (extensions), you can specify the extension like this:
data1, header1 = fits.getdata("input_file.fits", ext=1, header=True)
This will get you the data and header associated with the index=1 extension
in the FITS file. Without specifying a number, getdata() will get the
0th extension (equivalent to saying ext=0).
There are a lot of other useful commands to remember for reading FITS files:
fits.openallows us to look more generally at our data.fits.getheaderwill give you the same output asfits_inf[0].header. By changing the HDU number tofits_inf[1]header, what will the output be?
# hdu_number = 0 is the PRIMARY HDU. How many HDUs are in this file?
fits_inf = fits.open("input_file.fits")
fits_inf.info()
fits_inf[0].header
Filename: input_file.fits
No. Name Ver Type Cards Dimensions Format
0 PRIMARY 1 PrimaryHDU 8 (100, 100) float64
1 1 ImageHDU 7 (128, 128) float64
SIMPLE = T / conforms to FITS standard
BITPIX = -64 / array data type
NAXIS = 2 / number of array dimensions
NAXIS1 = 100
NAXIS2 = 100
EXTEND = T
OBJECT = 'KITTEN '
MYHDRKW = 'My Header Keyword'
Thought Question: How many HDUS are in this file? Were you right about the number of cards in the primary HDU?
Thought Question: What will happen if you type fits_inf[2].header?
Now that we know how to read a FITS file, let’s change the header. The header is always changed via its keyword. The keywords are the upper case words to the left when you print the extracted header info. Let’s change the header to give the correct OBJECT:
header["OBJECT"] = "M31"
The keyword OBJECT was in the primary HDU. We can also change a header in another HDU like this:
hdul = fits.open("input_file.fits")
hdr = hdul[1].header
hdr["newcard"] = "a value"
Since the keyword “newcard” didn’t exist in HDU 1, it is created by attempting to change its value.
fits.writeto("output_file.fits", data, header, overwrite=True)
That’s it; you’re done!
For more complicated cases, you should consult the full documentation.
A helpful tip if you want to make a small change to a FITS file, like updating a header keyword, but you don’t want to read in and write out the whole file, which can take a while, is to use mode='update':
with fits.open("input_file.fits", mode="update") as filehandle:
filehandle[0].header["MYHDRKW"] = "My Header Keyword"
Exercise#
Read in the file you just wrote and add three header keywords:
‘RA’ for the Right Ascension of M31
‘DEC’ for the Declination of M31
‘RADECSRC’ with text indicating where you found the RA/Dec (web URL, textbook name, your photographic memory, etc.)
Then write the updated header back out to a new file: