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 }