This notebook was put together by Oliver Fraser and Amelia Brown for UW's [Astro 599](http://www.astro.washington.edu/users/vanderplas/Astr599/) course. Source and license info is on [GitHub](https://github.com/jakevdp/2013_fall_ASTR599/).

Originally you used PyFITS to work with FITS files in Python, this was a wrapper around the cfitsio library (as in "a library written in C to do FITS I/O work"). Apparently PyFITS is soon to be abandoned, but it's okay because all of PyFITS is recreated in the astropy.io.fits library. If you have code that uses pyfits, you're 99% able to use astro py with nothing more then

import astropy.io.fits as pyfits

astropy.io.fits documentation


In [1]:
import astropy.io.fits as fits

First, lets find some FITS files to play with


In [2]:
import glob
FitsFiles = glob.glob('./data/*.fit*')
print FitsFiles


['./data/andromeda_i.fit', './data/dumbbell3.fit', './data/haFlat.fits', './data/herc_r.fit', './data/NewFile.fits', './data/ring4.fit']

We already used os.path.exists() to check the existence of directories, turns out .basename() is a system independant way to remove leading directories information.


In [3]:
import os.path
myfile = FitsFiles[0]
myfile


Out[3]:
'./data/andromeda_i.fit'

We used the getdata convienence function: it opens the FITS file, parses it, and closes it, all in one line of code.


In [4]:
ImageData, ImageHdr = fits.getdata(myfile, 0, header=True)

In [5]:
ImageData.shape


Out[5]:
(512, 512)

In [6]:
help(ImageHdr)


Help on Header in module astropy.io.fits.header object:

