github.com/biogo/biogo@v1.0.4/seq/linear/seq.go (about)

     1  // Copyright ©2011-2013 The bíogo Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package linear
     6  
     7  import (
     8  	"github.com/biogo/biogo/alphabet"
     9  	"github.com/biogo/biogo/feat"
    10  	"github.com/biogo/biogo/seq"
    11  
    12  	"fmt"
    13  	"unicode"
    14  )
    15  
    16  // A Seq is a basic linear sequence.
    17  type Seq struct {
    18  	seq.Annotation
    19  	Seq alphabet.Letters
    20  }
    21  
    22  // Interface guarantees
    23  var (
    24  	_ feat.Feature = (*Seq)(nil)
    25  	_ seq.Sequence = (*Seq)(nil)
    26  )
    27  
    28  // NewSeq creates a new Seq with the given id, letter sequence and alphabet.
    29  func NewSeq(id string, b []alphabet.Letter, alpha alphabet.Alphabet) *Seq {
    30  	return &Seq{
    31  		Annotation: seq.Annotation{
    32  			ID:     id,
    33  			Alpha:  alpha,
    34  			Strand: seq.Plus,
    35  		},
    36  		Seq: append(alphabet.Letters(nil), b...),
    37  	}
    38  }
    39  
    40  // Append append QLetters to the sequence, ignoring Q component.
    41  func (s *Seq) AppendQLetters(a ...alphabet.QLetter) error {
    42  	l := s.Len()
    43  	s.Seq = append(s.Seq, make([]alphabet.Letter, len(a))...)[:l]
    44  	for _, v := range a {
    45  		s.Seq = append(s.Seq, v.L)
    46  	}
    47  	return nil
    48  }
    49  
    50  // Append appends Letters to the sequence.
    51  func (s *Seq) AppendLetters(a ...alphabet.Letter) error {
    52  	s.Seq = append(s.Seq, a...)
    53  	return nil
    54  }
    55  
    56  // Slice returns the sequence data as a alphabet.Slice.
    57  func (s *Seq) Slice() alphabet.Slice { return s.Seq }
    58  
    59  // SetSlice sets the sequence data represented by the sequence. SetSlice will panic if sl
    60  // is not a alphabet.Letters.
    61  func (s *Seq) SetSlice(sl alphabet.Slice) { s.Seq = sl.(alphabet.Letters) }
    62  
    63  // At returns the letter at position pos.
    64  func (s *Seq) At(i int) alphabet.QLetter {
    65  	return alphabet.QLetter{
    66  		L: s.Seq[i-s.Offset],
    67  		Q: seq.DefaultQphred,
    68  	}
    69  }
    70  
    71  // Set sets the letter at position pos to l.
    72  func (s *Seq) Set(i int, l alphabet.QLetter) error {
    73  	s.Seq[i-s.Offset] = l.L
    74  	return nil
    75  }
    76  
    77  // Len returns the length of the sequence.
    78  func (s *Seq) Len() int { return len(s.Seq) }
    79  
    80  // Start returns the start position of the sequence in coordinates relative to the sequence
    81  // location.
    82  func (s *Seq) Start() int { return s.Offset }
    83  
    84  // End returns the end position of the sequence in coordinates relative to the sequence
    85  // location.
    86  func (s *Seq) End() int { return s.Offset + s.Len() }
    87  
    88  // Validate validates the letters of the sequence according to the sequence alphabet.
    89  func (s *Seq) Validate() (bool, int) { return s.Alpha.AllValid(s.Seq) }
    90  
    91  // Clone returns a copy of the sequence.
    92  func (s *Seq) Clone() seq.Sequence {
    93  	c := *s
    94  	c.Seq = append([]alphabet.Letter(nil), s.Seq...)
    95  	return &c
    96  }
    97  
    98  // New returns an empty *Seq sequence with the same alphabet.
    99  func (s *Seq) New() seq.Sequence {
   100  	return &Seq{Annotation: seq.Annotation{Alpha: s.Alpha}}
   101  }
   102  
   103  // RevComp reverse complements the sequence. RevComp will panic if the alphabet used by
   104  // the receiver is not a Complementor.
   105  func (s *Seq) RevComp() {
   106  	l, comp := s.Seq, s.Alphabet().(alphabet.Complementor).ComplementTable()
   107  	i, j := 0, len(l)-1
   108  	for ; i < j; i, j = i+1, j-1 {
   109  		l[i], l[j] = comp[l[j]], comp[l[i]]
   110  	}
   111  	if i == j {
   112  		l[i] = comp[l[i]]
   113  	}
   114  	s.Strand = -s.Strand
   115  }
   116  
   117  // Reverse reverses the order of letters in the the sequence without complementing them.
   118  func (s *Seq) Reverse() {
   119  	l := s.Seq
   120  	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
   121  		l[i], l[j] = l[j], l[i]
   122  	}
   123  	s.Strand = seq.None
   124  }
   125  
   126  // String returns a string representation of the sequence data only.
   127  func (s *Seq) String() string { return alphabet.Letters(s.Seq).String() }
   128  
   129  // Format is a support routine for fmt.Formatter. It accepts the formats 'v' and 's'
   130  // (string), 'a' (fasta) and 'q' (fastq). String, fasta and fastq formats support
   131  // truncated output via the verb's precision. Fasta format supports sequence line
   132  // specification via the verb's width field. Fastq format supports optional inclusion
   133  // of the '+' line descriptor line with the '+' flag. The 'v' verb supports the '#'
   134  // flag for Go syntax output. The 's' and 'v' formats support the '-' flag for
   135  // omission of the sequence name.
   136  func (s *Seq) Format(fs fmt.State, c rune) {
   137  	if s == nil {
   138  		fmt.Fprint(fs, "<nil>")
   139  		return
   140  	}
   141  	var (
   142  		w, wOk = fs.Width()
   143  		p, pOk = fs.Precision()
   144  		buf    []alphabet.Letter
   145  	)
   146  	if pOk {
   147  		buf = s.Seq[:min(p, len(s.Seq))]
   148  	} else {
   149  		buf = s.Seq
   150  	}
   151  
   152  	switch c {
   153  	case 'v':
   154  		if fs.Flag('#') {
   155  			fmt.Fprintf(fs, "&%#v", *s)
   156  			return
   157  		}
   158  		fallthrough
   159  	case 's':
   160  		if !fs.Flag('-') {
   161  			fmt.Fprintf(fs, "%q ", s.ID)
   162  		}
   163  		for _, l := range buf {
   164  			fmt.Fprintf(fs, "%c", l)
   165  		}
   166  		if pOk && p < s.Len() {
   167  			fmt.Fprint(fs, "...")
   168  		}
   169  	case 'a':
   170  		s.formatDescLineTo(fs, '>')
   171  		for i, l := range buf {
   172  			fmt.Fprintf(fs, "%c", l)
   173  			if wOk && i < s.Len()-1 && i%w == w-1 {
   174  				fmt.Fprintln(fs)
   175  			}
   176  		}
   177  		if pOk && p < s.Len() {
   178  			fmt.Fprint(fs, "...")
   179  		}
   180  	case 'q':
   181  		s.formatDescLineTo(fs, '@')
   182  		for _, l := range buf {
   183  			fmt.Fprintf(fs, "%c", l)
   184  		}
   185  		if pOk && p < s.Len() {
   186  			fmt.Fprintln(fs, "...")
   187  		} else {
   188  			fmt.Fprintln(fs)
   189  		}
   190  		if fs.Flag('+') {
   191  			s.formatDescLineTo(fs, '+')
   192  		} else {
   193  			fmt.Fprintln(fs, "+")
   194  		}
   195  		e := seq.DefaultQphred.Encode(seq.DefaultEncoding)
   196  		if e >= unicode.MaxASCII {
   197  			e = unicode.MaxASCII - 1
   198  		}
   199  		for range buf {
   200  			fmt.Fprintf(fs, "%c", e)
   201  		}
   202  		if pOk && p < s.Len() {
   203  			fmt.Fprint(fs, "...")
   204  		}
   205  	default:
   206  		fmt.Fprintf(fs, "%%!%c(linear.Seq=%.10s)", c, s)
   207  	}
   208  }
   209  
   210  func (s *Seq) formatDescLineTo(fs fmt.State, p rune) {
   211  	fmt.Fprintf(fs, "%c%s", p, s.ID)
   212  	if s.Desc != "" {
   213  		fmt.Fprintf(fs, " %s", s.Desc)
   214  	}
   215  	fmt.Fprintln(fs)
   216  }