A Ruby FITS I/O library based on C++ sfitsio.
RubyFits is an easy-to-use Ruby library that can be used to manipulate files in the FITS format, the standard file format for astronomy and astrophysics.
The library uses the C++ sfitsio library by Chisato Yamauchi via the SWIG interface generator.
To install this library, do the following:
-
RubyFits needs sllib and sfitsio to be installed.
These libraries can be installed via Homebrew, and
execute the following if you are missing these nice
libraries.
cd /usr/local/Library/Formula wget --no-check-certificate https://galaxy.astro.isas.jaxa.jp/%7Eyuasa/documents/20130513/sllib.rb wget --no-check-certificate https://galaxy.astro.isas.jaxa.jp/%7Eyuasa/documents/20130513/sfitsio.rb brew install sfitsio
-
Clone (download) from github.
git clone https://github.com/yuasatakayuki/RubyFits.git
-
Build with cmake.
cd RubyFits/swig mkdir build cd build cmake .. make install
Compiled library will be installed to $HOME/lib/ruby. If you do not like this, modify install prefix with --DCMAKE_INSTALL_PREFIX like:cmake . --DCMAKE_INSTALL_PREFIX=/usr/local
-
In the ruby scritps, you can import RubyFits by doing like:
require "RubyFits" include Fits
-
Define RUBYLIB to direct "$HOME/lib/ruby" in your .zshrc for example.
export RUBYLIB=$HOME/lib/ruby
- Takayuki Yuasa - Japan Aerospace Exploration Agency (JAXA)
- yuasa aaa astro.isas.jaxa.jp
- RubyFits API Reference generated by rdoc.
- Documentation contribution is very much welcome.
In the example/ folder, there are some scripts showing usages of RubyFits. "samplteTable.fits" can be used as a sample FITS file.
- readTable.rb well describes how to read TableHDU in a FITS file.
See openSave.rb.
require "RubyFits" include Fits f=FitsFile.new("sampleTable.fits") puts f puts f[0].headerKeyValueComment(1)
You can open a file after constructing an empty instance first.
f=FitsFile.new f.open("sampleTable.fits")
Save.
#save to file f.saveAs("openSave.fits")
You can check the saved FITS file with fv for example (HEASOFT should be installed):
fv openSave.fits
FitsFile::saveAs() has some aliases:
- writeToFile
- saveToFile
- writeToFile
- write
- save
- writeTo
- saveTo
See openSave.rb.
A FitsFile instance contains one or more HDU (header data unit, or sometimes called 'extension'). They can be accessed via one of the following accessors:
f=FitsFile.new("sampleTable.fits") f.hdu(1) # by index f[1] # by index f.hdu("SPECTRUM") # by name
An HDU contains Header and Data (table or image). Key-value records in a header can be accesses as follows:
#dump the 1-st and 3-rd header key-value records puts f[1].headerKeyValueComment(1) puts f[1].headerKeyValueComment(3) puts f[1].headerKeyValueComment("TELESCOP") #dump some header key-value records puts f[1].header("TELESCOP") puts f[1].header("RA_PNT").to_f #retrieve header key-value record f[1].headers.each { |headerRecord| puts headerRecord.keyword }
FitsFile::header(indexOrKeyword) returns header record object (an instance of FitsHeaderRecord class). Values of header record objects can be obtained via usual cast methods such as to_s(), to_f(), to_i(), and so on.
Header key-value record can be modified by assigning new value to the header record object. If no entry is found with a provided keyword, a new entry will be created with keyword and value (and comment if specified).
#modify header records f[1].header("TELESCOP") << "ASTRO-H" f[1].setHeader("INSTRUME","SXS") f[1].addHeader("NEWKEY",3.14159, "COMMENT")Type of record can be automatically changed depending on the assigned value.
#modify header record with comment f[1].header("TELESCOP") << [3.141592,"PI"]
FitsTableHDU consists of one or more FitsTableColumn objects which represent each column of the table. Data in a column can be accessed like ones contained in an array.
See readTable.rb in the example/ folder.
puts "TableHDU access example1:" puts "============================================" tableHDU=f.getHDU("SPECTRUM") puts "TableHDU #{tableHDU.getHDUName()} has #{tableHDU.nColumns()} columns and #{tableHDU.nRows} rows." tableHDU.columns.each {|column| puts column } puts "============================================"
This will result (with sampleTable.fits):
> ruby readTable.rb ... omitted ... TableHDU access example1: ============================================ TableHDU SPECTRUM has 2 columns and 256 rows. Column named "CHANNEL" = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... (256 elements in total) ] Column named "COUNTS" = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... (256 elements in total) ] ============================================
Another example is to use array accessor of FitsTableColumn. Index or range can be specified, e.g.
puts "TableHDU access example3:" puts "============================================" tableHDU=f.getHDU("SPECTRUM") puts tableHDU["COUNTS"][100] puts tableHDU["COUNTS"][100...120].join(",") puts "============================================"The above means "retrieve data of 101th-120th entries from the 'COUNTS' column contained in the 'SPECTRUM' HDU".
This will result:
============================================ 115 115,109,115,84,87,95,79,111,76,71,93,102,93,81,88,77,73,86,71,78 ============================================
Length of TableHDU (i.e. number of entries or number of rows) can be retrieved via FitsTableColumn.length() or its aliases:
- nEntries
- nRows
- getNEntries
- getNRows
See createNewTable.fits.
require "RubyFits" include Fits #create an empty column column=FitsTableColumn.new #set column name and format column.initializeWithNameAndFormat("COUNTS","1J") #set number of entries column.resize(128) #fill rows with (row number * 2). for i in 0...column.nRows column[i]=i*2 end #another example of filling rows column[1..3]=[10,11,12] #append the created column to a TableHDU tableHDU=FitsTableHDU.new tableHDU.resize(128) tableHDU.appendColumn(column) puts tableHDU #append the create TableHDU to a FitsFile f=FitsFile.new f.append tableHDU #Write to a file f.saveAs("createNewTable.fits")
This will create a TableHDU with a column named "COUNTS" with a type of "1J" (i.e. 1 integer per row). Following the assignment, rows[1], row[2], and row[3] will have 10, 11, and 12, respectively.
FitsImageHDU handles access to ImageHDUs.
In the following example (copied from readImage.rb in the example/ folder), pHDU is the PrimarHDU os the "sampleTable.fits" file and its type is Image HDU (Primary HDU should be always ImageHDU). Although this sample FITS file does not contain meaningful values in the Primary HDU image, we can retrieve some pieces of information such as width, height, and pixel values.
require "RubyFits" include Fits f=FitsFile.new("sampleTable.fits") #Primary HDU pHDU=f.hdu(0) puts pHDU puts "Image type = #{pHDU.getTypeAsString()}" puts "Image size = #{pHDU.getXSize} x #{pHDU.getYSize}" puts "Pixel value:" puts " (1,2) = #{pHDU.getPixelValue(1,2)}" puts " (3,3) = #{pHDU.getPixelValue(3,3)}" puts " (15,2) = #{pHDU.getPixelValue(15,2)}" puts " (100,100) = #{pHDU.getPixelValue(100,100)} # <= this should be NaN because the pixel is outside the define size." croppedImage=pHDU.section(1,2)
The example code copied from newImage.rb shows how to create a new ImageHDU.
Note: In the current version of RubyFits, users have to call FitsImageHDU::imageHDU.constructImage(x,y,z,type) to actually construct an image with buffer allocated not only new() which creates an empty instance. This restriction is due to some limitation of SWIG related to the %rename attribute, and might be resolved in the future releases.
Type: type parameter should be one of the following values.
- Fits::DOUBLE_T (64-bit double precision floating value)
- Fits::FLOAT_T (32-bit single precision floating value)
- Fits::LONG_T (32-bit signed integer)
- Fits::LONGLONG_T (64-bit signed integer)
- Fits::BYTE_T (8-bit signed integer)
- Fits::SHORT_T (16-bit signed integer)
require "RubyFits" include Fits #Create an image HDU whose size is 100x100, and has type of DOUBLE_T puts Fits::DOUBLE_T imageHDU=FitsImageHDU.new imageHDU.constructImage(100,100,0,Fits::DOUBLE_T) puts imageHDU.getHDUName imageHDU.setHDUName("SampleImage") puts imageHDU puts "Image type = #{imageHDU.getTypeAsString()}" puts "Image size = #{imageHDU.getXSize} x #{imageHDU.getYSize}" puts "Setting a value to (50,50)" imageHDU.setDouble(3.14159,50,50) puts " (50,50) = #{imageHDU.getValue(50,50)}" f=FitsFile.new f.appendHDU(imageHDU) f.saveAs("newImage.fits") puts "Created image was saved to newImage.fits"
Comments, suggestions, and questions are welcome. Please send them to yuasa aaa astro.isas.jaxa.jp.
If you are interested in SpaceWire, see my another project "The open-source SpaceWire project" and "SpaceWire RMAP Library.