class Header(__builtin__.object)
 |  FITS header class.  This class exposes both a dict-like interface and a
 |  list-like interface to FITS headers.
 |  
 |  The header may be indexed by keyword and, like a dict, the associated value
 |  will be returned.  When the header contains cards with duplicate keywords,
 |  only the value of the first card with the given keyword will be returned.
 |  It is also possible to use a 2-tuple as the index in the form (keyword,
 |  n)--this returns the n-th value with that keyword, in the case where there
 |  are duplicate keywords.
 |  
 |  For example:
 |  
 |      >>> header['NAXIS']
 |      0
 |      >>> header[('FOO', 1)] # Return the value of the second FOO keyword
 |      'foo'
 |  
 |  The header may also be indexed by card number:
 |  
 |      >>> header[0] # Return the value of the first card in the header
 |      'T'
 |  
 |  Commentary keywords such as HISTORY and COMMENT are special cases: When
 |  indexing the Header object with either 'HISTORY' or 'COMMENT' a list of all
 |  the HISTORY/COMMENT values is returned:
 |  
 |      >>> header['HISTORY']
 |      This is the first history entry in this header.
 |      This is the second history entry in this header.
 |      ...
 |  
 |  See the Astropy documentation for more details on working with headers.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, other)
 |  
 |  __contains__(self, keyword)
 |  
 |  __delitem__(self, key)
 |  
 |  __eq__(self, other)
 |      Two Headers are equal only if they have the exact same string
 |      representation.
 |  
 |  __getitem__(self, key)
 |  
 |  __iadd__(self, other)
 |  
 |  __init__(self, cards=[], txtfile=None)
 |      Construct a `Header` from an iterable and/or text file.
 |      
 |      Parameters
 |      ----------
 |      cards : A list of `Card` objects (optional)
 |          The cards to initialize the header with.
 |      
 |      txtfile : file path, file object or file-like object (optional)
 |          Input ASCII header parameters file **(Deprecated)**
 |          Use the Header.fromfile classmethod instead.
 |  
 |  __iter__(self)
 |  
 |  __len__(self)
 |  
 |  __repr__(self)
 |  
 |  __setitem__(self, key, value)
 |  
 |  __str__(self)
 |  
 |  add_blank(self, value='', before=None, after=None)
 |      Add a blank card.
 |      
 |      Parameters
 |      ----------
 |      value : str, optional
 |          text to be added.
 |      
 |      before : str or int, optional
 |          same as in `Header.update`
 |      
 |      after : str or int, optional
 |          same as in `Header.update`
 |  
 |  add_comment(self, value, before=None, after=None)
 |      Add a ``COMMENT`` card.
 |      
 |      Parameters
 |      ----------
 |      value : str
 |          text to be added.
 |      
 |      before : str or int, optional
 |          same as in `Header.update`
 |      
 |      after : str or int, optional
 |          same as in `Header.update`
 |  
 |  add_history(self, value, before=None, after=None)
 |      Add a ``HISTORY`` card.
 |      
 |      Parameters
 |      ----------
 |      value : str
 |          history text to be added.
 |      
 |      before : str or int, optional
 |          same as in `Header.update`
 |      
 |      after : str or int, optional
 |          same as in `Header.update`
 |  
 |  append(self, card=None, useblanks=True, bottom=False, end=False)
 |      Appends a new keyword+value card to the end of the Header, similar
 |      to list.append().
 |      
 |      By default if the last cards in the Header have commentary keywords,
 |      this will append the new keyword before the commentary (unless the new
 |      keyword is also commentary).
 |      
 |      Also differs from list.append() in that it can be called with no
 |      arguments: In this case a blank card is appended to the end of the
 |      Header.  In the case all the keyword arguments are ignored.
 |      
 |      Parameters
 |      ----------
 |      card : str, tuple
 |          A keyword or a (keyword, value, [comment]) tuple representing a
 |          single header card; the comment is optional in which case a
 |          2-tuple may be used
 |      
 |      useblanks : bool (optional)
 |          If there are blank cards at the end of the Header, replace the
 |          first blank card so that the total number of cards in the Header
 |          does not increase.  Otherwise preserve the number of blank cards.
 |      
 |      bottom : bool (optional)
 |          If True, instead of appending after the last non-commentary card,
 |          append after the last non-blank card.
 |      
 |      end : bool (optional):
 |          If True, ignore the useblanks and bottom options, and append at the
 |          very end of the Header.
 |  
 |  ascardlist(*args, **kwargs)
 |      .. deprecated:: 3.0
 |          Use the `.ascard` attribute instead.
 |      
 |      Returns a `CardList` object.
 |  
 |  clear(self)
 |      Remove all cards from the header.
 |  
 |  copy(self, strip=False)
 |      Make a copy of the :class:`Header`.
 |      
 |      Parameters
 |      ----------
 |      strip : bool (optional)
 |         If True, strip any headers that are specific to one of the standard
 |         HDU types, so that this header can be used in a different HDU.
 |      
 |      Returns
 |      -------
 |      header
 |          A new :class:`Header` instance.
 |  
 |  count(self, keyword)
 |      Returns the count of the given keyword in the header, similar to
 |      list.count() if the Header object is treated as a list of keywords.
 |      
 |      Parameters
 |      ----------
 |      keyword : str
 |          The keyword to count instances of in the header
 |  
 |  extend(self, cards, strip=True, unique=False, update=False, update_first=False, useblanks=True, bottom=False, end=False)
 |      Appends multiple keyword+value cards to the end of the header, similar
 |      to list.extend().
 |      
 |      Parameters
 |      ----------
 |      cards : iterable
 |          An iterable of (keyword, value, [comment]) tuples; see
 |          Header.append()
 |      
 |      strip : bool (optional)
 |          Remove any keywords that have meaning only to specific types of
 |          HDUs, so that only more general keywords are added from extension
 |          Header or Card list (default: True).
 |      
 |      unique : bool (optional)
 |          If `True`, ensures that no duplicate keywords are appended;
 |          keywords already in this header are simply discarded.  The
 |          exception is commentary keywords (COMMENT, HISTORY, etc.): they are
 |          only treated as duplicates if their values match.
 |      
 |      update : bool (optional)
 |          If `True`, update the current header with the values and comments
 |          from duplicate keywords in the input header.  This supercedes the
 |          `unique` argument.  Commentary keywords are treated the same as if
 |          `unique=True`.
 |      
 |      update_first : bool (optional)
 |          If the first keyword in the header is 'SIMPLE', and the first
 |          keyword in the input header is 'XTENSION', the 'SIMPLE' keyword is
 |          replaced by the 'XTENSION' keyword.  Likewise if the first keyword
 |          in the header is 'XTENSION' and the first keyword in the input
 |          header is 'SIMPLE', the 'XTENSION' keyword is replaced by the
 |          'SIMPLE' keyword.  This behavior is otherwise dumb as to whether or
 |          not the resulting header is a valid primary or extension header.
 |          This is mostly provided to support backwards compatibility with the
 |          old :meth:`Header.fromTxtFile` method, and only applies if
 |          `update=True`.
 |      
 |      useblanks, bottom, end : bool (optional)
 |          These arguments are passed to :meth:`Header.append` while appending
 |          new cards to the header.
 |  
 |  fromTxtFile(*args, **kwargs)
 |      .. deprecated:: 3.1
 |          This is equivalent to ``self.extend(Header.fromtextfile(fileobj), update=True, update_first=True)``.  Note that there there is no direct equivalent to the ``replace=True`` option since :meth:`Header.fromtextfile` returns a new :class:`Header` instance.
 |      
 |      Input the header parameters from an ASCII file.
 |      
 |      The input header cards will be used to update the current
 |      header.  Therefore, when an input card key matches a card key
 |      that already exists in the header, that card will be updated
 |      in place.  Any input cards that do not already exist in the
 |      header will be added.  Cards will not be deleted from the
 |      header.
 |      
 |      Parameters
 |      ----------
 |      fileobj : file path, file object or file-like object
 |          Input header parameters file.
 |      
 |      replace : bool, optional
 |          When `True`, indicates that the entire header should be
 |          replaced with the contents of the ASCII file instead of
 |          just updating the current header.
 |  
 |  get(self, key, default=None)
 |      Similar to :meth:`dict.get`--returns the value associated with keyword
 |      in the header, or a default value if the keyword is not found.
 |      
 |      Parameters
 |      ----------
 |      key : str
 |          A keyword that may or may not be in the header.
 |      
 |      default : (optional)
 |          A default value to return if the keyword is not found in the
 |          header.
 |      
 |      Returns
 |      -------
 |      value
 |          The value associated with the given keyword, or the default value
 |          if the keyword is not in the header.
 |  
 |  get_comment(*args, **kwargs)
 |      .. deprecated:: 3.1
 |          Use ``header['COMMENT']`` instead.
 |      
 |      Get all comment cards as a list of string texts.
 |  
 |  get_history(*args, **kwargs)
 |      .. deprecated:: 3.1
 |          Use ``header['HISTORY']`` instead.
 |      
 |      Get all history cards as a list of string texts.
 |  
 |  has_key(*args, **kwargs)
 |      .. deprecated:: 3.0
 |          Use ``key in header`` syntax instead.
 |      
 |      Like :meth:`dict.has_key`.
 |  
 |  index(self, keyword, start=None, stop=None)
 |      Returns the index if the first instance of the given keyword in the
 |      header, similar to list.index() if the Header object is treated as a
 |      list of keywords.
 |      
 |      Parameters
 |      ----------
 |      keyword : str
 |          The keyword to look up in the list of all keywords in the header
 |      
 |      start : int (optional)
 |          The lower bound for the index
 |      
 |      stop : int (optional)
 |          The upper bound for the index
 |  
 |  insert(self, idx, card, useblanks=True)
 |      Inserts a new keyword+value card into the Header at a given location,
 |      similar to list.insert().
 |      
 |      Parameters
 |      ----------
 |      idx : int
 |          The index into the the list of header keywords before which the
 |          new keyword should be inserted
 |      
 |      card : str, tuple
 |          A keyword or a (keyword, value, [comment]) tuple; see
 |          Header.append()
 |      
 |      useblanks : bool (optional)
 |          If there are blank cards at the end of the Header, replace the
 |          first blank card so that the total number of cards in the Header
 |          does not increase.  Otherwise preserve the number of blank cards.
 |  
 |  items(self)
 |      Like :meth:`dict.items`.
 |  
 |  iteritems(self)
 |      Like :meth:`dict.iteritems`.
 |  
 |  iterkeys(self)
 |      Like :meth:`dict.iterkeys`--iterating directly over the `Header`
 |      instance has the same behavior.
 |  
 |  itervalues(self)
 |      Like :meth:`dict.itervalues`.
 |  
 |  keys(self)
 |      Return a list of keywords in the header in the order they
 |      appear--like:meth:`dict.keys` but ordered.
 |  
 |  pop(self, *args)
 |      Works like :meth:`list.pop` if no arguments or an index argument are
 |      supplied; otherwise works like :meth:`dict.pop`.
 |  
 |  popitem(self)
 |  
 |  remove(self, keyword)
 |      Removes the first instance of the given keyword from the header
 |      similar to list.remove() if the Header object is treated as a list of
 |      keywords.
 |      
 |      Parameters
 |      ----------
 |      value : str
 |          The keyword of which to remove the first instance in the header
 |  
 |  rename_key(*args, **kwargs)
 |      .. deprecated:: 3.1
 |          Use :meth:`Header.rename_keyword` instead.
 |      
 |      \
 |  
 |  rename_keyword(self, oldkeyword, newkeyword, force=False)
 |      Rename a card's keyword in the header.
 |      
 |      Parameters
 |      ----------
 |      oldkeyword : str or int
 |          Old keyword or card index
 |      
 |      newkeyword : str
 |          New keyword
 |      
 |      force : bool (optional)
 |          When `True`, if the new keyword already exists in the header, force
 |          the creation of a duplicate keyword.  Otherwise a `ValueError` is
 |          raised.
 |  
 |  set(self, keyword, value=None, comment=None, before=None, after=None)
 |      Set the value and/or comment and/or position of a specified keyword.
 |      
 |      If the keyword does not already exist in the header, a new keyword is
 |      created in the specified position, or appended to the end of the header
 |      if no position is specified.
 |      
 |      This method is similar to :meth:`Header.update` prior to PyFITS 3.1.
 |      
 |      .. note::
 |          It should be noted that ``header.set(keyword, value)`` and
 |          ``header.set(keyword, value, comment)`` are equivalent to
 |          ``header[keyword] = value`` and
 |          ``header[keyword] = (value, comment)`` respectfully.
 |      
 |          New keywords can also be inserted relative to existing keywords
 |          using, for example
 |          ``header.insert('NAXIS1', ('NAXIS', 2, 'Number of axes'))`` to
 |          insert before an existing keyword, or
 |          ``header.insert('NAXIS', ('NAXIS1', 4096), after=True)`` to insert
 |          after an existing keyword.
 |      
 |          The the only advantage of using :meth:`Header.set` is that it
 |          easily replaces the old usage of :meth:`Header.update` both
 |          conceptually and in terms of function signature.
 |      
 |      Parameters
 |      ----------
 |      keyword : str
 |          A header keyword
 |      
 |      value : str (optional)
 |          The value to set for the given keyword; if None the existing value
 |          is kept, but '' may be used to set a blank value
 |      
 |      comment : str (optional)
 |          The comment to set for the given keyword; if None the existing
 |          comment is kept, but '' may be used to set a blank comment
 |      
 |      before : str, int (optional)
 |          Name of the keyword, or index of the `Card` before which
 |          this card should be located in the header.  The argument `before`
 |          takes precedence over `after` if both specified.
 |      
 |      after : str, int (optional)
 |          Name of the keyword, or index of the `Card` after which this card
 |          should be located in the header.
 |  
 |  setdefault(self, key, default=None)
 |  
 |  toTxtFile(*args, **kwargs)
 |      .. deprecated:: 3.1
 |          Use :meth:`Header.totextfile` instead.
 |      
 |      Output the header parameters to a file in ASCII format.
 |      
 |      Parameters
 |      ----------
 |      fileobj : file path, file object or file-like object
 |          Output header parameters file.
 |      
 |      clobber : bool
 |          When `True`, overwrite the output file if it exists.
 |  
 |  tofile(self, fileobj, sep='', endcard=True, padding=True, clobber=False)
 |      Writes the header to file or file-like object.
 |      
 |      By default this writes the header exactly as it would be written to a
 |      FITS file, with the END card included and padding to the next multiple
 |      of 2880 bytes.  However, aspects of this may be controlled.
 |      
 |      Parameters
 |      ----------
 |      fileobj : str, file (optional)
 |          Either the pathname of a file, or an open file handle or file-like
 |          object
 |      
 |      sep : str (optional)
 |          The character or string with which to separate cards.  By default
 |          there is no separator, but one could use `'\\n'`, for example, to
 |          separate each card with a new line
 |      
 |      endcard : bool (optional)
 |          If `True` (default) adds the END card to the end of the header
 |          string
 |      
 |      padding : bool (optional)
 |          If `True` (default) pads the string with spaces out to the next
 |          multiple of 2880 characters
 |      
 |      clobber : bool (optional)
 |          If `True`, overwrites the output file if it already exists
 |  
 |  tostring(self, sep='', endcard=True, padding=True)
 |      Returns a string representation of the header.
 |      
 |      By default this uses no separator between cards, adds the END card, and
 |      pads the string with spaces to the next multiple of 2880 bytes.  That
 |      is, it returns the header exactly as it would appear in a FITS file.
 |      
 |      Parameters
 |      ----------
 |      sep : str (optional)
 |          The character or string with which to separate cards.  By default
 |          there is no separator, but one could use `'\\n'`, for example, to
 |          separate each card with a new line
 |      
 |      endcard : bool (optional)
 |          If True (default) adds the END card to the end of the header
 |          string
 |      
 |      padding : bool (optional)
 |          If True (default) pads the string with spaces out to the next
 |          multiple of 2880 characters
 |      
 |      Returns
 |      -------
 |      s : string
 |          A string representing a FITS header.
 |  
 |  totextfile(self, fileobj, endcard=False, clobber=False)
 |      Equivalent to ``Header.tofile(fileobj, sep='\n', endcard=False,
 |      padding=False, clobber=clobber)``.
 |  
 |  update(self, *args, **kwargs)
 |      Update the Header with new keyword values, updating the values of
 |      existing keywords and appending new keywords otherwise; similar to
 |      dict.update().
 |      
 |      update() accepts either a dict-like object or an iterable.  In the
 |      former case the keys must be header keywords and the values may be
 |      either scalar values or (value, comment) tuples.  In the case of an
 |      iterable the items must be (keyword, value) tuples or
 |      (keyword, value, comment) tuples.
 |      
 |      Arbitrary arguments are also accepted, in which case the update() is
 |      called again with the kwargs dict as its only argument.  That is,
 |      
 |          >>> header.update(NAXIS1=100, NAXIS2=100)
 |      
 |      is equivalent to
 |      
 |          >>> header.update({'NAXIS1': 100, 'NAXIS2': 100})
 |      
 |      .. warning::
 |          As this method works similarly to dict.update() it is very
 |          different from the Header.update() method in PyFITS versions prior
 |          to 3.1.0.  However, support for the old API is also maintained for
 |          backwards compatibility.  If update() is called with at least two
 |          positional arguments then it can be assumed that the old API is
 |          being used.  Use of the old API should be considered
 |          **deprecated**.  Most uses of the old API can be replaced as
 |          follows:
 |      
 |          * Replace
 |      
 |                >>> header.update(keyword, value)
 |      
 |            with
 |      
 |                >>> header[keyword] = value
 |      
 |          * Replace
 |      
 |                >>> header.update(keyword, value, comment=comment)
 |      
 |            with
 |      
 |                >>> header[keyword] = (value, comment)
 |      
 |          * Replace
 |      
 |                >>> header.update(keyword, value, before=before_keyword)
 |      
 |            with
 |      
 |                >>> header.insert(before_keyword, (keyword, value))
 |      
 |          * Replace
 |      
 |                >>> header.update(keyword, value, after=after_keyword)
 |      
 |            with
 |      
 |                >>> header.insert(after_keyword, (keyword, value),
 |                ...               after=True)
 |      
 |          See also :meth:`Header.set` which is a new method that provides an
 |          interface similar to the old Header.update() and may help make
 |          transition a little easier.
 |      
 |          For reference, the old documentation for the old Header.update()
 |          is provided below:
 |      
 |      Update one header card.
 |      
 |      If the keyword already exists, it's value and/or comment will
 |      be updated.  If it does not exist, a new card will be created
 |      and it will be placed before or after the specified location.
 |      If no `before` or `after` is specified, it will be appended at
 |      the end.
 |      
 |      Parameters
 |      ----------
 |      key : str
 |          keyword
 |      
 |      value : str
 |          value to be used for updating
 |      
 |      comment : str (optional)
 |          to be used for updating, default=None.
 |      
 |      before : str, int (optional)
 |          name of the keyword, or index of the `Card` before which
 |          the new card will be placed.  The argument `before` takes
 |          precedence over `after` if both specified.
 |      
 |      after : str, int (optional)
 |          name of the keyword, or index of the `Card` after which
 |          the new card will be placed.
 |      
 |      savecomment : bool (optional)
 |          When `True`, preserve the current comment for an existing
 |          keyword.  The argument `savecomment` takes precedence over
 |          `comment` if both specified.  If `comment` is not
 |          specified then the current comment will automatically be
 |          preserved.
 |  
 |  values(self)
 |      Returns a list of the values of all cards in the header.
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  fromfile(cls, fileobj, sep='', endcard=True, padding=True) from __builtin__.type
 |      Similar to :meth:`Header.fromstring`, but reads the header string from
 |      a given file-like object or filename.
 |      
 |      Parameters
 |      ----------
 |      fileobj : str, file-like
 |          A filename or an open file-like object from which a FITS header is
 |          to be read.  For open file handles the file pointer must be at the
 |          beginning of the header.
 |      
 |      sep : str (optional)
 |          The string separating cards from each other, such as a newline.  By
 |          default there is no card separator (as is the case in a raw FITS
 |          file).
 |      
 |      endcard : bool (optional)
 |          If True (the default) the header must end with an END card in order
 |          to be considered valid.  If an END card is not found an `IOError`
 |          is raised.
 |      
 |      padding : bool (optional)
 |          If True (the default) the header will be required to be padded out
 |          to a multiple of 2880, the FITS header block size.  Otherwise any
 |          padding, or lack thereof, is ignored.
 |      
 |      Returns
 |      -------
 |      header
 |          A new `Header` instance.
 |  
 |  fromkeys(cls, iterable, value=None) from __builtin__.type
 |      Similar to :meth:`dict.fromkeys`--creates a new `Header` from an
 |      iterable of keywords and an optional default value.
 |      
 |      This method is not likely to be particularly useful for creating real
 |      world FITS headers, but it is useful for testing.
 |      
 |      Parameters
 |      ----------
 |      iterable
 |          Any iterable that returns strings representing FITS keywords.
 |      
 |      value : (optional)
 |          A default value to assign to each keyword; must be a valid type for
 |          FITS keywords.
 |      
 |      Returns
 |      -------
 |      header
 |          A new `Header` instance.
 |  
 |  fromstring(cls, data, sep='') from __builtin__.type
 |      Creates an HDU header from a byte string containing the entire header
 |      data.
 |      
 |      Parameters
 |      ----------
 |      data : str
 |         String containing the entire header.
 |      
 |      sep : str (optional)
 |          The string separating cards from each other, such as a newline.  By
 |          default there is no card separator (as is the case in a raw FITS
 |          file).
 |      
 |      Returns
 |      -------
 |      header
 |          A new `Header` instance.
 |  
 |  fromtextfile(cls, fileobj, endcard=False) from __builtin__.type
 |      Equivalent to ``Header.fromfile(fileobj, sep='\n', endcard=False,
 |      padding=False)``.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ascard
 |      .. deprecated:: 3.1
 |          Use the `.cards` attribute instead.
 |      
 |      Returns a CardList object wrapping this Header; provided for
 |      backwards compatibility for the old API (where Headers had an
 |      underlying CardList).
 |  
 |  cards
 |      The underlying physical cards that make up this Header; it can be
 |      looked at, but it should not be modified directly.
 |  
 |  comments
 |      View the comments associated with each keyword, if any.
 |      
 |      For example, to see the comment on the NAXIS keyword:
 |      
 |          >>> header.comments['NAXIS']
 |          number of data axes
 |      
 |      Comments can also be updated through this interface:
 |      
 |          >>> header.comments['NAXIS'] = 'Number of data axes'

