bio-ensembl 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/.document +5 -0
  2. data/Gemfile +20 -0
  3. data/Gemfile.lock +40 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +71 -0
  7. data/VERSION +1 -0
  8. data/bin/ensembl +40 -0
  9. data/bin/variation_effect_predictor +106 -0
  10. data/bio-ensembl.gemspec +190 -0
  11. data/lib/bio-ensembl.rb +65 -0
  12. data/lib/bio-ensembl/core/activerecord.rb +1812 -0
  13. data/lib/bio-ensembl/core/collection.rb +64 -0
  14. data/lib/bio-ensembl/core/project.rb +262 -0
  15. data/lib/bio-ensembl/core/slice.rb +657 -0
  16. data/lib/bio-ensembl/core/transcript.rb +409 -0
  17. data/lib/bio-ensembl/core/transform.rb +95 -0
  18. data/lib/bio-ensembl/db_connection.rb +205 -0
  19. data/lib/bio-ensembl/variation/activerecord.rb +536 -0
  20. data/lib/bio-ensembl/variation/variation_feature.rb +376 -0
  21. data/lib/bio-ensembl/variation/variation_feature62.rb +444 -0
  22. data/samples/ensembl_genomes_example.rb +60 -0
  23. data/samples/examples_perl_tutorial.rb +125 -0
  24. data/samples/small_example_ruby_api.rb +34 -0
  25. data/samples/variation_effect_predictor_data.txt +4 -0
  26. data/samples/variation_example.rb +67 -0
  27. data/test/data/seq_c6qbl.fa +10 -0
  28. data/test/data/seq_cso19_coding.fa +16 -0
  29. data/test/data/seq_cso19_transcript.fa +28 -0
  30. data/test/data/seq_drd3_gene.fa +838 -0
  31. data/test/data/seq_drd3_transcript.fa +22 -0
  32. data/test/data/seq_drd4_transcript.fa +24 -0
  33. data/test/data/seq_forward_composite.fa +1669 -0
  34. data/test/data/seq_par_boundary.fa +169 -0
  35. data/test/data/seq_rnd3_transcript.fa +47 -0
  36. data/test/data/seq_ub2r1_coding.fa +13 -0
  37. data/test/data/seq_ub2r1_gene.fa +174 -0
  38. data/test/data/seq_ub2r1_transcript.fa +26 -0
  39. data/test/data/seq_y.fa +2 -0
  40. data/test/default/test_connection.rb +60 -0
  41. data/test/default/test_releases.rb +130 -0
  42. data/test/ensembl_genomes/test_collection.rb +122 -0
  43. data/test/ensembl_genomes/test_gene.rb +46 -0
  44. data/test/ensembl_genomes/test_slice.rb +65 -0
  45. data/test/ensembl_genomes/test_variation.rb +38 -0
  46. data/test/helper.rb +18 -0
  47. data/test/release_50/core/test_project.rb +210 -0
  48. data/test/release_50/core/test_project_human.rb +52 -0
  49. data/test/release_50/core/test_relationships.rb +72 -0
  50. data/test/release_50/core/test_sequence.rb +170 -0
  51. data/test/release_50/core/test_slice.rb +116 -0
  52. data/test/release_50/core/test_transcript.rb +125 -0
  53. data/test/release_50/core/test_transform.rb +217 -0
  54. data/test/release_50/variation/test_activerecord.rb +138 -0
  55. data/test/release_50/variation/test_variation.rb +79 -0
  56. data/test/release_53/core/test_gene.rb +61 -0
  57. data/test/release_53/core/test_project.rb +91 -0
  58. data/test/release_53/core/test_project_human.rb +61 -0
  59. data/test/release_53/core/test_slice.rb +42 -0
  60. data/test/release_53/core/test_transform.rb +57 -0
  61. data/test/release_53/variation/test_activerecord.rb +137 -0
  62. data/test/release_53/variation/test_variation.rb +66 -0
  63. data/test/release_56/core/test_gene.rb +61 -0
  64. data/test/release_56/core/test_project.rb +91 -0
  65. data/test/release_56/core/test_slice.rb +49 -0
  66. data/test/release_56/core/test_transform.rb +57 -0
  67. data/test/release_56/variation/test_activerecord.rb +141 -0
  68. data/test/release_56/variation/test_consequence.rb +131 -0
  69. data/test/release_56/variation/test_variation.rb +63 -0
  70. data/test/release_60/core/test_gene.rb +61 -0
  71. data/test/release_60/core/test_project_human.rb +34 -0
  72. data/test/release_60/core/test_slice.rb +42 -0
  73. data/test/release_60/core/test_transcript.rb +120 -0
  74. data/test/release_60/core/test_transform.rb +57 -0
  75. data/test/release_60/variation/test_activerecord.rb +216 -0
  76. data/test/release_60/variation/test_consequence.rb +153 -0
  77. data/test/release_60/variation/test_variation.rb +64 -0
  78. data/test/release_62/core/test_gene.rb +42 -0
  79. data/test/release_62/variation/test_activerecord.rb +86 -0
  80. data/test/release_62/variation/test_consequence.rb +191 -0
  81. metadata +287 -0
@@ -0,0 +1,409 @@
1
+ #
2
+ # = ensembl/core/transcript.rb - ActiveRecord mapping to Ensembl core for transcript
3
+ #
4
+ # Copyright:: Copyright (C) 2007 Jan Aerts <http://jandot.myopenid.com>
5
+ # License:: The Ruby License
6
+ #
7
+ # @author Jan Aerts
8
+ nil
9
+ module Ensembl
10
+ nil
11
+ module Core
12
+ # The Intron class describes an intron.
13
+ #
14
+ # This class does _not_ use ActiveRecord and is only defined within the API.
15
+ # There is no _introns_ table in the Ensembl database.
16
+ #
17
+ # This class includes the mixin Sliceable, which means that it is mapped
18
+ # to a SeqRegion object and a Slice can be created for objects o this
19
+ # class. See Sliceable and Slice for more information.
20
+ #
21
+ # @example
22
+ # exon1 = Ensembl::Core::Exon.find(292811)
23
+ # exon2 = Ensembl::Core::Exon.find(292894)
24
+ # intron = Ensembl::Core::Intron.new(exon1,exon2)
25
+ # puts intron.to_yaml
26
+ #
27
+ # transcript = Ensembl::Core::Transcript.find(58972)
28
+ # puts transcript.introns.to_yaml
29
+ class Intron
30
+ include Sliceable
31
+ attr_accessor :seq_region, :seq_region_start, :seq_region_end, :seq_region_strand
32
+ attr_accessor :previous_exon, :next_exon, :transcript
33
+
34
+ def initialize(exon_1, exon_2)
35
+ # Check if these are actually two adjacent exons from the same transcript
36
+ ok = true
37
+
38
+ transcript = nil
39
+ exon_1.transcripts.each do |t|
40
+ transcript = t if exon_2.transcripts.include?(t)
41
+ end
42
+ raise ArgumentError, "Arguments should be adjacent exons of same transcript" if transcript.nil?
43
+
44
+ rank_1 = ExonTranscript.find_by_transcript_id_and_exon_id(transcript.id, exon_1.id).rank
45
+ rank_2 = ExonTranscript.find_by_transcript_id_and_exon_id(transcript.id, exon_2.id).rank
46
+ raise ArgumentError, "Arguments should be adjacent exons of same transcript" if (rank_2 - rank_1).abs > 1
47
+
48
+ @previous_exon, @next_exon = [exon_1, exon_2].sort_by{|e| e.seq_region_start}
49
+ @transcript = transcript
50
+ @seq_region = @previous_exon.seq_region
51
+ @seq_region_start = @previous_exon.seq_region_end + 1
52
+ @seq_region_end = @next_exon.seq_region_start - 1
53
+ @seq_region_strand = @previous_exon.seq_region_strand
54
+ end
55
+
56
+ end
57
+
58
+ # The Transcript class provides an interface to the transcript
59
+ # table. This table contains mappings of transcripts for a Gene to a
60
+ # SeqRegion.
61
+ #
62
+ # This class uses ActiveRecord to access data in the Ensembl database.
63
+ # See the general documentation of the Ensembl module for
64
+ # more information on what this means and what methods are available.
65
+ #
66
+ # This class includes the mixin Sliceable, which means that it is mapped
67
+ # to a SeqRegion object and a Slice can be created for objects of this
68
+ # class. See Sliceable and Slice for more information.
69
+ #
70
+ # @example
71
+ # #TODO
72
+ class Transcript < DBConnection
73
+ include Sliceable
74
+
75
+ set_table_name 'transcript'
76
+ set_primary_key 'transcript_id'
77
+
78
+ belongs_to :gene
79
+ belongs_to :seq_region
80
+ has_one :transcript_stable_id
81
+ has_many :transcript_attribs
82
+
83
+ has_many :exon_transcripts
84
+ has_many :exons, :through => :exon_transcripts, :order => "exon_transcript.rank"
85
+
86
+ has_one :translation
87
+
88
+ has_many :object_xrefs, :foreign_key => 'ensembl_id', :conditions => "ensembl_object_type = 'Transcript'"
89
+ has_many :xrefs, :through => :object_xrefs
90
+
91
+ has_many :transcript_supporting_features
92
+ has_many :dna_align_features, :through => :transcript_supporting_features, :conditions => ["feature_type = 'dna_align_feature'"]
93
+ has_many :protein_align_features, :through => :transcript_supporting_features, :conditions => ["feature_type = 'protein_align_feature'"]
94
+
95
+ alias attribs transcript_attribs
96
+
97
+ # The Transcript#exons method returns the exons for this transcript in
98
+ # the order of their ranks in the exon_transcript table.
99
+ #
100
+ # @return [Array<Exon>] Sorted array of Exon objects
101
+ #def exons
102
+ # if @exons.nil?
103
+ # @exons = self.exon_transcripts(:include => [:exons]).sort_by{|et| et.rank.to_i}.collect{|et| et.exon}
104
+ # end
105
+ # return @exons
106
+ #end
107
+
108
+ # The Transcript#introns methods returns the introns for this transcript
109
+ #
110
+ # @return [Array<Intron>] Sorted array of Intron objects
111
+ def introns
112
+ if @introns.nil?
113
+ @introns = Array.new
114
+ if self.exons.length > 1
115
+ self.exons.each_with_index do |exon, index|
116
+ next if index == 0
117
+ @introns.push(Intron.new(self.exons[index - 1], exon))
118
+ end
119
+ end
120
+ end
121
+ return @introns
122
+ end
123
+
124
+ # The Transcript#stable_id method returns the stable ID of the transcript.
125
+ #
126
+ # @return [String] Ensembl stable ID of the transcript.
127
+ def stable_id
128
+ return self.transcript_stable_id.stable_id
129
+ end
130
+
131
+ # The Transcript#display_label method returns the default name of the transcript.
132
+ def display_label
133
+ return Xref.find(self.display_xref_id).display_label
134
+ end
135
+ alias :display_name :display_label
136
+ alias :label :display_label
137
+ alias :name :display_label
138
+
139
+ # The Transcript#find_all_by_stable_id class method returns an array of
140
+ # transcripts with the given stable_id. If none were found, an empty
141
+ # array is returned.
142
+ def self.find_all_by_stable_id(stable_id)
143
+ answer = Array.new
144
+ transcript_stable_id_objects = Ensembl::Core::TranscriptStableId.find_all_by_stable_id(stable_id)
145
+ transcript_stable_id_objects.each do |transcript_stable_id_object|
146
+ answer.push(Ensembl::Core::Transcript.find(transcript_stable_id_object.transcript_id))
147
+ end
148
+
149
+ return answer
150
+ end
151
+
152
+ # The Transcript#find_all_by_stable_id class method returns a
153
+ # transcripts with the given stable_id. If none was found, nil is returned.
154
+ def self.find_by_stable_id(stable_id)
155
+ all = self.find_all_by_stable_id(stable_id)
156
+ if all.length == 0
157
+ return nil
158
+ else
159
+ return all[0]
160
+ end
161
+ end
162
+
163
+ # The Transcript#find_by_stable_id class method fetches a Transcript object based on
164
+ # its stable ID (i.e. the "ENST" accession number). If the name is
165
+ # not found, it returns nil.
166
+ def self.find_by_stable_id(stable_id)
167
+ transcript_stable_id = TranscriptStableId.find_by_stable_id(stable_id)
168
+ if transcript_stable_id.nil?
169
+ return nil
170
+ else
171
+ return transcript_stable_id.transcript
172
+ end
173
+ end
174
+
175
+ # The Transcript#seq method returns the full sequence of all concatenated
176
+ # exons.
177
+ def seq
178
+ if @seq.nil?
179
+ @seq = ''
180
+ self.exons.each do |exon|
181
+ @seq += exon.seq
182
+ end
183
+ end
184
+ return @seq
185
+ end
186
+
187
+ # The Transcript#cds_seq method returns the coding sequence of the transcript,
188
+ # i.e. the concatenated sequence of all exons minus the UTRs.
189
+ def cds_seq
190
+ cds_length = self.coding_region_cdna_end - self.coding_region_cdna_start + 1
191
+
192
+ return self.seq[(self.coding_region_cdna_start - 1), cds_length]
193
+ end
194
+
195
+ # The Transcript#five_prime_utr_seq method returns the sequence of the
196
+ # 5'UTR of the transcript.
197
+ def five_prime_utr_seq
198
+ return self.seq[0, self.coding_region_cdna_start - 1]
199
+ end
200
+
201
+ # The Transcript#three_prime_utr_seq method returns the sequence of the
202
+ # 3'UTR of the transcript.
203
+ def three_prime_utr_seq
204
+ return self.seq[self.coding_region_cdna_end..-1]
205
+ end
206
+
207
+ # The Transcript#protein_seq method returns the sequence of the
208
+ # protein of the transcript.
209
+ def protein_seq
210
+ return Bio::Sequence::NA.new(self.cds_seq).translate.seq
211
+ end
212
+
213
+
214
+ # The Transcript#coding_region_genomic_start returns the start position
215
+ # of the CDS in genomic coordinates. Note that, in contrast to
216
+ # Transcript#coding_region_cdna_start, the CDS start position is _always_
217
+ # ''left'' of the end position. So for transcripts on the reverse strand,
218
+ # the CDS start position is at the border of the 3'UTR instead of the
219
+ # 5'UTR.
220
+ def coding_region_genomic_start
221
+ strand = self.translation.start_exon.seq_region_strand
222
+ if strand == 1
223
+ return self.translation.start_exon.seq_region_start + ( self.translation.seq_start - 1 )
224
+ else
225
+ return self.translation.end_exon.seq_region_end - ( self.translation.seq_end - 1 )
226
+ end
227
+ end
228
+
229
+ # The Transcript#coding_region_genomic_end returns the stop position
230
+ # of the CDS in genomic coordinates. Note that, in contrast to
231
+ # Transcript#coding_region_cdna_end, the CDS stop position is _always_
232
+ # ''right'' of the start position. So for transcripts on the reverse strand,
233
+ # the CDS stop position is at the border of the 5'UTR instead of the
234
+ # 3'UTR.
235
+ def coding_region_genomic_end
236
+ strand = self.translation.start_exon.seq_region_strand
237
+ if strand == 1
238
+ return self.translation.end_exon.seq_region_start + ( self.translation.seq_end - 1 )
239
+ else
240
+ return self.translation.start_exon.seq_region_end - ( self.translation.seq_start - 1 )
241
+ end
242
+ end
243
+
244
+ # The Transcript#coding_region_cdna_start returns the start position
245
+ # of the CDS in cDNA coordinates. Note that, in contrast to the
246
+ # Transcript#coding_region_genomic_start, the CDS start position is
247
+ # _always_ at the border of the 5'UTR. So for genes on the reverse
248
+ # strand, the CDS start position in cDNA coordinates will be ''right''
249
+ # of the CDS stop position.
250
+ def coding_region_cdna_start
251
+ answer = 0
252
+
253
+ self.exons.each do |exon|
254
+ if exon == self.translation.start_exon
255
+ answer += self.translation.seq_start
256
+ return answer
257
+ else
258
+ answer += exon.length
259
+ end
260
+ end
261
+
262
+ end
263
+
264
+ # The Transcript#coding_region_cdna_end returns the stop position
265
+ # of the CDS in cDNA coordinates. Note that, in contrast to the
266
+ # Transcript#coding_region_genomic_end, the CDS start position is
267
+ # _always_ at the border of the 3'UTR. So for genes on the reverse
268
+ # strand, the CDS start position in cDNA coordinates will be ''right''
269
+ # of the CDS stop position.
270
+ def coding_region_cdna_end
271
+ answer = 0
272
+
273
+ self.exons.each do |exon|
274
+ if exon == self.translation.end_exon
275
+ answer += self.translation.seq_end
276
+ return answer
277
+ else
278
+ answer += exon.length
279
+ end
280
+ end
281
+ end
282
+
283
+
284
+ # The Transcript#exon_for_position identifies the exon that covers a given
285
+ # genomic position. Returns the exon object, or nil if in intron.
286
+ def exon_for_genomic_position(pos)
287
+ if pos < self.seq_region_start or pos > self.seq_region_end
288
+ raise RuntimeError, "Position has to be within transcript"
289
+ end
290
+ self.exons.each do |exon|
291
+ if exon.start <= pos and exon.stop >= pos
292
+ return exon
293
+ end
294
+ end
295
+ return nil
296
+ end
297
+
298
+ # The Transcript#exon_for_position identifies the exon that covers a given
299
+ # position of the cDNA.
300
+ def exon_for_cdna_position(pos)
301
+ # FIXME: Still have to check for when pos is outside of scope of cDNA.
302
+ accumulated_exon_length = 0
303
+
304
+ self.exons.each do |exon|
305
+ accumulated_exon_length += exon.length
306
+ if accumulated_exon_length > pos
307
+ return exon
308
+ end
309
+ end
310
+ raise RuntimeError, "Position outside of cDNA scope"
311
+ end
312
+
313
+ # The Transcript#cdna2genomic method converts cDNA coordinates to
314
+ # genomic coordinates for this transcript.
315
+ #
316
+ # @param [Integer] pos Position on the cDNA
317
+ # @return [Integer] Position on the genomic DNA
318
+ def cdna2genomic(pos)
319
+ #FIXME: Still have to check for when pos is outside of scope of cDNA.
320
+ # Identify the exon we're looking at.
321
+ exon_with_target = self.exon_for_cdna_position(pos)
322
+
323
+ accumulated_position = 0
324
+ ex = self.exons.sort_by {|e| e.seq_region_start}
325
+ ex.reverse! if self.strand == -1
326
+ ex.each do |exon|
327
+ if exon == exon_with_target
328
+ length_to_be_taken_from_exon = pos - (accumulated_position + 1)
329
+ if self.strand == -1
330
+ return exon.seq_region_end - length_to_be_taken_from_exon
331
+ else
332
+ return exon.seq_region_start + length_to_be_taken_from_exon
333
+ end
334
+ else
335
+ accumulated_position += exon.length
336
+ end
337
+ end
338
+ end
339
+
340
+ # The Transcript#cds2genomic method converts CDS coordinates to
341
+ # genomic coordinates for this transcript.
342
+ #
343
+ # @param [Integer] pos Position on the CDS
344
+ # @return [Integer] Position on the genomic DNA
345
+ def cds2genomic(pos)
346
+ return self.cdna2genomic(pos + self.coding_region_cdna_start)
347
+ end
348
+
349
+ # The Transcript#pep2genomic method converts peptide coordinates to
350
+ # genomic coordinates for this transcript.
351
+ #
352
+ # @param [Integer] pos Aminoacid position on the protein
353
+ # @return [Integer] Position on the genomic DNA
354
+ def pep2genomic(pos)
355
+ raise NotImplementedError
356
+ end
357
+
358
+ # The Transcript#genomic2cdna method converts genomic coordinates to
359
+ # cDNA coordinates for this transcript.
360
+ #
361
+ # @param [Integer] pos Position on the genomic DNA
362
+ # @return [Integer] Position on the cDNA
363
+ def genomic2cdna(pos)
364
+ #FIXME: Still have to check for when pos is outside of scope of cDNA.
365
+ # Identify the exon we're looking at.
366
+ exon_with_target = self.exon_for_genomic_position(pos)
367
+
368
+ accumulated_position = 0
369
+ ex = self.exons.sort_by {|e| e.seq_region_start}
370
+ ex.reverse! if self.strand == -1
371
+ ex.each do |exon|
372
+ if exon.stable_id == exon_with_target.stable_id
373
+ if self.strand == 1
374
+ accumulated_position += ( pos - exon.start) +1
375
+ else
376
+ accumulated_position += ( exon.stop - pos ) +1
377
+ end
378
+ return accumulated_position
379
+ else
380
+ accumulated_position += exon.length
381
+ end
382
+ end
383
+ return RuntimeError, "Position outside of cDNA scope"
384
+ end
385
+
386
+ # The Transcript#genomic2cds method converts genomic coordinates to
387
+ # CDS coordinates for this transcript.
388
+ #
389
+ # @param [Integer] pos Position on the genomic DNA
390
+ # @return [Integer] Position on the CDS
391
+ def genomic2cds(pos)
392
+ return self.genomic2cdna(pos) - self.coding_region_cdna_start
393
+ end
394
+
395
+ # The Transcript#genomic2pep method converts genomic coordinates to
396
+ # peptide coordinates for this transcript.
397
+ #
398
+ # @param [Integer] pos Base position on the genomic DNA
399
+ # @return [Integer] Aminoacid position in the protein
400
+ # *Arguments*:
401
+ # * pos:: position on the chromosome (required)
402
+ # *Returns*::
403
+ def genomic2pep(pos)
404
+ raise NotImplementedError
405
+ end
406
+
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,95 @@
1
+ #
2
+ # = bio/api/ensembl/core/transform.rb - transform positions for Ensembl Slice
3
+ #
4
+ # Copyright:: Copyright (C) 2007 Jan Aerts <http://jandot.myopenid.com>
5
+ # License:: The Ruby License
6
+ #
7
+ # @author Jan Aerts
8
+ nil
9
+ module Ensembl
10
+ nil
11
+ module Core
12
+ nil
13
+ module Sliceable
14
+ # The #transform method is used to transfer coordinates for a feature
15
+ # from one coordinate system to another. It basically creates a clone of
16
+ # the original feature and changes the seq_region, start position, stop
17
+ # position and strand.
18
+ #
19
+ # Suppose you have a feature on a
20
+ # contig in human (let's say on contig AC000031.6.1.38703) and you
21
+ # want to know the coordinates on the chromosome. This is a
22
+ # transformation of coordinates from a higher ranked coordinate system to
23
+ # a lower ranked coordinate system. Transformations can also be done
24
+ # from a chromosome to the contig level.
25
+ #
26
+ # In contrast to the #project method of Sliceables, the
27
+ # coordinates of a feature can only transformed to the target
28
+ # coordinate system if there is no ambiguity to which SeqRegion.
29
+ #
30
+ # For example, gene A can be transferred from the chromosome system to
31
+ # the clone coordinate system, whereas gene B can not.
32
+ #
33
+ # gene A gene B
34
+ # |---<=====>--------------------<=====>----------------| chromosome
35
+ #
36
+ # |-----------| |-------| |---------| clones
37
+ # |-----------| |-------| |--------|
38
+ #
39
+ # gene_a.transform('clone') --> gene
40
+ # gene_b.transform('clone') --> nil
41
+ #
42
+ # At the moment, transformations can only be done if the two coordinate
43
+ # systems are linked directly in the 'assembly' table.
44
+ #
45
+ # @example
46
+ # # Get a gene in cow and transform to scaffold level
47
+ # # (i.e. going from a high rank coord system to a lower rank coord
48
+ # # system)
49
+ # # Cow scaffold Chr4.10 lies on Chr4 from 8030345 to 10087277 on the
50
+ # # reverse strand
51
+ # source_gene = Gene.find(2408)
52
+ # target_gene = source_gene.transform('scaffold')
53
+ # puts source_gene.seq_region.name #--> 4
54
+ # puts source_gene.seq_region_start #--> 8104409
55
+ # puts source_gene.seq_region_end #--> 8496477
56
+ # puts source_gene.seq_region_strand #--> -1
57
+ # puts target_gene.seq_region.name #--> Chr4.003.10
58
+ # puts target_gene.seq_region_start #--> 1590800
59
+ # puts target_gene.seq_region_end #--> 1982868
60
+ # puts target_gene.seq_region_strand #--> 1
61
+ #
62
+ # @param [String] coord_system_name Name of the coordinate system to
63
+ # transform the coordinates to
64
+ # @return Nil or an object of the same class
65
+ # as self
66
+ def transform(coord_system_name)
67
+ #-
68
+ # There are two things I can do:
69
+ # (1) just use project
70
+ # (2) avoid doing all the calculations in project if the source slice
71
+ # covers multiple target slices, and _then_ go for project.
72
+ # Let's go for nr 1 for the moment and optimize later.
73
+ #+
74
+
75
+ if self.slice.seq_region.coord_system.name == coord_system_name
76
+ return self
77
+ end
78
+
79
+ target_slices = self.slice.project(coord_system_name)
80
+ if target_slices.length > 1
81
+ return nil
82
+ else
83
+ clone = self.clone
84
+ clone.seq_region_id = target_slices[0].seq_region.id
85
+ clone.seq_region_start = target_slices[0].start
86
+ clone.seq_region_end = target_slices[0].stop
87
+
88
+ clone.seq_region_strand = target_slices[0].strand * self.strand
89
+
90
+ return clone
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end