Last modified: December 2023

AHELP for CIAO 4.16


Context: transform


TRANSFORMS - Coordinate transforms in Python


TRANSFORMS is a software package developed by the Chandra X-Ray Center (CXC) to provide a means of applying mathematical operations to data in order to convert it from one reference frame to another. Various Transform objects can be strung together to create complex operations.

The library can be used as a standalone system, and is incorporated into the CRATES package to support the generation and use of "virtual" data objects (see "ahelp cratedata").

Supported transforms

Type Description
LINEARTransfrom A 1D affine transform.
LINEAR2DTransfrom A 2D affine transform.
WCSTransform A WCS projection; most of the WCS types such as TAN and SIN are supported (see the "Supported WCS projections" section below).
WCSTANTransform This is deprecated and WCSTransform should be used instead.

There are help files for each of the Transform commands:

"ahelp -c transform"


>>> import pycrates as pyc
>>> cr = pyc.read_file("img.fits")
>>> img = cr.get_image().values
>>> sky = cr.get_transform("sky")
>>> eqpos = cr.get_transform("eqpos")
>>> yi, xi = np.where(img == img.max())
>>> plog = np.column_stack((xi, yi)) + 1.0
>>> psky = sky.apply(plog)
>>> peqpos = eqpos.apply(psky)

Here we get the coordinates of the maximum value in the image in the 1D numpy arrays xi and yi. As the apply routine requires a single array, we use the column_stack routine from NumPy to combine the two arrays, adding on 1.0 to

The comparison of xi, yi and plog for this particular dataset looks like:

>>> print(xi)
>>> print(yi)
>>> print(plog)
[[209. 178.]]

The psky values are the SKY coordinates corresponding to this location are:

>>> print(psky)
[[3836.5 4188.5]]

and the equatorial coordinates are:

>>> print(peqpos)
[[210.25789497 2.8788792 ]]

Supported WCS projections

The WCSTransform class supports the following projections:

Supported projections

Code Description
TAN Gnomonic = Tangent Plane
SIN Orthographic/synthesis
STG Stereographic
ARC Zenithal/azimuthal equidistant
ZEA Zenithal/azimuthal Equal Area
CAR Cartesian (NOTE: this may give incorrect results)
MER Mercator
PCO Polyconic
SFL Sanson-Flamsteed
PAR Parabolic
AIT Hammer-Aitoff equal area all-sky
MOL Mollweide
CSC COBE quadrilateralized Spherical Cube
QSC Quadrilateralized Spherical Cube
TSC Tangential Spherical Cube
NCP North celestial pole (special case of SIN)
GLS GLobal Sinusoidal (Similar to SFL)
LIN Linear projection
DSS Digitized Sky Survey plate solution
PLT Plate fit polynomials (SAO)
TNX Gnomonic = Tangent Plane (NOAO with corrections)

A number of WCS projection types are currently unsupported:

WCS projections that return invalid results

Code Description
AIR Airy
AZP Zenithal (Azimuthal) Perspective
BON Bonne
HPX HealPix
SZP Slant Zenithal Perspective
ZPN Zenithal/azimuthal PolyNomial

The following projections may cause the Python interpretor to crash:

These WCS transformations that may cause a crash

Code Description
CYP CYlindrical Perspective
CEA Cylindrical Equal Area
COP COnic Perspective
COD COnic equiDistant
COE COnic Equal area
COO COnic Orthomorphic

Example using the SIN projection

As an example, consider the following file from NVSS:

unix% dmlist nvss.fits cols
Columns for Image Block PRIMARY
ColNo  Name                 Unit        Type             Range
   1   PRIMARY[61,61,1,1]   JY/BEAM      Real4(61x61x1x1) -Inf:+Inf            
Physical Axis Transforms for Image Block PRIMARY
Group# Axis# 
   1   1,2    POS(X) = (#1) 
                 (Y)   (#2)
   2   3      Z                    = #3 
   3   4      #AXIS4               = #4 
World Coordinate Axis Transforms for Image Block PRIMARY
Group# Axis# 
   1   1,2    EQPOS(RA ) = (+109.1846) +SIN[(-0.0042)* (POS(X)-(+31.0))]
                   (DEC)   (+37.6656 )      (+0.0042)  (   (Y) (+31.0)) 
   2   3      STOKES               = Z 
   3   4      FREQ                 = +1.4E+09  +100000000.0 * (#AXIS4  -1.0)

for which the physical and WCS projections can be handled by saying

>>> import pytransform as pyt
>>> cr = read_file('nvss.fits')
>>> print(cr.get_axisnames())
['POS', 'EQPOS', 'Z', 'STOKES', '#AXIS4', 'FREQ']
>>> pos = cr.get_transform('pos')
>>> eqpos = cr.get_transform('eqpos')
>>> print(pyt.get_transform_type(pos))
>>> print(pyt.get_transform_type(eqpos))

The parameters of the transformation can be displayed (or read and changed individually); for instance

>>> print(pos.print_parameter_list())
Name: SCALE	Type: dmDOUBLE	Value: 1.000000, 1.000000	   	Desc: Scale	Parent: POS
Name: ROTATION	Type: dmDOUBLE	Value: 0.000000	   	Desc: Rotation Angle	Parent: POS
Name: OFFSET	Type: dmDOUBLE	Value: 0.000000, 0.000000	   	Desc: Origin Offset	Parent: POS

>>> print(eqpos.print_parameter_list())
Name: CRPIX	Type: dmDOUBLE	Value: 31.000000, 31.000000	   	Desc: Reference Point Pixel Coordinates	Parent: EQPOS
Name: CRVAL	Type: dmDOUBLE	Value: 109.184583, 37.665556	   	Desc: Center Coordinate in decimal degrees	Parent: EQPOS
Name: CDELT	Type: dmDOUBLE	Value: -0.004167, 0.004167	   	Desc: Transform Scale in degrees/pixel	Parent: EQPOS
Name: CROTA	Type: dmDOUBLE	Value: 0.000000	   	Desc: Rotation Angle	Parent: EQPOS
Name: EQUINOX	Type: dmSHORT	Value: 2000	   	Desc: Equinox of Coordinates	Parent: EQPOS
Name: EPOCH	Type: dmDOUBLE	Value: 2000.000000	   	Desc: Epoch of Coordinates	Parent: EQPOS
Name: CTYPE	Type: dmCHAR	Value: RA---SIN   , DEC--SIN	   	Desc: Coordinate Projection Type	Parent: EQPOS

and we can use them to convert from a logical coordinate of (1,1); the bottom-left pixel in the image to a physical coordinate of

>>> print(pos.apply([[1.0, 1.0]]))
[[1. 1.]]

which in this case happens to be the identity transform (note how the input was given as an array of arrays, and the input coordinates were floating-point values, not integers). We can now convert to an equatorial position using the eqpos transform (in this case using the centers of both the bottom-left and top-right corners):

>>> ivals = np.asarray([[1.0, 1.0], [61.0, 61.0]])
>>> print(ivals)
[[ 1.  1.]
 [61. 61.]]
>>> ovals = eqpos.apply(ivals)
>>> print(ovals)
[[109.34222803   37.54045037]
 [109.02640676   37.79045023]]


See the bug pages on the CIAO website for an up-to-date listing of known bugs.

Refer to the CIAO bug pages for an up-to-date listing of known issues.