If you ask the header to print itself (next line) you get a straightforward representation of the header--but notice the padding at the bottom. This is important to the FITS standard, and most functions here won't read files with the wrong amount of padding without coaxing with 'ignore_missing_end=True'. You'll see this option several times in this notebook.


In [7]:
ImageHdr


Out[7]:
SIMPLE  =                    T / Fits standard                                  
BITPIX  =                  -32 / Bits per pixel                                 
NAXIS   =                    2 / Number of axes                                 
NAXIS1  =                  512 / Axis length                                    
NAXIS2  =                  512 / Axis length                                    
EXTEND  =                    F / File may contain extensions                    
ORIGIN  = 'NOAO-IRAF FITS Image Kernel July 2003' / FITS file originator        
DATE    = '2012-08-02T08:36:15' / Date FITS file was generated                  
IRAF-TLM= '2012-08-02T05:42:18' / Time of last modification                     
COMMENT   FITS (Flexible Image Transport System) format defined in Astronomy and
COMMENT   Astrophysics Supplement Series v44/p363, v44/p371, v73/p359, v73/p365.
COMMENT   Contact the NASA Science Office of Standards and Technology for the   
COMMENT   FITS Definition document #100 and other FITS information.             
HEAD    = 'DV434   '           / Head model                                     
ACQMODE = 'Single Scan'        / Acquisition mode                               
READMODE= 'Image   '           / Readout mode                                   
IMGRECT = '1, 1024, 1024, 1'   / Image format                                   
HBIN    =                    2 / Horizontal binning                             
VBIN    =                    2 / Vertical binning                               
SUBRECT = '1, 1024, 1024, 1'   / Subimage format                                
XTYPE   = 'Pixel number'       / Calibration type                               
XUNIT   =                    0 / Type of system                                 
TRIGGER = 'Internal'           / Trigger mode                                   
CALIB   = '0,1,0,0 '           / Calibration                                    
EXPOSURE=         4.500000E+01 / Total Exposure Time                            
TEMP    =         0.000000E+00 / Temperature                                    
READTIME=         1.000000E-06 / Pixel readout time                             
OPERATN =                    4 / Type of system                                 
DATE-OBS= '2012-08-02T08:36:15' / Time at start of exposure                     
UT      = '08:36:15'           / UT time at start of exposure                   
OBSERVAT= 'mro     '           / per the IRAF observatory list                  
RA      = '00:43:24.69'        / Right Ascension                                
DEC     = '41:20:13.9'         / Declination                                    
EPOCH   = '2012.59 '           / Epoch for RA and Dec (years)                   
ST      = '21:14:27'           / local sidereal time (hours)                    
HA      = '-03:28:56'          / Hour Angle                                     
ZD      = '37:11:55.3'         / Zenith Angle                                   
RDNOISE =                 12.5 / Readnoise                                      
GAIN    =                  3.1 / Gain                                           
AIRMASS =             1.253933                                                  
UTMIDDLE= '2012-08-02T08:36:37.50'                                              
JD      =     2456141.85876736                                                  
HJD     =     2456141.85982094                                                  
LJD     =             2456141.                                                  
IMAGETYP= 'object  '                                                            
OBJECT  = 'andromeda'                                                           
FILTER  = 'i       '                                                            
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                

