Module: VORuby::VOTable

Defined in:
lib/voruby/votable/votable.rb,
lib/voruby/votable/1.0/votable.rb,
lib/voruby/votable/1.1/votable.rb

Overview

A set of classes designed to read and manipulate the IVOA standard for representing astronomical tabular data called VOTable.

As a quick start, you might do something like this:

require 'voruby/votable/votable'
include VORuby

votable = VOTable.from_xml(File.new('votable.basic.xml'))  # this happens to be a 1.1 votable
table = votable.resources.first.tables.first               # get the first resource and table

# See the name of each column
puts table.fields.collect{ |field| field.name }.join('|')

# Iterate through each row.
table.data.format.trs.each do |row|
  row_as_string = row.tds.collect{ |td| td.value }.join('|')
  puts row_as_string
end

Methods that are pluralized (i.e. table.fields and format.trs above) normally return an array-like object called a HomogeneousNodeList. You can do most of the common array operations on it, including array assignment ([]=) and retrieval ([]), appending (<<) and iteration (each). So:

table.fields << Field.new(...)       # append a new field
table.fields.prepend(Field.new(...)) # prepend a new field
table.fields.each { |field| ... }    # iterate through each field
table.fields[2] = Field.new(...)     # assign a new field to the third position
table.fields[2]                      # retrieve the third field
table.fields.delete_at(2)            # delete the third field
table.fields.clear                   # delete all fields
table.fields.first                   # retrieve the first field
table.fields.last                    # retrieve the last field
table.fields.size                    # the number of fields present

It also mixes in Enumerable so all the other standard methods are available.

To build a simple VOTable from scratch all in one go one might do this:

votable = VOTable.new(
  :version => '1.1',
  :coordinate_systems => [
    Coosys.new(:id => 'J2000', :equinox => 'J2000.', :epoch => 'J2000.', :system => 'eq_FK5')
  ],
  :resources => [
    Resource.new(
      :name => 'myFavouriteGalaxies',
      :tables => [
        Table.new(
          :name => 'results',
          :description => Description.new(:text => 'Velocities and Distance estimations'),
          :params => [
            Param.new(
              :name => 'Telescope',
              :datatype => 'float',
              :ucd => 'phys.size;instr.tel',
              :unit => 'm',
              :value => '3.6'
            )
          ],
          :fields => [
            Field.new(:name => 'RA', :id => 'col1', :ucd => 'pos.eq.ra;meta.main',
                      :ref => 'J2000', :datatype => 'float', :width => 6, :precision => '2', :unit => 'deg'),
            Field.new(:name => 'Dec', :id => 'col2', :ucd => 'pos.eq.dec;meta.main',
                      :ref => 'J2000', :datatype => 'float', :width => 6, :precision => '2', :unit => 'deg'),
            Field.new(:name => 'Name', :id => 'col3', :ucd => 'meta.id;meta.main',
                      :datatype => 'char', :arraysize => '8*'),
            Field.new(:name => 'RVel', :id => 'col4', :ucd => 'src.veloc.hc', :datatype => 'int',
                      :width => 5, :unit => 'km/s'),
            Field.new(:name => 'e_RVel', :id => 'col5', :ucd => 'stat.error;src.veloc.hc',
                      :datatype => 'int', :width => 3, :unit => 'km/s'),
            Field.new(:name => 'R', :id => 'col6', :ucd => 'phys.distance', :datatype => 'float',
                      :width => 4, :precision => '1', :unit => 'Mpc',
                      :description => Description.new(:text => 'Distance of Galaxy, assuming H=75km/s/Mpc'))
          ],
          :data => Data.new(
            :format => TableData.new(
              :trs => [
                Tr.new(:tds => [
                    Td.new(:text => '010.68'), Td.new(:text => '+41.27'), Td.new(:text => 'N 224'),
                    Td.new(:text => '-297'), Td.new(:text => '5'), Td.new(:text => '0.7')
                ]),
                Tr.new(:tds => [
                  Td.new(:text => '287.43'), Td.new(:text => '-63.85'), Td.new(:text => 'N 6744'),
                  Td.new(:text => '839'), Td.new(:text => '6'), Td.new(:text => '10.4')
                ]),
                Tr.new(:tds => [
                  Td.new(:text => '023.48'), Td.new(:text => '+30.66'), Td.new(:text => 'N 598'),
                  Td.new(:text => '-182'), Td.new(:text => '3'), Td.new(:text => '0.7')
                ])
              ]
            )
          )
        )
      ]
    )
  ]
)

Of course, it’s more likely you would have read the votable in directly from a file. To convert this votable to a (very) simple CSV-like file you could then:

puts votable.resources.first.tables.first.fields.collect{ |field| field.name }.join(',')
votable.resources.first.tables.first.data.format.trs.each do |tr|
  puts tr.tds.collect{ |td| td.text }.join(',')
end

Which would print out something like:

RA,Dec,RVel,e_RVel,R
010.68,+41.27,N 224,-297,5,0.7
287.43,-63.85,N 6744,839,6,10.4
023.48,+30.66,N 598,-182,3,0.7

You can also convert the votable to an HTML fragment by doing:

votable.to_html

Defined Under Namespace

Modules: Castable, V1_0, V1_1 Classes: Base

Class Method Summary collapse

Class Method Details

.from_xml(defn) ⇒ Object

Automatically determines the votable version in question and returns the appropriate domain object.

defn

a String, XML::Document, XML::Node or IO object representing the XML.

votable = VOTable.from_xml(File.new('votable.basic.xml'))  # assuming this is 1.1 document
puts votable.class   #=> VOTable::V1_1::VOTable


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/voruby/votable/votable.rb', line 142

def self.from_xml(defn)
  generic_vot = Base.new(defn).node
  
  namespaces = (generic_vot.namespace || []).collect{ |ns| ns.href }
  namespaces << generic_vot['noNamespaceSchemaLocation']
  
  if namespaces.include?('http://www.ivoa.net/xml/VOTable/VOTable/v1.1') or generic_vot['version'] =~ /1\.1$/
    require 'voruby/votable/1.1/votable'
    return VOTable::V1_1::VOTable.new(generic_vot)
  elsif namespaces.include?('http://www.ivoa.net/xml/VOTable/v1.0') or generic_vot['version'] =~ /1\.0$/
    require 'voruby/votable/1.0/votable'
    return VOTable::V1_0::VOTable.new(generic_vot)
  else
    require 'voruby/votable/1.1/votable'
    return VOTable::V1_1::VOTable.new(generic_vot) # go with the most recent if namespace indeterminate
  end
end