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   1393 use strict;
  1         1  
  1         22  
88 1     1   3 use warnings;
  1         1  
  1         18  
89 1     1   3 use Bio::LocatableSeq;
  1         1  
  1         16  
90 1     1   3 use base qw( Bio::Seq::Quality Bio::LocatableSeq );
  1         1  
  1         1940  
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 255 my ($class, @args) = @_;
121 46         106 my $self = $class->SUPER::new(@args);
122 46         95 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       101 $coord_style = defined $coord_style ? $coord_style : 'bioperl';
125 46         62 $self->coord_style($coord_style);
126 46 100       53 $track = defined $track ? $track : 1;
127 46         61 $self->track($track);
128 46 100       61 $qual_levels = defined $qual_levels ? $qual_levels : [];
129 46 50       97 $self->qual_levels($qual_levels) if defined $qual_levels;
130 46 100       100 $self->reference($reference) if defined $reference;
131 46 100       62 $self->mid($mid) if defined $mid;
132 46         45 $self->{_mutated} = 0;
133 46 100       70 $self->errors($errors) if defined $errors;
134 46         182 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 110 my ($self, $qual_levels) = @_;
159 153 100       211 if (defined $qual_levels) {
160 48 50 66     100 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         46 $self->{qual_levels} = $qual_levels;
165             }
166 153         264 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 241 my ($self, $reference) = @_;
185 353 100       437 if (defined $reference) {
186             # Sanity check 1
187 45 50 66     141 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     102 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       81 if (not defined $self->start) {
197 40         52 $self->start(1);
198             }
199             # Use end of reference sequence as end default
200 45 100       56 if (not defined $self->end) {
201 40         63 $self->end($reference->length);
202             }
203             # Use strand 1 as strand default
204 45 100       60 if (not defined $self->strand) {
205 39         46 $self->strand(1);
206             }
207             # Set the reference sequence object
208 45         42 $self->{reference} = $reference;
209             # Create a sequence, quality scores and description from the reference
210 45         54 $self->_create_seq;
211 45 100       37 $self->_create_qual if scalar @{$self->qual_levels};
  45         55  
212 45 100       62 $self->_create_desc if $self->track;
213             }
214 353         468 return $self->{reference};
215             }
216              
217              
218             sub _create_seq {
219 45     45   30 my $self = shift;
220             # Get a truncation of the reference sequence
221 45         57 my $reference = $self->reference;
222 45         52 my $read_obj = $reference->trunc( $self->start, $self->end );
223             # Reverse complement the read if needed
224 45 100       74 if ($self->strand == -1) {
225 4         9 $read_obj = $read_obj->revcom();
226             }
227 45         73 $self->seq($read_obj->seq);
228 45         94 return 1;
229             }
230              
231              
232             sub _create_qual {
233 13     13   12 my $self = shift;
234 13         15 $self->qual([ ($self->qual_levels->[0]) x ($self->end - $self->start + 1) ]);
235 13         12 return 1;
236             }
237              
238              
239             sub _create_desc {
240             # Create the read description of the error-free read
241 45     45   39 my $self = shift;
242             # Reference sequence ID
243 45         34 my $desc_str = '';
244 45         52 my $ref_id = $self->reference->id;
245 45 100       60 if (defined $ref_id) {
246 43         79 $desc_str .= 'reference='.$ref_id.' ';
247             }
248             # Position of read on reference sequence: start, end and strand
249 45         85 my $strand = $self->strand;
250 45 100       49 if ($self->coord_style eq 'bioperl') {
251 41         67 $desc_str .= 'start='.$self->start.' end='.$self->end.' ';
252 41 50       57 if (defined $strand) {
253             # Strand of the reference sequence that the read is on
254 41 100       57 $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         5 $desc_str .= 'position='.$self->start.'..'.$self->end.' ';
264             }
265             }
266             # Description of the original sequence
267 45         61 my $ref_desc = $self->reference->desc;
268 45 100 66     52 if ( (defined $self->reference->desc) && ($self->reference->desc !~ m/^\s*$/) ) {
269 42         47 $ref_desc =~ s/"/\\"/g; # escape double-quotes to \"
270 42         63 $desc_str .= 'description="'.$ref_desc.'" ';
271             }
272 45         112 $desc_str =~ s/\s$//g;
273             # Record new description
274 45         68 $self->desc($desc_str);
275 45         44 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 13 my ($self, $mid) = @_;
293 11 100       19 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       12 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       12 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       6 $self->_update_qual_mid($mid) if scalar @{$self->qual_levels};
  8         10  
311 8 50       9 $self->_update_desc_mid($mid) if $self->track;
312             # Set the MID value
313 8         9 $self->{mid} = $mid;
314             }
315             return $self->{mid}
316 11         20 }
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         13 my $seq = $self->seq;
324 8         7 my $old_mid = $self->{mid};
325 8 100       14 if (defined $old_mid) {
326 2         18 $seq =~ s/^$old_mid//;
327             }
328             # Add new MID
329 8         9 $seq = $mid . $seq;
330 8         13 $self->seq( $seq );
331 8         9 return 1;
332             }
333              
334              
335             sub _update_qual_mid {
336             # Update the MID of a quality scores
337 4     4   2 my ($self, $mid) = @_;
338             # Remove old MID
339 4         8 my $qual = $self->qual;
340 4         4 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   8 my ($self, $mid) = @_;
353 9 100       12 if ($mid) {
354             # Sequencing errors introduced in the read
355 7         9 my $mid_str = "mid=".$mid;
356 7         9 my $desc_str = $self->desc;
357 7         64 $desc_str =~ s/((position|strand)=\S+)( mid=\S+)?/$1 $mid_str/g;
358 7         14 $self->desc( $desc_str );
359             }
360 9         7 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       121 if (defined $errors) {
392             # Verify that we have a hashref
393 28 50 33     75 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       32 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         39 $errors = $self->_scalar_to_arrayref($errors);
402             # Check validity of error specifications
403 28         35 $errors = $self->_validate_error_specs($errors);
404             # Set the error specifications
405 28         26 $self->{errors} = $errors;
406             # Need to recalculate the read from the reference if previously mutated
407 28 50       41 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         35 $self->_update_seq_errors;
414 28 100       17 $self->_update_qual_errors if scalar @{$self->qual_levels};
  28         33  
415 28 50       39 $self->_update_desc_errors if $self->track;
416              
417             }
418 93         99 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   22 my ($self, $errors) = @_;
425 28         89 while ( my ($pos, $ops) = each %$errors ) {
426 38         70 while ( my ($op, $res) = each %$ops ) {
427 40 100       65 if (ref $res eq '') {
428 36   100     89 my $arr = [ split //, ($res || '') ];
429 36 100       64 $arr = [undef] if scalar @$arr == 0;
430 36         111 $$errors{$pos}{$op} = $arr;
431             }
432             }
433             }
434 28         26 return $errors;
435             }
436              
437              
438             sub _validate_error_specs {
439             # Clean error specifications and warn of any issues encountered
440 28     28   27 my ($self, $errors) = @_;
441 28         45 my %valid_ops = ('%' => undef, '-' => undef, '+' => undef); # valid operations
442              
443             # Calculate read length
444 28         48 my $read_length = $self->length;
445 28         49 while ( my ($pos, $ops) = each %$errors ) {
446              
447             # Position cannot be no longer than the read length
448 38 100 66     124 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         5 delete $errors->{$pos};
452             }
453              
454             # Position has to be 0+ for addition, 1+ for substitution and deletion
455 38 100 66     60 if ( $pos < 1 && (exists $ops->{'%'} || exists $ops->{'-'}) ) {
      66        
456 2         13 $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         2 delete $ops->{'%'};
460 2         3 delete $ops->{'-'};
461             }
462 38 0 33     47 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         66 while ( my ($op, $res) = each %$ops ) {
470 38 50       49 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     71 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     102 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     112 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       94 delete $errors->{$pos} unless scalar keys %$ops;
494             }
495              
496 28         41 return $errors;
497             }
498              
499              
500             sub _update_seq_errors {
501 28     28   20 my $self = shift;
502 28         47 my $seq_str = $self->seq;
503 28         40 my $errors = $self->errors;
504 28 100       38 if (scalar keys %$errors > 0) {
505 22         17 my $off = 0;
506 22         46 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  15         22  
507             # Process sequencing errors at that position
508 33         29 for my $type ( '%', '-', '+' ) {
509 99 100       138 next if not exists $$errors{$pos}{$type};
510 35         30 my $arr = $$errors{$pos}{$type};
511 35 100       63 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         22 substr $seq_str, $pos - 1 + $off, 1, $$arr[-1];
515             } elsif ($type eq '-') {
516             # Deletion at residue position
517 10         19 substr $seq_str, $pos - 1 + $off, 1, '';
518 10         9 $off--;
519             } elsif ($type eq '+') {
520             # Insertion after residue position
521 16         35 substr $seq_str, $pos + $off, 0, join('', @$arr);
522 16         23 $off += scalar @$arr;
523             }
524             }
525             }
526 22         29 $self->{_mutated} = 1;
527             } else {
528 6         7 $self->{_mutated} = 0;
529             }
530 28         37 $self->seq($seq_str);
531 28         27 return 1;
532             }
533              
534              
535             sub _update_qual_errors {
536 6     6   6 my $self = shift;
537 6         12 my $qual = $self->qual;
538 6         8 my $errors = $self->errors;
539 6         8 my $bad_qual = $self->qual_levels->[1];
540 6 50       13 if (scalar keys %$errors > 0) {
541 6         4 my $off = 0;
542 6         12 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  5         8  
543             # Process sequencing errors at that position
544 10         11 for my $type ( '%', '-', '+' ) {
545 30 100       49 next if not exists $$errors{$pos}{$type};
546 10         10 my $arr = $$errors{$pos}{$type};
547 10 100       22 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         3 splice @$qual, $pos - 1 + $off, 1;
553 2         3 $off--;
554             } elsif ($type eq '+') {
555             # Insertion after residue position
556 5         14 splice @$qual, $pos + $off, 0, ($bad_qual) x scalar(@$arr);
557 5         8 $off += scalar @$arr;
558             }
559             }
560             }
561             }
562 6         10 $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   15 my $self = shift;
570 29         40 my $errors = $self->errors;
571 29 100 66     95 if (defined $errors and scalar keys %$errors > 0) {
572             # Sequencing errors introduced in the read
573 23         21 my $err_str = 'errors=';
574 23         44 for my $pos ( sort {$a <=> $b} (keys %$errors) ) {
  15         24  
575             # Process sequencing errors at that position
576 34         25 for my $type ( '%', '-', '+' ) {
577 102 100       142 next if not exists $$errors{$pos}{$type};
578 36         26 for my $val ( @{$$errors{$pos}{$type}} ) {
  36         48  
579 50 100       58 $val = '' if not defined $val;
580 50         72 $err_str .= $pos . $type . $val . ',';
581             }
582             }
583             }
584 23         98 $err_str =~ s/,$//;
585 23         42 my $desc_str = $self->desc;
586 23         218 $desc_str =~ s/((position|strand)=\S+( mid=\S+)?)( errors=\S+)?/$1 $err_str/g;
587 23         39 $self->desc( $desc_str );
588             }
589 29         24 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 102 my ($self, $track) = @_;
606 134 100       179 if (defined $track) {
607 48 100       60 if (defined $self->reference) {
608 2 100       4 if ($track == 1) {
609 1         3 $self->_create_desc;
610 1         3 $self->_update_desc_mid($self->mid);
611 1         2 $self->_update_desc_errors;
612             } else {
613 1         3 $self->desc(undef);
614             }
615             }
616 48         49 $self->{track} = $track;
617             }
618 134         226 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 71 my ($self, $coord_style) = @_;
642 91         146 my %styles = ( 'bioperl' => undef, 'genbank' => undef );
643 91 100       143 if (defined $coord_style) {
644 46 50       68 if (not exists $styles{$coord_style}) {
645 0         0 die "Error: Invalid coordinate style '$coord_style'\n";
646             }
647 46         85 $self->{coord_style} = $coord_style;
648             }
649 91         147 return $self->{coord_style};
650             }
651              
652              
653             1;