In [8]:
ImageHdr[9]


Out[8]:
'  FITS (Flexible Image Transport System) format defined in Astronomy and'

In [9]:
ImageHdr.keys()


Out[9]:
['SIMPLE',
 'BITPIX',
 'NAXIS',
 'NAXIS1',
 'NAXIS2',
 'EXTEND',
 'ORIGIN',
 'DATE',
 'IRAF-TLM',
 'COMMENT',
 'COMMENT',
 'COMMENT',
 'COMMENT',
 'HEAD',
 'ACQMODE',
 'READMODE',
 'IMGRECT',
 'HBIN',
 'VBIN',
 'SUBRECT',
 'XTYPE',
 'XUNIT',
 'TRIGGER',
 'CALIB',
 'EXPOSURE',
 'TEMP',
 'READTIME',
 'OPERATN',
 'DATE-OBS',
 'UT',
 'OBSERVAT',
 'RA',
 'DEC',
 'EPOCH',
 'ST',
 'HA',
 'ZD',
 'RDNOISE',
 'GAIN',
 'AIRMASS',
 'UTMIDDLE',
 'JD',
 'HJD',
 'LJD',
 'IMAGETYP',
 'OBJECT',
 'FILTER',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '']

Note that the header "dictionary" isn't case sensitive! ('filter' == 'FILTER')


In [10]:
ImageHdr['filter']


Out[10]:
'i'

Now lets use another function, getval, to see if all of our files have the all-important Date-Obs keyword. Note that I'm using try to catch an exceptions that 'fits.getval()' throws. This actually got me in trouble when I gave fits.getval() a non-complient file, and it just incorrectly printed "whoops! No Date-Obs header" when actually it was refusing to read the file. My bad--I changed the code to catch the errors more specifically, and to print out the auto-generated error string 'e'. Try this code both ways: with and without 'ignore_missing_end=True'.


In [11]:
for file in FitsFiles:
    try:
        print file, fits.getval(file, 'date-obs', ignore_missing_end=True)
    except IOError, e:
        print e, "try adding 'ignore_missing_end=True'"
    except KeyError, e:
        print e, "whoops!"


./data/andromeda_i.fit 2012-08-02T08:36:15
./data/dumbbell3.fit 2012-09-15T06:18:13
./data/haFlat.fitsWARNING: Header block contains null bytes instead of spaces for padding, and is not FITS-compliant. Nulls may be replaced with spaces upon writing. [astropy.io.fits.header]
WARNING: VerifyWarning: Error validating header for HDU #1 (note: PyFITS uses zero-based indexing).
    Header size is not multiple of 2880: 2998
There may be extra bytes after the last HDU or the file is corrupted. [astropy.io.fits.hdu.hdulist]
 "Keyword 'DATE-OBS' not found." whoops!
./data/herc_r.fit 2012-08-02T05:54:22
./data/NewFile.fits 2012-09-09T07:55:32
./data/ring4.fit 2012-09-15T06:58:38

Note that astropy.io.fits is super-complient to the FITS standard, and will throw an exception with this file unless you use 'ignore_missing_end=True'


In [12]:
ImageData, ImageHdr = fits.getdata('./data/haFlat.fits', 0, header=True, ignore_missing_end=True)

In [13]:
ImageHdr['date']


Out[13]:
'2012-09-09T07:55:32'

The header has an update method, but you do have to use fits.writeto() to save your work


In [14]:
if os.path.exists('data/NewFile.fits'):
    os.remove('data/NewFile.fits')
DateObs = ImageHdr['date']
ImageHdr.update('DATE-OBS', DateObs, comment = "Time at start of exposure")
fits.writeto('data/NewFile.fits', ImageData, ImageHdr)

fits.open is the standard way of opening files, and an OO interface to the file.


In [15]:
Image = fits.open('data/haFlat.fits', mode='update', ignore_missing_end=True)
ImageHdr = Image[0].header
ImageHdr.update('Date-Obs', DateObs)

You'll need to save your changes with either 'Image.flush()', 'Image.close()', or fits.writeto('NewFile.fits', ImageData, ImageHdr). I (just) found that only the last method, writing to a new file, actually makes a complient file. The other methods leave the header the wrong length, which at best produces error messages, and at worst means it generates an exception. # In my code at MRO, I had to add 'output_verify = "ignore"' as an option here--unfortunately I don't remember why, but try it if you have any problems.


In [16]:
if os.path.exists('data/NewFile.fits'):
    os.remove('data/NewFile.fits')
fits.writeto('data/NewFile.fits', ImageData, ImageHdr)

In [17]:
print DateObs
import time
thistime = time.strptime(DateObs+' UTC', "%Y-%m-%dT%H:%M:%S %Z")
print thistime


2012-09-09T07:55:32
time.struct_time(tm_year=2012, tm_mon=9, tm_mday=9, tm_hour=7, tm_min=55, tm_sec=32, tm_wday=6, tm_yday=253, tm_isdst=0)

In [18]:
print time.mktime(thistime)


1347206132.0

In [19]:
print time.mktime(time.strptime('2012-08-02T08:45:21 UTC', "%Y-%m-%dT%H:%M:%S %Z") ) - time.mktime(time.strptime('2012-08-02T08:45:20 UTC', "%Y-%m-%dT%H:%M:%S %Z") )


