1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
|
#
# = bio/map.rb - biological mapping class
#
# Copyright:: Copyright (C) 2006 Jan Aerts <jan.aerts@bbsrc.ac.uk>
# License:: The Ruby License
#
# $Id: map.rb,v 1.11 2007/04/12 12:19:16 aerts Exp $
require 'bio/location'
module Bio
# == Description
#
# The Bio::Map contains classes that describe mapping information
# and can be used to contain linkage maps, radiation-hybrid maps,
# etc. As the same marker can be mapped to more than one map, and a
# single map typically contains more than one marker, the link
# between the markers and maps is handled by Bio::Map::Mapping
# objects. Therefore, to link a map to a marker, a Bio::Map::Mapping
# object is added to that Bio::Map. See usage below.
#
# Not only maps in the strict sense have map-like features (and
# similarly not only markers in the strict sense have marker-like
# features). For example, a microsatellite is something that can be
# mapped on a linkage map (and hence becomes a 'marker'), but a
# clone can also be mapped to a cytogenetic map. In that case, the
# clone acts as a marker and has marker-like properties. That same
# clone can also be considered a 'map' when BAC-end sequences are
# mapped to it. To reflect this flexibility, the modules
# Bio::Map::ActsLikeMap and Bio::Map::ActsLikeMarker define methods
# that are typical for maps and markers.
#
#--
# In a certain sense, a biological sequence also has map- and
# marker-like properties: things can be mapped to it at certain
# locations, and the sequence itself can be mapped to something else
# (e.g. the BAC-end sequence example above, or a BLAST-result).
#++
#
# == Usage
#
# 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)', 'RH', 'cR')
# my_map2 = Bio::Map::SimpleMap.new('consensus', 'linkage', 'cM')
#
# my_map1.add_mapping_as_map(my_marker1, '17')
# my_map1.add_mapping_as_map(Bio::Map::Marker.new('marker2'), '5')
# my_marker3.add_mapping_as_marker(my_map1, '9')
#
# print "Does my_map1 contain marker3? => "
# puts my_map1.contains_marker?(my_marker3).to_s
# print "Does my_map2 contain marker3? => "
# puts my_map2.contains_marker?(my_marker3).to_s
#
# my_map1.mappings_as_map.sort.each do |mapping|
# puts [ mapping.map.name,
# mapping.marker.name,
# mapping.location.from.to_s,
# mapping.location.to.to_s ].join("\t")
# end
# puts my_map1.mappings_as_map.min.marker.name
#
# my_map2.mappings_as_map.each do |mapping|
# puts [ mapping.map.name,
# mapping.marker.name,
# mapping.location.from.to_s,
# mapping.location.to.to_s ].join("\t")
# end
#
module Map
# == Description
#
# The Bio::Map::ActsLikeMap module contains methods that are typical for
# map-like things:
#
# * add markers with their locations (through Bio::Map::Mappings)
# * check if a given marker is mapped to it,
# and can be mixed into other classes (e.g. Bio::Map::SimpleMap)
#
# Classes that include this mixin should provide an array property
# called mappings_as_map.
#
# For example:
#
# class MyMapThing
# include Bio::Map::ActsLikeMap
#
# def initialize(name)
# @name = name
# @mappings_as_maps = Array.new
# end
# attr_accessor :name, :mappings_as_map
# end
#
module ActsLikeMap
# == Description
#
# Adds a Bio::Map::Mappings object to its array of mappings.
#
# == Usage
#
# # suppose we have a Bio::Map::SimpleMap object called my_map
# my_map.add_mapping_as_map(Bio::Map::Marker.new('marker_a'), '5')
#
# ---
# *Arguments*:
# * _marker_ (required): Bio::Map::Marker object
# * _location_: location of mapping. Should be a _string_, not a _number_.
# *Returns*:: itself
def add_mapping_as_map(marker, location = nil)
unless marker.class.include?(Bio::Map::ActsLikeMarker)
raise "[Error] marker is not object that implements Bio::Map::ActsLikeMarker"
end
my_mapping = ( location.nil? ) ? Bio::Map::Mapping.new(self, marker, nil) : Bio::Map::Mapping.new(self, marker, Bio::Locations.new(location))
if ! marker.mapped_to?(self)
self.mappings_as_map.push(my_mapping)
marker.mappings_as_marker.push(my_mapping)
else
already_mapped = false
marker.positions_on(self).each do |loc|
if loc.equals?(Bio::Locations.new(location))
already_mapped = true
end
end
if ! already_mapped
self.mappings_as_map.push(my_mapping)
marker.mappings_as_marker.push(my_mapping)
end
end
return self
end
# Checks whether a Bio::Map::Marker is mapped to this
# Bio::Map::SimpleMap.
#
# ---
# *Arguments*:
# * _marker_: a Bio::Map::Marker object
# *Returns*:: true or false
def contains_marker?(marker)
unless marker.class.include?(Bio::Map::ActsLikeMarker)
raise "[Error] marker is not object that implements Bio::Map::ActsLikeMarker"
end
contains = false
self.mappings_as_map.each do |mapping|
if mapping.marker == marker
contains = true
return contains
end
end
return contains
end
end # ActsLikeMap
# == Description
#
# The Bio::Map::ActsLikeMarker module contains methods that are
# typical for marker-like things:
#
# * map it to one or more maps
# * check if it's mapped to a given map
# and can be mixed into other classes (e.g. Bio::Map::Marker)
#
# Classes that include this mixin should provide an array property
# called mappings_as_marker.
#
# For example:
#
# class MyMarkerThing
# include Bio::Map::ActsLikeMarker
#
# def initialize(name)
# @name = name
# @mappings_as_marker = Array.new
# end
# attr_accessor :name, :mappings_as_marker
# end
#
module ActsLikeMarker
# == Description
#
# Adds a Bio::Map::Mappings object to its array of mappings.
#
# == Usage
#
# # suppose we have a Bio::Map::Marker object called marker_a
# marker_a.add_mapping_as_marker(Bio::Map::SimpleMap.new('my_map'), '5')
#
# ---
# *Arguments*:
# * _map_ (required): Bio::Map::SimpleMap object
# * _location_: location of mapping. Should be a _string_, not a _number_.
# *Returns*:: itself
def add_mapping_as_marker(map, location = nil)
unless map.class.include?(Bio::Map::ActsLikeMap)
raise "[Error] map is not object that implements Bio::Map::ActsLikeMap"
end
my_mapping = (location.nil?) ? Bio::Map::Mappings.new(map, self, nil) : Bio::Map::Mapping.new(map, self, Bio::Locations.new(location))
if ! self.mapped_to?(map)
self.mappings_as_marker.push(my_mapping)
map.mappings_as_map.push(my_mapping)
else
already_mapped = false
self.positions_on(map).each do |loc|
if loc.equals?(Bio::Locations.new(location))
already_mapped = true
end
end
if ! already_mapped
self.mappings_as_marker.push(my_mapping)
map.mappings_as_map.push(my_mapping)
end
end
end
# Check whether this marker is mapped to a given Bio::Map::SimpleMap.
# ---
# *Arguments*:
# * _map_: a Bio::Map::SimpleMap object
# *Returns*:: true or false
def mapped_to?(map)
unless map.class.include?(Bio::Map::ActsLikeMap)
raise "[Error] map is not object that implements Bio::Map::ActsLikeMap"
end
mapped = false
self.mappings_as_marker.each do |mapping|
if mapping.map == map
mapped = true
return mapped
end
end
return mapped
end
# Return all positions of this marker on a given map.
# ---
# *Arguments*:
# * _map_: an object that mixes in Bio::Map::ActsLikeMap
# *Returns*:: array of Bio::Location objects
def positions_on(map)
unless map.class.include?(Bio::Map::ActsLikeMap)
raise "[Error] map is not object that implements Bio::Map::ActsLikeMap"
end
positions = Array.new
self.mappings_as_marker.each do |mapping|
if mapping.map == map
positions.push(mapping.location)
end
end
return positions
end
# Return all mappings of this marker on a given map.
# ---
# *Arguments*:
# * _map_: an object that mixes in Bio::Map::ActsLikeMap
# *Returns*:: array of Bio::Map::Mapping objects
def mappings_on(map)
unless map.class.include?(Bio::Map::ActsLikeMap)
raise "[Error] map is not object that implements Bio::Map::ActsLikeMap"
end
m = Array.new
self.mappings_as_marker.each do |mapping|
if mapping.map == map
m.push(mapping)
end
end
return m
end
end # ActsLikeMarker
# == Description
#
# Creates a new Bio::Map::Mapping object, which links Bio::Map::ActsAsMap-
# and Bio::Map::ActsAsMarker-like objects. This class is typically not
# accessed directly, but through map- or marker-like objects.
class Mapping
include Comparable
# Creates a new Bio::Map::Mapping object
# ---
# *Arguments*:
# * _map_: a Bio::Map::SimpleMap object
# * _marker_: a Bio::Map::Marker object
# * _location_: a Bio::Locations object
def initialize(map, marker, location = nil)
@map, @marker, @location = map, marker, location
end
attr_accessor :map, :marker, :location
# Compares the location of this mapping to another mapping.
# ---
# *Arguments*:
# * other_mapping: Bio::Map::Mapping object
# *Returns*::
# * 1 if self < other location
# * -1 if self > other location
# * 0 if both location are the same
# * nil if the argument is not a Bio::Location object
def <=>(other)
unless other.kind_of?(Bio::Map::Mapping)
raise "[Error] markers are not comparable"
end
unless @map.equal?(other.map)
raise "[Error] maps have to be the same"
end
return self.location[0].<=>(other.location[0])
end
end # Mapping
# == Description
#
# This class handles the essential storage of name, type and units
# of a map. It includes Bio::Map::ActsLikeMap, and therefore
# supports the methods of that module.
#
# == Usage
#
# my_map1 = Bio::Map::SimpleMap.new('RH_map_ABC (2006)', 'RH', 'cR')
# my_map1.add_marker(Bio::Map::Marker.new('marker_a', '17')
# my_map1.add_marker(Bio::Map::Marker.new('marker_b', '5')
#
class SimpleMap
include Bio::Map::ActsLikeMap
# Builds a new Bio::Map::SimpleMap object
# ---
# *Arguments*:
# * name: name of the map
# * type: type of the map (e.g. linkage, radiation_hybrid, cytogenetic, ...)
# * units: unit of the map (e.g. cM, cR, ...)
# *Returns*:: new Bio::Map::SimpleMap object
def initialize(name = nil, type = nil, length = nil, units = nil)
@name, @type, @length, @units = name, type, length, units
@mappings_as_map = Array.new
end
# Name of the map
attr_accessor :name
# Type of the map
attr_accessor :type
# Length of the map
attr_accessor :length
# Units of the map
attr_accessor :units
# Mappings
attr_accessor :mappings_as_map
end # SimpleMap
# == Description
#
# This class handles markers that are anchored to a Bio::Map::SimpleMap.
# It includes Bio::Map::ActsLikeMarker, and therefore supports the
# methods of that module.
#
# == Usage
#
# marker_a = Bio::Map::Marker.new('marker_a')
# marker_b = Bio::Map::Marker.new('marker_b')
#
class Marker
include Bio::Map::ActsLikeMarker
# Builds a new Bio::Map::Marker object
# ---
# *Arguments*:
# * name: name of the marker
# *Returns*:: new Bio::Map::Marker object
def initialize(name)
@name = name
@mappings_as_marker = Array.new
end
# Name of the marker
attr_accessor :name
# Mappings
attr_accessor :mappings_as_marker
end # Marker
end # Map
end # Bio
|