[BioRuby] Map objects => comparable
jan aerts (RI)
jan.aerts at bbsrc.ac.uk
Wed Feb 8 16:46:56 UTC 2006
Hi all,
I've just looked into creating a simple Map object (could hold data for
linkage maps, RH maps and the like). However, being rather new to ruby,
I bump into what probably turns out to be a simple problem.
I originally thought of creating a SimpleMap and Marker class, each
containing a @mappings array. However, this gave problems when
implementing a sensible <=> method in the Marker class (to be able to
use Comparable mixin). The reason is that a single marker can be mapped
to different maps, and I couldn't see a way to traverse only those
mappings for a marker that would go to a certain map.
Therefore, I included a Mapping class, which would provide the link
between maps and markers and in which a sane <=> method could be
written.
Result: it looks like these three classes work nicely together (see
test-code below: I can sort markers on position within a given map, or
print the last marker on the map). However, I think that this setting
does not make it possible to do a between? or '>' between mappings...
Could I ask anyone to take a look at the code below and tell me how to
use/alter it to be able to:
* Test if a marker is located upstream of another marker (e.g. based on
the '<'-method from the Comparable mixin)
* Test is a marker is between two other markers (e.g. based on the
'between?'-method from the Comparable mixin; in the code example below:
test if my_marker3 lies between my_marker1 and my_marker2 on my_map1)
Explanation of setup of maps/markers:
# One marker can be mapped to different maps. (<= this is what's giving
the problem)
# For each marker that is mapped to a map, or map that gets a marker
added, basically two things happen: a mapping is added to the Marker
object as well as to the SimpleMap object
Many thanks,
jan.
<BEGIN OF MODULE>
module Bio
module Map
# This class handles the essential storage of name, species, type
and units of a map.
class SimpleMap
include Enumerable
# Builds a new Bio::Map::SimpleMap object
def initialize (name = nil, species = nil, units = nil, type =
nil)
@name, @species, @units, @type = name, species, units, type
@mappings = Array.new()
end
attr_accessor :name, :species, :units, :type, :mappings
# Add a MappedMarker object to the map
def add_mapping(marker, position)
unless marker.kind_of?(Bio::Map::Marker)
raise "[Error] marker is not a Bio::Map::Marker object"
end
my_mapping = Bio::Map::Mapping.new(self, marker, position)
@mappings.push(my_mapping)
unless marker.mapped_to?(self)
marker.mappings.push(my_mapping)
end
end
# Check whether a Bio::Map::Marker is mapped to this
Bio::Map::SimpleMap.
def contains?(marker)
contains = false
@mappings.each do |mapping|
if mapping.marker == marker
contains = true
return contains
end
end
return contains
end
# Go through all Bio::Map::Mapping objects linked to this
Bio::Map::SimpleMap.
def each
@mappings.each do |mapping|
yield mapping
end
end
end # SimpleMap
# This class represents the link between SimpleMap and Marker
class Mapping
include Comparable
def initialize (map, marker, position)
@map, @marker, @position = map, marker, position
end
attr_accessor :map, :marker, :position
# To get comparable working...
def <=>(other)
unless self.position.kind_of?(Comparable)
raise "[Error] markers are not comparable"
end
if self.position > other.position
return 1
elsif self.position < other.position
return -1
elsif self.position == other.position
return 0
end
end
end # Mapping
# This class handles markers that are anchored to
Bio::Map::SimpleMap.
class Marker
include Enumerable
def initialize(name)
@name = name
@mappings = Array.new()
end
attr_accessor :name, :mappings
# Add a new map and position for this marker
def add_mapping (map, position)
unless map.kind_of?(Bio::Map::SimpleMap)
raise "[Error] map is not a Bio::Map::SimpleMap object"
end
my_mapping = Bio::Map::Mapping.new(map, self, position)
@mappings.push(my_mapping)
unless map.contains?(self)
map.mappings.push(my_mapping)
end
end
# Check whether this Bio::Map::Marker is mapped to a given
Bio::Map::SimpleMap
def mapped_to?(map)
mapped = false
@mappings.each do |mapping|
if mapping.map == map
mapped = true
return mapped
end
end
return mapped
end
# Go through all Mapping objects linked to this map.
def each
@mappings.each do |mapping|
yield mapping
end
end
end # MappedMarker
end # Map
end # Bio
if __FILE__ == $0
my_marker1 = Bio::Map::Marker.new('marker1')
my_marker2 = Bio::Map::Marker.new('marker2')
my_marker3 = Bio::Map::Marker.new('marker3')
my_map1 = Bio::Map::SimpleMap.new('RH_map_ABC (2006)', 'BTA', 'cR',
'RH')
my_map2 = Bio::Map::SimpleMap.new('consensus', 'GGA', 'cM', 'linkage')
my_map1.add_mapping(my_marker1, 17)
my_map1.add_mapping(my_marker2, 5)
my_marker3.add_mapping(my_map1, 9)
my_marker3.add_mapping(my_map2, 53)
my_map1.sort.each do |mapping|
puts mapping.map.name + "\t" + mapping.marker.name + "\t" +
mapping.position.to_s
end
puts my_map1.min.marker.name
my_map2.each do |mapping|
puts mapping.map.name + "\t" + mapping.marker.name + "\t" +
mapping.position.to_s
end
# p my_map1.between?(my_mappable2,my_mappable3)
# p my_map1.between?(my_mappable,my_mappable2)
end
<END OF MODULE>
---------The obligatory disclaimer--------
The information contained in this e-mail (including any attachments) is
confidential and is intended for the use of the addressee only. The
opinions expressed within this e-mail (including any attachments) are
the opinions of the sender and do not necessarily constitute those of
Roslin Institute (Edinburgh) ("the Institute") unless specifically
stated by a sender who is duly authorised to do so on behalf of the
Institute.
More information about the BioRuby
mailing list