1.0

In [20]:
from pyraf import iraf
iraf.noao.astutil(_doprint=0)
iraf.noao.astutil.setairmass (options.destination_dir+'/'+FileName, observatory=")_.observatory", 
    intype="beginning", outtype="effective", ra="ra", dec="dec", equinox="epoch", st="st", 
    ut="ut", date="date-obs", exposure="exposure", airmass="airmass", utmiddle="utmiddle", 
    scale=750., show='yes', update='yes', override='yes')


An exception has occurred, use %tb to see the full traceback.

SystemExit: 
Your iraf and IRAFARCH environment variables are not defined and could not
be determined from /usr/local/bin/cl.  Before starting pyraf, define them
by doing (for example)
   setenv iraf /usr/local/iraf/
   setenv IRAFARCH redhat
at the Unix command line.  The values will depend on your IRAF installation.

Created directory /Users/jakevdp/Opensource/2013_fall_ASTR599/notebooks/pyraf for cache
To exit: use 'exit', 'quit', or Ctrl-D.

Homework

  • sketch code to find all files with header x, and add filter info to header, OR
  • generate a FITS image of a de Vaucouleurs galaxy (I just found out that a Jaffe profile is the function to use) OR
  • just a disk galaxy with mutiple expentially decaying bits (does this sound tougher then the second one? It's not!).

To make a fits file from scratch, try this:


In [ ]:
import numpy as np
# this is goofy--but it makes a visible pattern!
x, y = np.ogrid[-50:50, -50:50]
x.shape, y.shape
n = np.sqrt(x**2 + y**2)
n.shape # we have a 2D array!
hdu = fits.PrimaryHDU(n)
hdu.writeto('DarkStar.fits')

In [ ]: