File Coverage

Bio/Seq/SimulatedRead.pm
Criterion Covered Total %
statement 224 244 91.8
branch 111 138 80.4
condition 27 44 61.3
subroutine 22 22 100.0
pod 7 7 100.0
total 391 455 85.9


line stmt bran cond sub pod time code
1             package Bio::Seq::SimulatedRead;
2              
3              
4             =head1 NAME
5              
6             Bio::Seq::SimulatedRead - Read with sequencing errors taken from a reference sequence
7              
8             =head1 SYNOPSIS
9              
10             use Bio::Seq::SimulatedRead;
11             use Bio::PrimarySeq;
12            
13             # Create a reference sequence
14             my $genome = Bio::PrimarySeq->new( -id => 'human_chr2',
15             -seq => 'TAAAAAAACCCCTG',
16             -desc => 'The human genome' );
17              
18             # A 10-bp error-free read taken from a genome
19             my $read = Bio::Seq::SimulatedRead->new(
20             -reference => $genome , # sequence to generate the read from
21             -id => 'read001', # read ID
22             -start => 3 , # start of the read on the genome forward strand
23             -end => 12 , # end of the read on the genome forward strand
24             -strand => 1 , # genome strand that the read is on
25             );
26              
27             # Display the sequence of the read
28             print $read->seq."\n";
29              
30             # Add a tag or MID to the beginning of the read
31             $read->mid('ACGT');
32              
33             # Add sequencing errors (error positions are 1-based and relative to the
34             # error-free MID-containing read)
35             my $errors = {};
36             $errors->{'8'}->{'+'} = 'AAA'; # insertion of AAA after residue 8
37             $errors->{'1'}->{'%'} = 'G'; # substitution of residue 1 by a G
38             $errors->{'4'}->{'-'} = undef; # deletion of residue 4
39             $read->errors($errors);
40              
41             # Display the sequence of the read with errors
42             print $read->seq."\n";
43              
44             # String representation of where the read came from and its errors
45             print $read->desc."\n";
46              
47             =head1 DESCRIPTION
48              
49             This object is a simulated read with sequencing errors. The user can provide a
50             reference sequence to take a read from, the position and orientation of the
51             read on the reference sequence, and the sequencing errors to generate.
52              
53             The sequence of the read is automatically calculated based on this information.
54             By default, the description of the reads contain tracking information and will
55             look like this (Bioperl-style):
56              
57             reference=human_chr2 start=3 end=12 strand=-1 mid=ACGT errors=1%G,4-,8+AAA description="The human genome"
58              
59             or Genbank-style:
60              
61             reference=human_chr2 position=complement(3..12) mid=ACGT errors=1%G,4-,8+AAA description="The human genome"
62              
63             Creating a simulated read follows these steps:
64             1/ Define the read start(), end(), strand() and qual_levels() if you want
65             quality scores to be generated. Do not change these values once set because
66             the read will not be updated.
67             2/ Specify the reference sequence that the read should be taken from. Once
68             this is done, you have a fully functional read. Do not use the reference()
69             method again after you have gone to the next step.
70             3/ Use mid() to input a MID (or tag or barcode) to add to the beginning of the
71             read. You can change the MID until you go to next step.
72             4/ Give sequencing error specifications using errors() as the last step. You
73             can do that as many times as you like, and the read will be updated.
74              
75             =head1 AUTHOR
76              
77             Florent E Angly Eflorent . angly @ gmail-dot-comE.
78              
79             Copyright (c) 2011 Florent E Angly.
80              
81             This library is free software; you can redistribute it under the GNU General
82             Public License version 3.
83              
84             =cut
85              
86              
87 1     1   1646 use strict;
  1         1  
  1         23  
88 1     1   4 use warnings;
  1         0  
  1         22  
89 1     1   3 use Bio::LocatableSeq;
  1         2  
  1         19  
90 1     1   3 use base qw( Bio::Seq::Quality Bio::LocatableSeq );
  1         1  
  1         1942  
91              
92              
93             =head2 new
94              
95             Title : new
96             Function : Create a new simulated read object
97             Usage : my $read = Bio::Seq::SimulatedRead->new(
98             -id => 'read001',
99             -reference => $seq_obj ,
100             -errors => $errors ,
101             -start => 10 ,
102             -end => 135 ,
103             -strand => 1 ,
104             );
105             Arguments: -reference => Bio::SeqI, Bio::PrimarySeqI object representing the
106             reference sequence to take the read from. See
107             reference().
108             -errors => Hashref representing the position of errors in the read
109             See errors().
110             -mid => String of a MID to prepend to the read. See mid().
111             -track => Track where the read came from in the read description?
112             See track().
113             -coord_style => Define what coordinate system to use. See coord_style().
114             All other methods from Bio::LocatableSeq are available.
115             Returns : new Bio::Seq::SimulatedRead object
116              
117             =cut
118              
119             sub new {
120 46     46 1 252 my ($class, @args) = @_;
121 46         100 my $self = $class->SUPER::new(@args);
122 46         120 my ($qual_levels, $reference, $mid, $errors, $track, $coord_style) =
123             $self->_rearrange([qw(QUAL_LEVELS REFERENCE MID ERRORS TRACK COORD_STYLE)], @args);
124 46 100       106 $coord_style = defined $coord_style ? $coord_style : 'bioperl';
125 46         63 $self->coord_style($coord_style);
126 46 100       61 $track = defined $track ? $track : 1;
127 46         61 $self->track($track);
128 46 100       75 $qual_levels = defined $qual_levels ? $qual_levels : [];
129 46 50       88 $self->qual_levels($qual_levels) if defined $qual_levels;
130 46 100       75 $self->reference($reference) if defined $reference;
131 46 100       63 $self->mid($mid) if defined $mid;
132 46         46 $self->{_mutated} = 0;
133 46 100       85 $self->errors($errors) if defined $errors;
134 46         180 return $self;
135             }
136              
137              
138             =head2 qual_levels
139              
140             Title : qual_levels
141             Function : Get or set the quality scores to give to the read. By default, if your
142             reference sequence does not have quality scores, no quality scores
143             are generated for the simulated read. The generated quality scores
144             are very basic. If a residue is error-free, it gets the quality score
145             defined for good residues. If the residue has an error (is an
146             addition or a mutation), the residue gets the quality score specified
147             for bad residues. Call the qual_levels() method before using the
148             reference() method.
149             Usage : my $qual_levels = $read->qual_levels( );
150             Arguments: Array reference containing the quality scores to use for:
151             1/ good residues (e.g. 30)
152             2/ bad residues (e.g. 10)
153             Returns : Array reference containing the quality scores to use.
154              
155             =cut
156              
157             sub qual_levels {
158 153     153 1 113 my ($self, $qual_levels) = @_;
159 153 100       186 if (defined $qual_levels) {
160 48 50 66     99 if ( (scalar @$qual_levels != 0) && (scalar @$qual_levels != 2) ) {
161 0         0 $self->throw("The quality score specification must define the score".
162             " to use for good and for bad residues\n");
163             }
164 48         49 $self->{qual_levels} = $qual_levels;
165             }
166 153         258 return $self->{qual_levels};
167             }
168              
169              
170             =head2 reference
171              
172             Title : reference
173             Function : Get or set the reference sequence that the read comes from. Once the
174             reference has been set, you have a functional simulated read which
175             supports all the Bio::LocatableSeq methods. This method must be
176             called after qual_levels() but before mid() or errors().
177             Usage : my $seq_obj = $read->reference();
178             Arguments: Bio::SeqI or Bio::PrimarySeqI object
179             Returns : Bio::SeqI or Bio::PrimarySeqI object
180              
181             =cut
182              
183             sub reference {
184 353     353 1 258 my ($self, $reference) = @_;
185 353 100       400 if (defined $reference) {
186             # Sanity check 1
187 45 50 66     154 if ( (not $reference->isa('Bio::SeqI')) && (not $reference->isa('Bio::PrimarySeqI')) ) {
188 0         0 $self->throw("Expected a Bio::SeqI object as reference, but got: $reference\n");
189             }
190             # Sanity check 2
191 45 50 33     104 if ($self->{mid} || $self->{errors}) {
192 0         0 $self->throw("Cannot change the reference sequence after an MID or ".
193             "sequencing errors have been added to the read\n");
194             }
195             # Use beginning of reference sequence as start default
196 45 100       79 if (not defined $self->start) {
197 40         52 $self->start(1);
198             }
199             # Use end of reference sequence as end default
200 45 100       88 if (not defined $self->end) {
201 40         68 $self->end($reference->length);
202             }
203             # Use strand 1 as strand default
204 45 100       74 if (not defined $self->strand) {
205 39         48 $self->strand(1);
206             }
207             # Set the reference sequence object
208 45         39 $self->{reference} = $reference;
209             # Create a sequence, quality scores and description from the reference
210 45         58 $self->_create_seq;
211 45 100       35 $self->_create_qual if scalar @{$self->qual_levels};
  45         68  
212 45 100       65 $self->_create_desc if $self->track;
213             }
214 353         500 return $self->{reference};
215             }
216              
217              
218             sub _create_seq {
219 45     45   36 my $self = shift;
220             # Get a truncation of the reference sequence
221 45         50 my $reference = $self->reference;
222 45         55 my $read_obj = $reference->trunc( $self->start, $self->end );
223             # Reverse complement the read if needed
224 45 100       80 if ($self->strand == -1) {
225 4         12 $read_obj = $read_obj->revcom();
226             }
227 45         82 $self->seq($read_obj->seq);
228 45         89 return 1;
229             }
230              
231              
232             sub _create_qual {
233 13     13   13 my $self = shift;
234 13         17 $self->qual([ ($self->qual_levels->[0]) x ($self->end - $self->start + 1) ]);
235 13         14 return 1;
236             }
237              
238              
239             sub _create_desc {
240             # Create the read description of the error-free read
241 45     45   34 my $self = shift;
242             # Reference sequence ID
243 45         37 my $desc_str = '';
244 45         52 my $ref_id = $self->reference->id;
245 45 100       71 if (defined $ref_id) {
246 43         77 $desc_str .= 'reference='.$ref_id.' ';
247             }
248             # Position of read on reference sequence: start, end and strand
249 45         75 my $strand = $self->strand;
250 45 100       55 if ($self->coord_style eq 'bioperl') {
251 41         74 $desc_str .= 'start='.$self->start.' end='.$self->end.' ';
252 41 50       64 if (defined $strand) {
253             # Strand of the reference sequence that the read is on
254 41 100       63 $strand = '+1' if $strand == 1;
255 41         47 $desc_str .= 'strand='.$strand.' ';
256             }
257             } else {
258 4 100 66     17 if ( (defined $strand) && ($strand == -1) ) {
259             # Reverse complemented
260 1         2 $desc_str .= 'position=complement('.$self->start.'..'.$self->end.') ';
261             } else {
262             # Regular (forward) orientation
263 3         9 $desc_str .= 'position='.$self->start.'..'.$self->end.' ';
264             }
265             }
266             # Description of the original sequence
267 45         51 my $ref_desc = $self->reference->desc;
268 45 100 66     47 if ( (defined $self->reference->desc) && ($self->reference->desc !~ m/^\s*$/) ) {
269 42         42 $ref_desc =~ s/"/\\"/g; # escape double-quotes to \"
270 42         59 $desc_str .= 'description="'.$ref_desc.'" ';
271             }
272 45         130 $desc_str =~ s/\s$//g;
273             # Record new description
274 45         68 $self->desc($desc_str);
275 45         45 return 1;
276             }
277              
278              
279             =head2 mid
280              
281             Title : mid
282             Function : Get or set a multiplex identifier (or MID, or tag, or barcode) to
283             add to the read. By default, no MID is used. This method must be
284             called after reference() but before errors().
285             Usage : my $mid = read->mid();
286             Arguments: MID sequence string (e.g. 'ACGT')
287             Returns : MID sequence string
288              
289             =cut
290              
291             sub mid {
292 11     11 1 14 my ($self, $mid) = @_;
293 11 100       20 if (defined $mid) {
294             # Sanity check 1
295 8 50       11 if (not defined $self->reference) {
296 0         0 $self->throw("Cannot add MID because the reference sequence was not ".
297             "set\n");
298             }
299             # Sanity check 2
300 8 50       16 if ($self->{errors}) {
301 0         0 $self->throw("Cannot add an MID after sequencing errors have been ".
302             "introduced in the read\n");
303             }
304             # Sanity check 3
305 8 50       15 if (not $self->validate_seq($mid)) {
306 0         0 $self->throw("MID is not a valid DNA sequence\n");
307             }
308             # Update sequence, quality scores and description with the MID
309 8         15 $self->_update_seq_mid($mid);
310 8 100       5 $self->_update_qual_mid($mid) if scalar @{$self->qual_levels};
  8         10  
311 8 50       15 $self->_update_desc_mid($mid) if $self->track;
312             # Set the MID value
313 8         12 $self->{mid} = $mid;
314             }
315             return $self->{mid}
316 11         22 }
317              
318              
319             sub _update_seq_mid {
320             # Update the MID of a sequence
321 8     8   7 my ($self, $mid) = @_;
322             # Remove old MID
323 8         12 my $seq = $self->seq;
324 8         21 my $old_mid = $self->{mid};
325 8 100       12 if (defined $old_mid) {
326 2         20 $seq =~ s/^$old_mid//;
327             }
328             # Add new MID
329 8         10 $seq = $mid . $seq;
330 8         15 $self->seq( $seq );
331 8         8 return 1;
332             }
333              
334              
335             sub _update_qual_mid {
336             # Update the MID of a quality scores
337 4     4   5 my ($self, $mid) = @_;
338             # Remove old MID
339 4         8 my $qual = $self->qual;
340 4         6 my $old_mid = $self->{mid};
341 4 100       7 if (defined $old_mid) {
342 1         3 splice @$qual, 0, length($old_mid);
343             }
344 4         6 $qual = [($self->qual_levels->[0]) x length($mid), @$qual];
345 4         7 $self->qual( $qual );
346 4         4 return 1;
347             }
348              
349              
350             sub _update_desc_mid {
351             # Update MID specifications in the read description
352 9     9   10 my ($self, $mid) = @_;
353 9 100       11 if ($mid) {
354             # Sequencing errors introduced in the read
355 7         9 my $mid_str = "mid=".$mid;
356 7         13 my $desc_str = $self->desc;
357 7         67 $desc_str =~ s/((position|strand)=\S+)( mid=\S+)?/$1 $mid_str/g;
358 7         14 $self->desc( $desc_str );
359             }
360 9         9 return 1;
361             }
362              
363              
364             =head2 errors
365              
366             Title : errors
367             Function : Get or set the sequencing errors and update the read. By default, no
368             errors are made. This method must be called after the mid() method.
369             Usage : my $errors = $read->errors();
370             Arguments: Reference to a hash of the position and nature of sequencing errors.
371             The positions are 1-based relative to the error-free MID-containing
372             read (not relative to the reference sequence). For example:
373             $errors->{34}->{'%'} = 'T' ; # substitution of residue 34 by a T
374             $errors->{23}->{'+'} = 'GG' ; # insertion of GG after residue 23
375             $errors->{45}->{'-'} = undef; # deletion of residue 45
376             Substitutions and deletions are for a single residue, but additions
377             can be additions of several residues.
378             An alternative way to specify errors is by using array references
379             instead of scalar for the hash values. This allows to specify
380             redundant mutations. For example, the case presented above would
381             result in the same read sequence as the example below:
382             $errors->{34}->{'%'} = ['C', 'T'] ; # substitution by a C and then a T
383             $errors->{23}->{'+'} = ['G', 'G'] ; # insertion of G and then a G
384             $errors->{45}->{'-'} = [undef, undef]; # deletion of residue, and again
385             Returns : Reference to a hash of the position and nature of sequencing errors.
386              
387             =cut
388              
389             sub errors {
390 93     93 1 64 my ($self, $errors) = @_;
391 93 100       132 if (defined $errors) {
392             # Verify that we have a hashref
393 28 50 33     85 if ( (not defined ref $errors) || (not ref $errors eq 'HASH') ) {
394 0         0 $self->throw("Error specification has to be a hashref. Got: $errors\n");
395             }
396             # Verify that we have a reference sequence
397 28 50       36 if (not defined $self->reference) {
398 0         0 $self->throw("Cannot add errors because the reference sequence was not set\n");
399             }
400             # Convert scalar error specs to arrayref specs
401 28         40 $errors = $self->_scalar_to_arrayref($errors);
402             # Check validity of error specifications
403 28         42 $errors = $self->_validate_error_specs($errors);
404             # Set the error specifications
405 28         33 $self->{errors} = $errors;
406             # Need to recalculate the read from the reference if previously mutated
407 28 50       93 if ($self->{_mutated}) {
408 0         0 $self->_create_seq;
409 0 0       0 $self->_create_qual if scalar @{$self->qual_levels};
  0         0  
410 0 0       0 $self->_create_desc if $self->track;
411             }
412             # Now mutate the read, quality score and description
413 28         43 $self->_update_seq_errors;
414 28 100       22 $self->_update_qual_errors if scalar @{$self->qual_levels};
  28         34  
415 28 50       39 $self->_update_desc_errors if $self->track;
416              
417             }
418 93         98 return $self->{errors};
419             }
420              
421              
422             sub _scalar_to_arrayref {
423             # Replace the scalar values in the error specs by more versatile arrayrefs
424 28     28   25 my ($self, $errors) = @_;
425 28         100 while ( my ($pos, $ops) = each %$errors ) {
426 38         75 while ( my ($op, $res) = each %$ops ) {
427 40 100       66 if (ref $res eq '') {
428 36   100     101 my $arr = [ split //, ($res || '') ];
429 36 100       57 $arr = [undef] if scalar @$arr == 0;
430 36         125 $$errors{$pos}{$op} = $arr;
431             }
432             }
433             }
434 28         27 return $errors;
435             }
436              
437              
438             sub _validate_error_specs {
439             # Clean error specifications and warn of any issues encountered
440 28     28   20 my ($self, $errors) = @_;
441 28         62 my %valid_ops = ('%' => undef, '-' => undef, '+' => undef); # valid operations
442              
443             # Calculate read length
444 28         59 my $read_length = $self->length;
445 28         59 while ( my ($pos, $ops) = each %$errors ) {
446              
447             # Position cannot be no longer than the read length
448 38 100 66     132 if ( (defined $read_length) && ($pos > $read_length) ) {
449 3         11 $self->warn("Position $pos is beyond end of read ($read_length ".
450             "residues). Skipping errors specified at this position.\n");
451 3         6 delete $errors->{$pos};
452             }
453              
454             # Position has to be 0+ for addition, 1+ for substitution and deletion
455 38 100 66     77 if ( $pos < 1 && (exists $ops->{'%'} || exists $ops->{'-'}) ) {
      66        
456 2         15 $self->warn("Positions of substitutions and deletions have to be ".
457             "strictly positive but got $pos. Skipping substitution or deletion".
458             " at this position\n");
459 2         4 delete $ops->{'%'};
460 2         3 delete $ops->{'-'};
461             }
462 38 0 33     49 if ( $pos < 0 && exists $ops->{'+'}) {
463 0         0 $self->warn("Positions of additions have to be zero or more. ".
464             "Skipping addition at position $pos.\n");
465 0         0 delete $ops->{'+'};
466             }
467              
468             # Valid operations are '%', '+' and '-'
469 38         61 while ( my ($op, $res) = each %$ops ) {
470 38 50       63 if (not exists $valid_ops{$op}) {
471 0         0 $self->warn("Skipping unknown error operation '$op' at position".
472             " $pos\n");
473 0         0 delete $ops->{$op};
474             } else {
475             # Substitutions: have to have at least one residue to substitute
476 38 50 66     77 if ( ($op eq '%') && (scalar @$res < 1) ) {
477 0         0 $self->warn("At least one residue must be provided for substitutions,".
478             "but got ".scalar(@$res)." at position $pos.\n");
479             }
480             # Additions: have to have at least one residue to add
481 38 50 66     86 if ( ($op eq '+') && (scalar @$res < 1) ) {
482 0         0 $self->warn("At least one residue must be provided for additions,".
483             "but got ".scalar(@$res)." at position $pos.\n");
484             }
485             # Deletions
486 38 50 66     120 if ( ($op eq '-') && (scalar @$res < 1) ) {
487 0         0 $self->warn("At least one 'undef' must be provided for deletions,".
488             "but got ".scalar(@$res)." at position $pos.\n");
489             }
490             }
491             }
492              
493 38 100       97 delete $errors->{$pos} unless scalar keys %$ops;
494             }
495              
496 28         35 return $errors;
497             }
498              
499              
500             sub _update_seq_errors {
501 28     28   21 my $self = shift;
502 28         48 my $seq_str = $self->seq;
503 28         41 my $errors = $self->errors;
504 28 100       48 if (scalar keys %$errors > 0) {
505 22         13 my $off = 0;
506 22         52 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  14         36  
507             # Process sequencing errors at that position
508 33         31 for my $type ( '%', '-', '+' ) {
509 99 100       146 next if not exists $$errors{$pos}{$type};
510 35         46 my $arr = $$errors{$pos}{$type};
511 35 100       70 if ($type eq '%') {
    100          
    50          
512             # Substitution at residue position. If there are multiple
513             # substitutions to do, directly skip to the last one.
514 9         37 substr $seq_str, $pos - 1 + $off, 1, $$arr[-1];
515             } elsif ($type eq '-') {
516             # Deletion at residue position
517 10         18 substr $seq_str, $pos - 1 + $off, 1, '';
518 10         10 $off--;
519             } elsif ($type eq '+') {
520             # Insertion after residue position
521 16         37 substr $seq_str, $pos + $off, 0, join('', @$arr);
522 16         26 $off += scalar @$arr;
523             }
524             }
525             }
526 22         26 $self->{_mutated} = 1;
527             } else {
528 6         8 $self->{_mutated} = 0;
529             }
530 28         39 $self->seq($seq_str);
531 28         27 return 1;
532             }
533              
534              
535             sub _update_qual_errors {
536 6     6   7 my $self = shift;
537 6         13 my $qual = $self->qual;
538 6         13 my $errors = $self->errors;
539 6         10 my $bad_qual = $self->qual_levels->[1];
540 6 50       17 if (scalar keys %$errors > 0) {
541 6         4 my $off = 0;
542 6         14 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  6         9  
543             # Process sequencing errors at that position
544 10         10 for my $type ( '%', '-', '+' ) {
545 30 100       44 next if not exists $$errors{$pos}{$type};
546 10         10 my $arr = $$errors{$pos}{$type};
547 10 100       24 if ($type eq '%') {
    100          
    50          
548             # Substitution at residue position
549 3         8 splice @$qual, $pos - 1 + $off, 1, $bad_qual;
550             } elsif ($type eq '-') {
551             # Deletion at residue position
552 2         6 splice @$qual, $pos - 1 + $off, 1;
553 2         3 $off--;
554             } elsif ($type eq '+') {
555             # Insertion after residue position
556 5         16 splice @$qual, $pos + $off, 0, ($bad_qual) x scalar(@$arr);
557 5         9 $off += scalar @$arr;
558             }
559             }
560             }
561             }
562 6         12 $self->qual($qual);
563 6         6 return 1;
564             }
565              
566              
567             sub _update_desc_errors {
568             # Add or update error specifications in the read description
569 29     29   24 my $self = shift;
570 29         40 my $errors = $self->errors;
571 29 100 66     98 if (defined $errors and scalar keys %$errors > 0) {
572             # Sequencing errors introduced in the read
573 23         20 my $err_str = 'errors=';
574 23         44 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  14         18  
575             # Process sequencing errors at that position
576 34         27 for my $type ( '%', '-', '+' ) {
577 102 100       139 next if not exists $$errors{$pos}{$type};
578 36         19 for my $val ( @{$$errors{$pos}{$type}} ) {
  36         76  
579 50 100       57 $val = '' if not defined $val;
580 50         85 $err_str .= $pos . $type . $val . ',';
581             }
582             }
583             }
584 23         69 $err_str =~ s/,$//;
585 23         44 my $desc_str = $self->desc;
586 23         235 $desc_str =~ s/((position|strand)=\S+( mid=\S+)?)( errors=\S+)?/$1 $err_str/g;
587 23         38 $self->desc( $desc_str );
588             }
589 29         27 return 1;
590             }
591              
592              
593             =head2 track
594              
595             Title : track
596             Function : Get or set the tracking status in the read description. By default,
597             tracking is on. This method can be called at any time.
598             Usage : my $track = $read->track();
599             Arguments: 1 for tracking, 0 otherwise
600             Returns : 1 for tracking, 0 otherwise
601              
602             =cut
603              
604             sub track {
605 134     134 1 97 my ($self, $track) = @_;
606 134 100       188 if (defined $track) {
607 48 100       58 if (defined $self->reference) {
608 2 100       5 if ($track == 1) {
609 1         2 $self->_create_desc;
610 1         3 $self->_update_desc_mid($self->mid);
611 1         2 $self->_update_desc_errors;
612             } else {
613 1         4 $self->desc(undef);
614             }
615             }
616 48         59 $self->{track} = $track;
617             }
618 134         234 return $self->{track};
619             }
620              
621              
622             =head2 coord_style
623              
624             Title : coord_style
625             Function : When tracking is on, define which 1-based coordinate system to use
626             in the read description:
627             * 'bioperl' uses the start, end and strand keywords (default),
628             similarly to the GFF3 format. Example:
629             start=1 end=10 strand=+1
630             start=1 end=10 strand=-1
631             * 'genbank' does only provide the position keyword. Example:
632             position=1..10
633             position=complement(1..10)
634             Usage : my $coord_style = $read->track();
635             Arguments: 'bioperl' or 'genbank'
636             Returns : 'bioperl' or 'genbank'
637              
638             =cut
639              
640             sub coord_style {
641 91     91 1 76 my ($self, $coord_style) = @_;
642 91         157 my %styles = ( 'bioperl' => undef, 'genbank' => undef );
643 91 100       129 if (defined $coord_style) {
644 46 50       73 if (not exists $styles{$coord_style}) {
645 0         0 die "Error: Invalid coordinate style '$coord_style'\n";
646             }
647 46         79 $self->{coord_style} = $coord_style;
648             }
649 91         150 return $self->{coord_style};
650             }
651              
652              
653             1;