Please note that all the SIEpedia's articles address specific issues or questions raised by IAC users, so they do not attempt to be rigorous or exhaustive, and may or may not be useful or applicable in different or more general contexts.
Work in progress
This is the updated (as of 15th May 2008) guideline for a talk on "Pyraf" given by Ruymán Azzollini at the IAC in March 2007. These notes have been checked to be in step with the version of this software currently installed in "our" servers, i.e. version 1.4. We thank Chris Sontag from the STScI for sending us a very thorough revision of these notes.
You can find the PyRAF documentation at: http://www.stsci.edu/resources/software_hardware/pyraf.
Tutorial: http://stsdas.stsci.edu/pyraf/doc.old/pyraf_tutorial/
Programmer's Guide: http://stsdas.stsci.edu/pyraf/doc.old/pyraf_guide/pyraf_guide.html
Note also that general questions about PyRAF may be directed to "help@stsci.edu".
IRAF from a pythonian point of view, by R Azzollini
PYRAF CONSOLE MODE
- Loading pyraf
% pyraf
- Loading a package, (no way back... 'bye' does nothing)
--> stsdas
Mostly iraf-like...
- Now a few commands to see how it works:
--> imheader GOODS.fits l+
--> imcopy GOODS.fits GOODS2.fits
Getting help from within
- Help tasks
--> help stsdas
# contents of a module
--> system.help imcopy
# help on imcopy, iraf-like
--> phelp imcopy
# more or less the same..
Epars... playing around with the epar-window.
- To open a "window" with the "epar" page of a given task, just type:
--> epar imcalc # (GOODS.fits GOODS_div2.fits im1/2. old ...)
Within this window, you'll be able to "Save" the parameters, "Unlearn" the task, "Execute" it or just "Cancel" it. You can also ask for help ("Task Help"). (More information on this in http://stsdas.stsci.edu/pyraf/doc.old/pyraf_tutorial/UsingEPAR.html).
- Note also that you can use 'tpar' as a terminal/text-based parameter editing interface.
--> tpar imcalc
Task Parameters
if a task is executed using Python syntax, then the uparm copy of the par file will not be updated (unless the special boolean keyword _save=1 was specified).
- setParam
--> iraf.listpix.setParam('images','GOODS2.fits[0]')
--> iraf.listpix(mode='ql')
# confirms parameter
--> iraf.listpix(mode='h')
# doesn't ask for parameter...@@
- getParam
--> variable = iraf.listpix.getParam('images',mode='h')
--> print variable
'GOODS2.fits[0]'
- saveParList
--> iraf.listpix.saveParList(filename="listpix.par")
'5 parameters written to listpix.par'
--> !more listpix.par
images,f,a,'GOODS2.fits[0]',,,'Images to be converted to list form'
wcs,s,h,'logical',,,'Output world coordinate system name'
formats,s,h,'',,,'List of pixel coordinate formats'
verbose,b,h,no,,,'Print banner for each input image'
mode,s,h,'al'
- setParList
--> iraf.listpix.setParList(ParList="listpix.par")
--> iraf.listpix()
- or directly...
--> iraf.listpix(ParList="listpix.par")
# no need of mode='h' to avoid check!
- these commands do the same as in IRAF CL.
--> lparam(iraf.hedit)
--> dparam(iraf.hedit)
--> unlearn(iraf.hedit)
Pyraf Graphics and Image Display
- Image plot:
--> implot GOODS.fits
- Play a bit with "Window: New", "Page: Next,back" ...with interactive capabilities... e.g. try:
> E
# zoom
> :l 25
# plot line 25
- Printing graphics Hardcopy:
use "File" > "Print", which sends the plot to stdplot device
- Which device is stdplot?
--> envget('stdplot')
'lp'
OTHER THINGS
- Saving and restoring sessions...
--> saveToFile session
--> restoreFromFile session
- How to run system commands:
--> !ps
- Easily naming temporary files:
--> filename = iraf.mktemp('root')
--> print filename
root19883j
RUNNING TASKS IN PYTHON MODE
- Import Iraf:
--> import iraf
# in pyraf
>>> from pyraf import iraf
# in python
--> from pyraf.iraf import stsdas, imcalc
# importing specific packages
--> iraf.images()
# Loading "images"
--> ?
images/:
imcoords/ imfit/ immatch/ tv/
imfilter/ imgeom/ imutil/
- let's do some things to see how it works:
name of parameters may be specified or not (the order is meaningful if not)
--> iraf.imcopy('GOODS.fits','deletable.fits')
--> iraf.imcopy(input='GOODS.fits',output='deletable.fits') # this works too
--> iraf.imcopy.input = 'GOODS.fits'
--> iraf.imcopy.output = 'deletable.fits'
--> iraf.imcopy() # does the same...
- in pyraf you can use common iraf abbreviations for parameters:
--> iraf.imcopy.inp = 'GOODS.fits'
or even shorter... but beware of name collisions (use PY): "in" is a reserved word in python, that's the reason of using PY prefix.
--> iraf.imcopy.PYin = 'GOODS.fits'
I/O redirection:
- Use of STDIN, STDOUT, STDERR - STDOUT, STDERR = 0/1/textfile
--> GOODS_txt = iraf.listpix("GOODS.fits[1:5,1:5]",Stdout=1)
--> print GOODS_txt
--> GOODS_err = iraf.listpix("GOODS.fits[1:5,1:5]",Stderr=1,\ Stdout="STDOUT")
--> print GOODS_err
--> iraf.listpix("GOODS.fits[1:5,1:5],Stdout="GOODS.txt")
--> !more GOODS.txt
- Use of Stdin:
--> s = iraf.imhead('GOODS.fits',long=yes,Stdout=1)
--> print s[0]
'GOODS.fits[124,84][real]: '
--> iraf.head(nl=3,Stdin=s)
GOODS.fits[124,84][real]:
No bad pixels, min=0., max=0. (old)
Line storage mode, physdim [124,84], length of user area 1215 s.u.
- Listing and handling parameters for a task, "alla Python":
--> iraf.imcopy.lParam()
--> iraf.lpar(iraf.imcopy)
# no quotation marks!
--> iraf.lpar('imcopy')
- EPARs, the python way:
>>> iraf.imcopy.eParam()
>>> iraf.epar(iraf.imcopy)
- Tasks appear as attributes of packages, with nested packages also found. For example:
--> load("stsdas")
--> load("analysis")
- You can call tasks with different degree of explicitness on nesting packages, once they have been loaded, and provided there is no possible name collision.
--> iraf.stsdas.restore.mem
<IrafTask mem (restore$x_restore.e) Pkg: restore Bin: stsdasbin$>
--> iraf.restore.mem
<IrafTask mem (restore$x_restore.e) Pkg: restore Bin: stsdasbin$>
--> iraf.mem
<IrafTask mem (restore$x_restore.e) Pkg: restore Bin: stsdasbin$>
- The shorter the better... you can rename tasks, modules, for the sake of brevity.
--> i = iraf
--> i.imcopy('GOODS.fits','deletable.fits')
--> i.imstat('GOODS.fits')
- You can start up PyRAF from any directory. It looks for login.cl in a directory named "iraf" in your home, or in current directory, and uses it to start up.
Important differences between Pyraf and CL:
- Some graphic devices don't have full interactive support, and graphics can be redirected to a GKI file: For instance:
--> prow dev$pix 256 >G redirfile.gki
--> gkidecode redirfile.gki > redirfile.gki.txt
Speaking of graphics, also note that the latest version of PyRAF (just out, v1.6) allows the option of using matplotlib (if installed) in plots/graphics, creating smoother looking plots and more attractive fonts ... But we will have to wait a bit for it to be installed here at the IAC.
- Packages cannot be unloaded.
- No GOTO statement in CL scripts. CL scripts with GOTO's raise exceptions. (Update: Forward-only GOTO's have been supported since v1.2)
- Background execution is not available.
- Error traceback in CL scripts does not print CL line numbers. Instead, line numbers of the translated cl code are given. There is a wish-list item to help map these back to the original script source line numbers... so, hopefully, this will benefit from an "upgrade" soon.
Notes and examples taken directly from "Pyraf Programmer's Guide", by Philip E. Hodge, after minor modifications
PYTHON PROGRAMS WHICH "MIMIC" IRAF TASKS:
- Pyraf allows to write a generic Python program and treat it as an IRAF task, with the familiar CL command-like syntax and parameter editing facilities.
- Python tasks can only be used in PyRAF, not in IRAF CL.
- 1st Example:
xyz.py,
xyz.par
- to use it from pyraf:
--> pyexecute("<path>xyz.py")
--> epar xyz # do "Execute"
--> xyz('Hello Motto')
Hello Motto
--> xyz 'Hello Motto'
Hello Motto
- and from python:
>>> execfile("<path>xyz.py")
>>> xyz('Hello Motto')
Hello Motto
- on the other hand, "pyexecute" doesn't work in python:
>>> pyexecute("<path>xyz.py")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'pyexecute' is not defined
- Correction: "pyexecute" may work from python, as it can be "imported" this way:
--> from pyraf import iraf
--> iraf.pyexecute("<path>xyz.py")
- Also, note of course that your python task in xyz.py could be imported and called directly from a Python script, Python-to-Python.
- 2nd Example: using the _iraf Filename Convention, and more elaborated functionality.
/home/ruyman/iraf/SCRIPTS_SIE/ncounts.par
/home/ruyman/iraf/SCRIPTS_SIE/ncounts_pyraf.py
/home/ruyman/iraf/SCRIPTS_SIE/ncounts.py
- The .par file has as root of its name, the name of the task.
- In order for ncounts_pyraf to find "ncounts" module, add this to .cshrc:
setenv PYTHONPATH "${PYTHONPATH}:/home/ruyman/iraf/SCRIPTS_SIE
- Then...
% source /home/ruyman/.cshrc
- and then, in pyraf:
--> pyexecute("home$SCRIPTS_SIE/ncounts_pyraf.py")
--> epar ncounts
--> ncounts GOODS.fits
- Task ncounts is running...
total = 98450.88605
IRAF CL SCRIPTS in PYRAF
- 3rd example: how to translate an IRAF SSP script to Python.
--> iraf.task(IAC80comb = 'home$SCRIPTS_SIE/IAC80comb.cl')
--> epar IAC80comb
- or in python
>>> iraf.task(IAC80comb = '/home/ruyman/iraf/SCRIPTS_SIE/IAC80comb.cl')
>>> iraf.IAC80comb.eParam()
- NOTE: 'goto' is not supported - Correction: actually 'goto' is supported (but forward-only, and not to the inside of a block).
LOCATING AND EXAMINING TRANSLATED CL SCRIPTS
- The translated script (the python equivalent fo the CL script) is saved in a cache directory, which by default is the 'pyraf/clcache.v2' of the user's IRAF home directory.
- How to see the code easily:
--> iraf.task(IAC80comb = 'home$SCRIPTS_SIE/IAC80comb.cl')
--> print iraf.IAC80comb.getCode()
Dealing with Errors
- The mighty "try" and "except"...
--> try:
... iraf.listpix('GOODS.fits[0:5,1:5]')
... except iraf.IrafError, e:
... print "error was caught"
...
Killing IRAF task `listpixels'
error was caught
- Note: Many IRAF tasks can operate on a list on a list of input files, and these tasks usually convert some errors (such as a file not found) into a warning, allowing the task to continue trying to process the other input files. But warnings are not caught by 'try' and 'except'. So, sometimes, a bit more of code, checking input parameters, is needed to catch some potential errors.
DEBUGGING TIPS
- How to increase verbosity in the tracebacks:
--> iraf.listpix('GOODS.fits[0:10,1:10]')
--> setVerbose(value=2)
--> print iraf.Verbose
2
--> iraf.listpix('GOODS.fits[0:10,1:10]')
- also, use of .fulltraceback
--> iraf.listpix('GOODS.fits[0:10,1:10]')
We get an error, do we do:
--> .full
and we get extended information
WRITING PYTHON SCRIPTS THAT USE IRAF
- Let's see and play around with an example:
python_iraf_script1.py
- Close any ds9 window before running it like this:
% ./python_iraf_script1.py -i GOODS.fits
- Gets median of an image using "imstatistics" (in 2 ways)
- Substracts median from image
- Catches an exception using "try" and "except"
- Rotates an image using "rotate"
- Shows an "implot" of image
- optionally dumps a hardcopy of last plot
- Display images on ds9
ERROR TRACKING
See bugs.py and bugs.cl. Both are equivalent, buggy scripts, in python and IRAF scripting language. Compare the Error Tracking, that python and the IRAF CL provide.
- From console
% ./bugs.py GOODS.fits OHMYGOD.fits
- From IRAF CL
ecl> task $bugs = bugs.cl
ecl> bugs GOODS.fits OHMYGOD.fits
How to run python scripts:
Assume first we have this complex script:
"""A dumb script"""
def Hello():
print 'Hello'
Hello()
- This is how we could run it from the console:
% python script.py
- If we want to execute it without (explicitly) invoking the python interpreter, we should add this one line as the first in the script:
#! /usr/bin/env python # This tells the system to call the python interpreter for 'translation'
"""A dumb script"""
#[... everything else...]
Then we would give it execution permission, and we would execute it like this:
% chmod +x script.py
# to give it execution permission (only needed once)
% ./script.py
- Finally, if we really have the lazy day, or we want to call our script as another system command, from anywhere, first we would tweak the code a little bit more, to have these looks:
#! /usr/bin/env python
"""A dumb script"""
def Hello():
print 'Hello'
if __name__ == '__main__': Hello()
I assume we already gave it execution permission. So, we only need to go to to our 'home' directory, and once there, go to the 'bin/' directory (I assume we're working in Linux), and type some short commands. So, do this:
% cd ~
# go back 'home'
% cd bin/
% ln -s <whateverpathleadstoscript.py>/script.py scrip
t
% rehash
% cd ~
# go back home, for example...
% script
# and this will print a happy message in your console, wherever you are.
- from python/pyraf sessions:
--> execfile("script.py")
>>> execfile("script.py")