Edit a FITS header#

Authors#

Adrian Price-Whelan, Adam Ginsburg, Stephanie T. Douglas, Kelle Cruz, Saima Siddiqui, Zihao Chen, Lúthien Liu

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:

  1. fits.open allows us to look more generally at our data.

  2. fits.getheader will give you the same output as fits_inf[0].header. By changing the HDU number to fits_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:

  1. ‘RA’ for the Right Ascension of M31

  2. ‘DEC’ for the Declination of M31

  3. ‘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: