PDL::IO::FITS(3pm)
π PDL::IO::FITS β the PDL::IO::FITS(3pm) page, bestie edition π
User Contributed Perl Documentation Β· PDL::IO::FITS(3pm)
okay so. you want FITS files in and out of PDL with zero drama? say less. this is the page, and it's a long one, so grab a snack. π
β¨ NAME β¨
PDL::IO::FITS β simple FITS support for PDL. that's it, that's the whole vibe. π
β¨ SYNOPSIS β¨
use PDL;
use PDL::IO::FITS;
$x = rfits('foo.fits'); # read a FITS file
$x->wfits('bar.fits'); # write a FITS file
see? two lines. little tiny baby lines. slay. π
β¨ DESCRIPTION β¨
So this module gives you basic FITS support for PDL, and by "basic" she means reading and writing whole FITS files, top to bottom. That's the assignment. π«Ά
If you need the more complex stuff β like prefiltering rows out of tables, or messing with a FITS file in place on disk, main character energy β then go look at the Astro::FITS::CFITSIO module, which is available on CPAN. She's there for you too. β¨
Here's what's on the menu:
- Basic FITS image files? supported. β
BINTABLEandIMAGEextensions? supported. β- ASCII Table support? planned. π
- The HEASARC bintable extensions recommended in the 1999 FITS standard? also planned. π
Table support is built on hashes and named columns, not on that less convenient (but slightly more congruent) technique of perl lists of numbered columns. No cap, named columns are just nicer to live with. π
The principle interface routines are "rfits" and "wfits" β reading and writing respectively, and yes you will use them constantly.
FITS headers come back as perl hashes, or β if the module is present β as Astro::FITS::Header objects that are tied to perl hashes. Those tied objects give you the convenient tied-hash interface, but they also let you control the card structure in more detail through a separate method interface. See the Astro::FITS::Header documentation for the details, bestie, she explains herself better than I can. π
β¨ AUTHOR β¨
Copyright (C) Karl Glazebrook, Craig DeForest, and Doug Burke, 1997-2010.
There is no warranty. π
You are allowed to redistribute and/or modify this software under certain conditions. For details, see the file COPYING in the PDL distribution. If this file is separated from the PDL distribution, the copyright notice should be pasted into in this file. (yes, "pasted into in this file." we keep it exactly as written, periodt. π)
β¨ FUNCTIONS β¨
π« rfits()
Simple ndarray FITS reader. Your new best friend fr fr.
$pdl = rfits('file.fits'); # Read a simple FITS image
π¦ Suffix magic
The filename suffix is doing β¨workβ¨:
$pdl = rfits('file.fits.gz'); # Read a file with gunzip(1)
$pdl = rfits('file.fits.Z'); # Read a file with uncompress(1)
$pdl = rfits('file.fits[2]'); # Read 2nd extension
$pdl = rfits('file.fits.gz[3]'); # Read 3rd extension
@pdls = rfits('file.fits'); # Read primary data and extensions
π¦ Tilde expansion
#expand leading ~ to home directory (using glob())
$pdl = rfits '~/filename.fits';
$hdr = rfits('file.fits',{data=>0}); # Options hash changes behavior
In list context, "rfits" reads the primary image and all possible extensions, and returns them in the same order that they occurred in the file β except that, by default, the primary HDU is skipped if it contains no data. (Iconic behaviour, honestly.)
In scalar context, the default is to read the first HDU that contains data. Wanna read other HDU's? Use the [n] syntax. And if you use the [0] syntax, that forces a read of the first HDU, regardless of whether it contains data or no. Yes, hard force. π
Currently recognized extensions are IMAGE and BINTABLE. (See the addendum on EXTENSIONS for details β yes there's an addendum, keep scrolling.)
"rfits" accepts several options that may be passed in as a hash ref if desired:
bscale(default=1) β Determines whether the data are linearly scaled using theBSCALE/BZEROkeywords in the FITS header. To read in the exact data values in the file, set this to0.data(default=1) β Determines whether to read the data, or just the header. If you set this to0, you will get back the FITS header rather than the data themselves. (Note that the header is normally returned as the"hdr"field of the returned PDL; this causes it to be returned as a hash ref directly.)hdrcpy(default=0) β Determines whether thehdrcpyflag is set in the returned PDL. Setting the flag will cause an explicit deep copy of the header whenever you use the returned PDL in an arithmetic or slicing operation. That is useful in many circumstances but also causes a hit in speed. When two or more PDLs withhdrcpyset are used in an expression, the result gets the header of the first PDL in the expression. Seehdrcpyfor an example.expand(default=1) β Determines whether auto-expansion of tile-compressed images should happen. Tile-compressed images are transmitted as binary tables with particular fields ("ZIMAGE") set. Leaving this alone does what you want most of the time, unpacking such images transparently and returning the data and header as if they were part of a normalIMAGEextension. Setting"expand"to0delivers the binary table, rather than unpacking it into an image.afh(default=1) β By defaultrfitsusesAstro::FITS::Headertied-hash objects to contain the FITS header information. This permits explicit control over FITS card information, and conforms well with the FITS specification. ButAstro::FITS::Headerobjects are about 40-60x more memory intensive than comparable perl hashes, and also use ~10x more CPU to manage. For jobs where header processing performance is important (e.g. reading just the headers of 1,000 FITS files), setafhto0to use the legacy parser and get a large boost in speed. ποΈ
FITS image headers are stored in the output PDL and can be retrieved with hdr or gethdr. The hdrcpy flag of the PDL is set so that the header is copied to derived ndarrays by default. (This is inefficient if you are planning to do lots of small operations on the data; clear the flag with "->hcpy(0)" or via the options hash if that's the case. Lowkey important, don't sleep on it.)
The header is a hash whose keys are the keywords in the FITS header. If you have the "Astro::FITS::Header" module installed, the header is actually a tied hash to a FITS header object, which can give you more control over card order, comment fields, and variable types. (see Astro::FITS::Header for details).
The header keywords are converted to uppercase per the FITS standard. Access is case-insensitive on the perl side, provided that Astro::FITS::Header is installed. π
If Astro::FITS::Header is not installed, then a built-in legacy parser is used to generate the header hash. Keyword-associated comments in the headers are stored under the hash key "<keyword>_COMMENT>". All HISTORY cards in the header are collected into a single multiline string stored in the "HISTORY" key. All COMMENT cards are similarly collected under the "COMMENT" key. (Look at her organising. π)
πΈ BSCALE/BZERO
If the BSCALE and/or BZERO keywords are set, they are applied to the image before it is returned. The returned PDL is promoted as necessary to contain the multiplied values, and the BSCALE and BZERO keywords are deleted from the header for clarity. If you don't want this type of processing, set 'bscale=>0' in the options hash.
πΈ EXTENSIONS
Sometimes a FITS file contains only extensions and a stub header in the first header/data unit (the "primary HDU"). In scalar context, you normally only get back the primary HDU β but in this special case, you get back the first extension HDU. You can force a read of the primary HDU by adding a '[0]' suffix to the file name. π
πΈ BINTABLE EXTENSIONS
Binary tables are handled. Currently only the following PDL datatypes are supported: byte, short, ushort, long, float, and double. At present ushort() data is written as a long rather than as a short with TSCAL/ZERO; this may change. (Heads up, okay? don't come for me.)
The return value for a binary table is a hash ref containing the names of the columns in the table (in UPPER CASE as per the FITS standard). Each element of the hash contains a PDL (for numerical values) or a perl list (for string values). The PDL's 0th dimension runs across rows; the 1st dimension runs across the repeat index within the row (for rows with more than one value). (Note that this is different from standard broadcasting order β but it allows Least Surprise to work when adding more complicated objects such as collections of numbers (via the repeat count) or variable length arrays. She's doing it on purpose bestie.)
Thus, if your table contains a column named "FOO" with type "5D", the expression
$x->{FOO}->((2))
returns a 5-element double-precision PDL containing the values of FOO from the third row of the table. π―
The header of the table itself is parsed as with a normal FITS HDU, and is returned in the element 'hdr' of the returned hash. You can use that to preserve the original column order or access the table at a low level, if you like.
Scaling and zero-point adjustment are performed as with BSCALE/BZERO: the appropriate keywords are deleted from the as-returned header. To avoid this behavior, set 'bscale=>0' in the options hash.
As appropriate, TSCAL/ZERO and TUNIT are copied into each column-PDL's header as BSCALE/BZERO and BUNIT.
The main hash also contains the element 'tbl', which is set to 'binary' to distinguish it from an ASCII table.
Because different columns in the table might have identical names in a FITS file, the binary table reader practices collision avoidance. If you have multiple columns named "FOO", then the first one encountered (numerically) gets the name "FOO", the next one gets "FOO_1", and the next "FOO_2", etc. The appropriate TTYPEn fields in the header are changed to match the renamed column fields. β¨
Columns with no name are assigned the name "COL_<n>", where <n> starts at 1 and increments for each no-name column found.
Variable-length arrays are supported for reading. They are unpacked into PDLs that appear exactly the same as the output for fixed-length rows, except that each row is padded to the maximum length given in the extra characters β e.g. a row with TFORM of 1PB(300) will yield an NAXIS2x300 output field in the final hash. The padding uses the TNULn keyword for the column, or 0 if TNULn is not present. The output hash also gets an additional field, "len_<name>", that contains the number of elements in each table row. π
πΈ TILE-COMPRESSED IMAGES
CFITSIO and several large projects (including NASA's Solar Dynamics Observatory) now support an unofficial extension to FITS that stores images as a collection of individually compressed tiles within a BINTABLE extension. These images are automagically uncompressed by default, and delivered as if they were normal image files. You can override this behavior by supplying the "expand" key in the options hash.
Currently, only Rice compression is supported, though there is a framework in place for adding other compression schemes. (Framework's there, schemes aren't yet. That's the tea. π΅)
πΈ BAD VALUE HANDLING
If a FITS file contains the "BLANK" keyword (and has "BITPIX > 0"), the ndarray will have its bad flag set, and those elements which equal the "BLANK" value will be set bad. For "BITPIX < 0", any NaN's are converted to bad (if necessary).
π« rfitshdr()
Read only the header of a FITS file or an extension within it.
This is syntactic sugar for the "data=>0" option to rfits. That's it. Short and sweet and so valid. π§
See rfits for the whole β¨details on header handlingβ¨ thing. rfitshdr() literally runs the same code to read the header, but instead of also pulling in a data structure, it just hands you the header back. bestie behavior fr fr π«Ά
wfits() πΎ
Simple PDL FITS writer, no cap.
wfits $pdl, 'filename.fits', [$BITPIX], [$COMPRESSION_OPTIONS];
wfits $hash, 'filename.fits', [$OPTIONS];
$pdl->wfits('foo.fits',-32);
Suffix magic β¨ (the filename just knows what to do):
# Automatically compress through pipe to gzip
wfits $pdl, 'filename.fits.gz';
# Automatically compress through pipe to compress
wfits $pdl, 'filename.fits.Z';
Tilde expansion π :
#expand leading ~ to home directory (using glob())
wfits $pdl, '~/filename.fits';
- Ordinary (PDL) data handling: π«§
If the first argument is a PDL, then the PDL gets written out as a totally ordinary FITS file, with a single Header/Data Unit of data. simple as that.
$BITPIX is optional here, and it coerces the output data type following the standard FITS convention for the BITPIX field β that means positive values = integer types, negative values = floating-point types. π
If $pdl has a FITS header attached to it (and honestly, any hash that contains a "SIMPLE=>T" keyword counts here), then that FITS header is what gets written out to the file. The image dimension tags get adjusted to match the actual dataset. And if there's a mismatch between the dims of the data and the dims in the FITS header? The header gets corrected and a warning gets printed. it's giving "we fixed it but we're telling you about it" πΈ
If $pdl is a slice of another PDL that already has a FITS header (and header copying is enabled), then omg be careful, bestie. wfits will remove any extraneous NAXISn keywords (per the FITS standard), and it also removes the other keywords hanging out with that axis: CTYPEn, CRPIXn, CRVALn, CDELTn, and CROTAn. This can get real confusing if the slice is NOT out of the last dimension: "wfits($x(:,(0),:),'file.fits');" β and in that case you'd be best off adjusting the header yourself before calling wfits. consider yourself warned π
You can tile-compress images according to the CFITSIO extension to the FITS standard, by adding an option hash to the arguments:
compressβ This can be eitherunity, in which case Rice compression is used, or a (case-insensitive) string matching the CFITSIO compression type names. Currently supported compression algorithms are:RICE_1β linear Rice compression. π₯
This uses limited-symbol-length Rice compression, which works so well on low entropy image data (aka where most pixels differ from their neighbors by much less than the dynamic range of the image). iconic.
BLOCKSIZE(RICE_1 only; default32) β ForRICE_1, this indicates the number of pixel samples to use for each compression block within the compression algorithm. The blocksize is independent of the tile dimensions. For RICE compression, the pixels from each tile are arranged in normal pixel order (early dims fastest) and compressed as a linear stream. π§
- Table handling: π
If you feed in a hash ref instead of a PDL, then the hash ref gets written out as a binary table extension. The hash ref keys are treated as column names, and their values are treated as the data going into each column. periodt.
For numeric information, the hash values should contain PDLs. The 0th dim of the PDL runs across rows, and higher dims get written as multi-value entries in the table (like, a 7x5 PDL will yield a single named column with 7 rows and 5 numerical entries per row, in a binary table). Note that this is slightly different from the usual concept of broadcasting, where dimension 1 runs across rows. lowkey a plot twist π¦
ASCII tables only allow one entry per column in each row, so if you're planning to write an ASCII table then all of the values of $hash should have at most one dim.
All of the columns' 0 dims must agree in the broadcasting sense. That is to say, the 0th dimension of all of the values of $hash should be the same (which signals that all columns have the same number of rows). As an exception, if the 0th dim of any of the values is 1, or if that value is a PDL scalar (with 0 dims), then that value is "broadcasted" over β copied into all rows. π«Ά
Data dimensions higher than 2 are preserved in binary tables, via the TDIMn field (e.g. a 7x5x3 PDL is stored internally as seven rows with 15 numerical entries per row, and reconstituted as a 7x5x3 PDL on read). preserved, as it should be π
Non-PDL Perl scalars are treated as strings, even if they contain numerical values. For example, a list ref containing 7 values is treated as 7 rows containing one string each. There is no such thing as a multi-string column in FITS tables, so any nonscalar values in the list get stringified before being written. For example, if you pass in a perl list of 7 PDLs, each PDL will be stringified before being written, just as if you printed it to the screen. This is probably not what you want β you should use "glue" to connect the separate PDLs into a single one. (e.g. "$x->glue(1,$y,$c)->mv(1,0)") bestie pls use glue π
The column names are case-insensitive, but by convention the keys of $hash should normally be ALL CAPS, containing only digits, capital letters, hyphens, and underscores. If you include other characters, then case is smashed to ALL CAPS, whitespace is converted to underscores, and unrecognized characters are ignored β so if you include the key "Au Purity (%)", it will be written to the file as a column named "AU_PURITY". Since this is not guaranteed to produce unique column names, subsequent columns by the same name are disambiguated by the addition of numbers. β¨
You can specify the use of variable-length rows in the output, saving space in the file. To specify variable length rows for a column named "FOO", you can include a separate key "len_FOO" in the hash to be written. The key's value should be a PDL containing the number of actual samples in each row. The result is a FITS P-type variable length column that, upon read with rfits(), will restore to a field named FOO and a corresponding field named "len_FOO". Invalid data in the final PDL consist of a padding value (which defaults to 0 but which you may set by including a TNULL field in the hdr specificaion). Variable length arrays must be 2-D PDLs, with the variable length in the 1 dimension. π
Two further special keys, 'hdr' and 'tbl', can contain meta-information about the type of table you want to write. You may override them by including an $OPTIONS hash with a 'hdr' and/or 'tbl' key.
The 'tbl' key, if it exists, must contain either 'ASCII' or 'binary' (case-insensitive), indicating whether to write an ascii or binary table. The default is binary. [ASCII table writing is planned but does not yet exist]. π
You can specify the format of the table quite specifically with the 'hdr' key or option field. If it exists, then the 'hdr' key should contain fields appropriate to the table extension being used. Any field information that you don't specify will be filled in automatically, so (for example) you can specify that a particular column name goes in a particular position, but allow wfits to arrange the other columns in the usual alphabetical order into any unused slots that you leave behind. The "TFORMn", "TFIELDS", "PCOUNT", "GCOUNT", "NAXIS", and "NAXISn" keywords are ignored: their values are calculated based on the hash that you supply. Any other fields are passed into the final FITS header verbatim. no notes π
As an example, the following
$x = long(1,2,4);
$y = double(1,2,4);
wfits { 'COLA'=>$x, 'COLB'=>$y }, "table1.fits";
will create a binary FITS table called table1.fits which contains two columns called "COLA" and "COLB". The order of the columns is controlled by setting the "TTYPEn" keywords in the header array, so
$h = { 'TTYPE1'=>'Y', 'TTYPE2'=>'X' };
wfits { 'X'=>$x, 'Y'=>$y, hdr=>$h }, "table2.fits";
creates table2.fits where the first column is called "Y" and the second column is "X". slay π
- multi-value handling π
If you feed in a perl array-ref rather than a PDL or a hash, then each element gets written out as a separate HDU in the FITS file. Each element of the list must be a PDL or a hash. one job, bestie π
- DEVEL NOTES π§
ASCII tables are not yet handled but should be.
Binary tables currently only handle one vector (up to 1-D array) per table entry; the standard allows more, and should be fully implemented.
Handling multidim arrays implies that perl multidim lists should also be handled.
For integer types (ie "BITPIX > 0"), the "BLANK" keyword is set to the bad value. For floating-point types, the bad value is converted to NaN (if necessary) before writing. β
fits_field_cmp π€
fits_field_cmp
Sorting comparison routine that makes proper sense of the digits at the end of some FITS header fields. Sort your hash keys using "fits_field_cmp" and you will get (e.g.) your "TTYPE" fields in the correct order even if there are 140 of them. like, 140?? and still in order?? we love to see it π
This is a standard perl comparison sub β it uses the magical $a and $b variables, rather than normal argument passing. πͺ
_rows() π
Return the number of rows in a variable for table entry
You feed in a PDL or a list ref, and you get back the 0th dimension. that's the whole thing π«Ά
_prep_table() π
Accept a hash ref containing a table, and return a header describing the table and a string to be written out as the table, or barf. π
You can indicate whether the table should be binary or ascii. The default is binary; it can be overridden by the "tbl" field of the hash (if present) or by parameter.
and that's the whole page, bestie!! π«Άβ¨ this little number is PDL::IO::FITS(3pm) from perl v5.42.3, dated 2026-08-20 β go forth and write some FITS files, you absolute icon π
π
π¦ where this page comes from
- ubuntu stonking: pdl 1:2.106-1build1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms