Skip to content

Commit

Permalink
add new command range. #19
Browse files Browse the repository at this point in the history
  • Loading branch information
shenwei356 committed Aug 12, 2017
1 parent 933f297 commit 1acc61f
Show file tree
Hide file tree
Showing 6 changed files with 463 additions and 17 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,14 @@ enable researchers to rapidly accomplish common FASTA/Q file manipulations.
- `split` split sequences into files by id/seq region/size/parts
- `sample` sample sequences by number or proportion
- `head` print first N FASTA/Q records
- `concate` concatenate sequences from multiple files
- `range` print FASTA/Q records in a range (start:end)

**Edit**

- `replace` replace name/sequence by regular expression
- `rename` rename duplicated IDs
- `restart` reset start position for circular genome
- `concate` concatenate sequences with same ID from multiple files

**Ordering**

Expand Down
29 changes: 17 additions & 12 deletions doc/docs/download.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ SeqKit is implemented in [Go](https://golang.org/) programming language,

## Latest Version

[SeqKit v0.6.0](https://github.com/shenwei356/seqkit/releases/tag/v0.6.0)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/seqkit/v0.6.0/total.svg)](https://github.com/shenwei356/seqkit/releases/tag/v0.6.0)
[SeqKit v0.7.0](https://github.com/shenwei356/seqkit/releases/tag/v0.7.0)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/seqkit/v0.7.0/total.svg)](https://github.com/shenwei356/seqkit/releases/tag/v0.7.0)

- add new command `genautocomplete` to generate **shell autocompletion** script! ([#17](https://github.com/shenwei356/seqkit/issues/17))
- add new command `seqkit dup` for duplicating sequences ([#16](https://github.com/shenwei356/seqkit/issues/16))
- `seqkit stats -a` does not show L50 which may brings confusion ([#15](https://github.com/shenwei356/seqkit/issues/15))
- `seqkit subseq --bed`: more robust for bad BED files
- add new command `convert` for coverting FASTQ quality encoding between Sanger, Solexa and Illumina. Thanks suggestion from [@cviner](https://github.com/cviner) ( [#18](https://github.com/shenwei356/seqkit/issues/18)). [usage & example](http://bioinf.shenwei.me/seqkit/usage/#convert).
- add new command `range` for printing FASTA/Q records in a range (start:end). [#19](https://github.com/shenwei356/seqkit/issues/19). [usage & example](http://bioinf.shenwei.me/seqkit/usage/#range).
- add new command `concate` for concatenating sequences with same ID from multiple files. [usage & example](http://bioinf.shenwei.me/seqkit/usage/#concate).

### Please cite

Expand All @@ -25,12 +24,12 @@ SeqKit is implemented in [Go](https://golang.org/) programming language,

OS |Arch |File, (mirror为中国用户下载镜像链接) |Download Count
:------|:---------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Linux |32-bit |[seqkit_linux_386.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_linux_386.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_linux_386.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_linux_386.tar.gz)
Linux |**64-bit**|[**seqkit_linux_amd64.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_linux_amd64.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_linux_amd64.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_linux_amd64.tar.gz)
OS X |32-bit |[seqkit_darwin_386.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_darwin_386.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_darwin_386.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_darwin_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_darwin_386.tar.gz)
OS X |**64-bit**|[**seqkit_darwin_amd64.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_darwin_amd64.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_darwin_amd64.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_darwin_amd64.tar.gz)
Windows|32-bit |[seqkit_windows_386.exe.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_windows_386.exe.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_windows_386.exe.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_windows_386.exe.tar.gz)
Windows|**64-bit**|[**seqkit_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_windows_amd64.exe.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_windows_amd64.exe.tar.gz))|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.6.0/seqkit_windows_amd64.exe.tar.gz)
Linux |32-bit |[seqkit_linux_386.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_linux_386.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_linux_386.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_linux_386.tar.gz)
Linux |**64-bit**|[**seqkit_linux_amd64.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_linux_amd64.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_linux_amd64.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_linux_amd64.tar.gz)
OS X |32-bit |[seqkit_darwin_386.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_darwin_386.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_darwin_386.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_darwin_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_darwin_386.tar.gz)
OS X |**64-bit**|[**seqkit_darwin_amd64.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_darwin_amd64.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_darwin_amd64.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_darwin_amd64.tar.gz)
Windows|32-bit |[seqkit_windows_386.exe.tar.gz](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_windows_386.exe.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_windows_386.exe.tar.gz)) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_windows_386.exe.tar.gz)
Windows|**64-bit**|[**seqkit_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_windows_amd64.exe.tar.gz), ([mirror](http://app.shenwei.me/data/seqkit/seqkit_windows_amd64.exe.tar.gz))|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/seqkit/latest/seqkit_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/seqkit/releases/download/v0.7.0/seqkit_windows_amd64.exe.tar.gz)

## Installation

Expand Down Expand Up @@ -84,6 +83,12 @@ Howto:

## Release History

- [SeqKit v0.6.0](https://github.com/shenwei356/seqkit/releases/tag/v0.6.0)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/seqkit/v0.6.0/total.svg)](https://github.com/shenwei356/seqkit/releases/tag/v0.6.0)
- add new command `genautocomplete` to generate **shell autocompletion** script! ([#17](https://github.com/shenwei356/seqkit/issues/17))
- add new command `seqkit dup` for duplicating sequences ([#16](https://github.com/shenwei356/seqkit/issues/16))
- `seqkit stats -a` does not show L50 which may brings confusion ([#15](https://github.com/shenwei356/seqkit/issues/15))
- `seqkit subseq --bed`: more robust for bad BED files
- [SeqKit v0.5.5](https://github.com/shenwei356/seqkit/releases/tag/v0.5.5)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/seqkit/v0.5.5/total.svg)](https://github.com/shenwei356/seqkit/releases/tag/v0.5.5)
- Increasing speed of reading `.gz` file by utilizing `gzip` (1.3X),
Expand Down
194 changes: 194 additions & 0 deletions doc/docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

- [fq2fa](#fq2fa)
- [fx2tab & tab2fx](#fx2tab--tab2fx)
- [convert](#convert)

**Searching**

Expand All @@ -32,12 +33,14 @@
- [split](#split)
- [sample](#sample)
- [head](#head)
- [range](#range)

**Edit**

- [replace](#replace)
- [rename](#rename)
- [restart](#restart)
- [concate](#concate)

**Ordering**

Expand Down Expand Up @@ -717,6 +720,125 @@ as `seqkit common -n` along with shell.
- [csv_melt](https://github.com/shenwei356/datakit/blob/master/csv_melt)
provides melt function, could be used in preparation of data for ploting.

## convert

Usage

```
covert FASTQ quality encoding between Sanger, Solexa and Illumina
Usage:
seqkit convert [flags]
Flags:
-d, --dry-run dry run
-f, --force for Illumina-1.8+ -> Sanger, truncate scores > 40 to 40
--from string source quality encoding. if not given, we'll guess it
-h, --help help for convert
-n, --nrecords int number of records for guessing quality encoding (default 1000)
-N, --thresh-B-in-n-most-common int threshold of 'B' in top N most common quality for guessing Illumina 1.5. (default 4)
-F, --thresh-illumina1.5-frac float threshold of faction of Illumina 1.5 in the leading N records (default 0.1)
--to string target quality encoding (default "Sanger")
```

Examples:

Note that `seqkit convert` always output sequences.

The test dataset contains score 41 (`J`):

```
$ seqkit head -n 1 tests/Illimina1.8.fq.gz
@ST-E00493:56:H33MFALXX:4:1101:23439:1379 1:N:0:NACAACCA
NCGTGGAAAGACGCTAAGATTGTGATGTGCTTCCCTGACGATTACAACTGGCGTAAGGACGTTTTGCCTACCTATAAGGCTAACCGTAAGGGTTCTCGCAAGCCTGTAGGTTACAAGAGGTTCGTAGCCGAAGTGATGGCTGACTCACGG
+
#AAAFAAJFFFJJJ<JJJJJFFFJFJJJJJFJJAJJJFJJFJFJJJJFAFJ<JA<FFJ7FJJFJJAAJJJJ<JJJJJJJFJJJAJJJJJFJJ77<JJJJ-F7A-FJFFJJJJJJ<FFJ-<7FJJJFJJ)A7)7AA<7--)<-7F-A7FA<
```

By default, nothing changes when converting Illumina 1.8 to Sanger. A warning message show that source and target quality encoding match.

```
$ seqkit convert tests/Illimina1.8.fq.gz | seqkit head -n 1
[INFO] possible quality encodings: [Illumina-1.8+]
[INFO] guessed quality encoding: Illumina-1.8+
[INFO] converting Illumina-1.8+ -> Sanger
[WARN] source and target quality encoding match.
@ST-E00493:56:H33MFALXX:4:1101:23439:1379 1:N:0:NACAACCA
NCGTGGAAAGACGCTAAGATTGTGATGTGCTTCCCTGACGATTACAACTGGCGTAAGGACGTTTTGCCTACCTATAAGGCTAACCGTAAGGGTTCTCGCAAGCCTGTAGGTTACAAGAGGTTCGTAGCCGAAGTGATGGCTGACTCACGG
+
#AAAFAAJFFFJJJ<JJJJJFFFJFJJJJJFJJAJJJFJJFJFJJJJFAFJ<JA<FFJ7FJJFJJAAJJJJ<JJJJJJJFJJJAJJJJJFJJ77<JJJJ-F7A-FJFFJJJJJJ<FFJ-<7FJJJFJJ)A7)7AA<7--)<-7F-A7FA<
```

When switching flag `--force` on, `J` (41) was converted to `I` (40).

```
$ seqkit convert tests/Illimina1.8.fq.gz -f | seqkit head -n 1
[INFO] possible quality encodings: [Illumina-1.8+]
[INFO] guessed quality encoding: Illumina-1.8+
[INFO] converting Illumina-1.8+ -> Sanger
@ST-E00493:56:H33MFALXX:4:1101:23439:1379 1:N:0:NACAACCA
NCGTGGAAAGACGCTAAGATTGTGATGTGCTTCCCTGACGATTACAACTGGCGTAAGGACGTTTTGCCTACCTATAAGGCTAACCGTAAGGGTTCTCGCAAGCCTGTAGGTTACAAGAGGTTCGTAGCCGAAGTGATGGCTGACTCACGG
+
#AAAFAAIFFFIII<IIIIIFFFIFIIIIIFIIAIIIFIIFIFIIIIFAFI<IA<FFI7FIIFIIAAIIII<IIIIIIIFIIIAIIIIIFII77<IIII-F7A-FIFFIIIIII<FFI-<7FIIIFII)A7)7AA<7--)<-7F-A7FA<
```

Other cases:

To Illumina-1.5.

```
$ seqkit convert tests/Illimina1.8.fq.gz --to Illumina-1.5+ | seqkit head -n 1
[INFO] possible quality encodings: [Illumina-1.8+]
[INFO] guessed quality encoding: Illumina-1.8+
[INFO] converting Illumina-1.8+ -> Illumina-1.5+
@ST-E00493:56:H33MFALXX:4:1101:23439:1379 1:N:0:NACAACCA
NCGTGGAAAGACGCTAAGATTGTGATGTGCTTCCCTGACGATTACAACTGGCGTAAGGACGTTTTGCCTACCTATAAGGCTAACCGTAAGGGTTCTCGCAAGCCTGTAGGTTACAAGAGGTTCGTAGCCGAAGTGATGGCTGACTCACGG
+
B```e``ieeeiii[iiiiieeeieiiiiieii`iiieiieieiiiie`ei[i`[eeiVeiieii``iiii[iiiiiiieiii`iiiiieiiVV[iiiiLeV`Leieeiiiiii[eeiL[VeiiieiiH`VHV``[VLLH[LVeL`Ve`[
```

To Illumina-1.5 and back to Sanger.

```
$ seqkit convert tests/Illimina1.8.fq.gz --to Illumina-1.5+ | seqkit convert | seqkit head -n 1
[INFO] possible quality encodings: [Illumina-1.8+]
[INFO] guessed quality encoding: Illumina-1.8+
[INFO] converting Illumina-1.8+ -> Illumina-1.5+
[INFO] possible quality encodings: [Illumina-1.5+]
[INFO] guessed quality encoding: Illumina-1.5+
[INFO] converting Illumina-1.5+ -> Sanger
@ST-E00493:56:H33MFALXX:4:1101:23439:1379 1:N:0:NACAACCA
NCGTGGAAAGACGCTAAGATTGTGATGTGCTTCCCTGACGATTACAACTGGCGTAAGGACGTTTTGCCTACCTATAAGGCTAACCGTAAGGGTTCTCGCAAGCCTGTAGGTTACAAGAGGTTCGTAGCCGAAGTGATGGCTGACTCACGG
+
!AAAFAAJFFFJJJ<JJJJJFFFJFJJJJJFJJAJJJFJJFJFJJJJFAFJ<JA<FFJ7FJJFJJAAJJJJ<JJJJJJJFJJJAJJJJJFJJ77<JJJJ-F7A-FJFFJJJJJJ<FFJ-<7FJJJFJJ)A7)7AA<7--)<-7F-A7FA<
```

Checking encoding

```
$ seqkit convert tests/Illimina1.8.fq.gz --from Solexa
[INFO] converting Solexa -> Sanger
[ERRO] seq: invalid Solexa quality
```
Real Illumina 1.5+ data

```
$ seqkit seq tests/Illimina1.5.fq
@HWI-EAS209_0006_FC706VJ:5:58:5894:21141#ATCACG/1
TTAATTGGTAAATAAATCTCCTAATAGCTTAGATNTTACCTTNNNNNNNNNNTAGTTTCTTGAGATTTGTTGGGGGAGACATTTTTGTGATTGCCTTGAT
+
efcfffffcfeefffcffffffddf`feed]`]_Ba_^__[YBBBBBBBBBBRTT\]][]dddd`ddd^dddadd^BBBBBBBBBBBBBBBBBBBBBBBB
$ seqkit convert tests/Illimina1.5.fq | seqkit head -n 1
[INFO] possible quality encodings: [Illumina-1.5+]
[INFO] guessed quality encoding: Illumina-1.5+
[INFO] converting Illumina-1.5+ -> Sanger
@HWI-EAS209_0006_FC706VJ:5:58:5894:21141#ATCACG/1
TTAATTGGTAAATAAATCTCCTAATAGCTTAGATNTTACCTTNNNNNNNNNNTAGTTTCTTGAGATTTGTTGGGGGAGACATTTTTGTGATTGCCTTGAT
+
FGDGGGGGDGFFGGGDGGGGGGEEGAGFFE>A>@!B@?@@<:!!!!!!!!!!355=>><>EEEEAEEE?EEEBEE?!!!!!!!!!!!!!!!!!!!!!!!!
```


## grep

Expand Down Expand Up @@ -1201,6 +1323,46 @@ Examples
HIHIIIIIHIIHGHHIHHIIIIIIIIIIIIIIIHHIIIIIHHIHIIIIIGIHIIIIHHHHHHGHIHIIIIIIIII


## range

Usage

```
print FASTA/Q records in a range (start:end)
Usage:
seqkit range [flags]
Flags:
-h, --help help for range
-r, --range string range. e.g., 1:12 for first 12 records (head -n 12), -12:-1 for last 12 records (tail -n 12)
```

Examples

1. leading N records (head)

$ cat tests/hairpin.fa | seqkit head -n 100 | md5sum
f65116af7d9298d93ba4b3d19077bbf1 -
$ cat tests/hairpin.fa | seqkit range -r 1:100 | md5sum
f65116af7d9298d93ba4b3d19077bbf1 -

1. last N records (tail)

$ cat tests/hairpin.fa | seqkit range -r -100:-1 | seqkit stats
file format type num_seqs sum_len min_len avg_len max_len
- FASTA RNA 100 8,656 58 86.6 172

1. Other ranges

$ cat tests/hairpin.fa | seqkit range -r 101:150 | seqkit stats
file format type num_seqs sum_len min_len avg_len max_len
- FASTA RNA 50 3,777 63 75.5 96

$ cat tests/hairpin.fa | seqkit range -r -100:-2 | seqkit stats
file format type num_seqs sum_len min_len avg_len max_len
- FASTA RNA 99 8,484 58 85.7 146


## replace

Expand Down Expand Up @@ -1414,6 +1576,38 @@ Flags:
```

## concate

Usage

```
concatenate sequences with same ID from multiple files
Usage:
seqkit concate [flags]
Flags:
-h, --help help for concate
```

Examples

1. concatenating leanding 2 bases and last 2 bases

$ cat t.fa
>test
ACCTGATGT
>test2
TGATAGCTACTAGGGTGTCTATCG

$ seqkit concate <(seqkit subseq -r 1:2 t.fa) <(seqkit subseq -r -2:-1 t.fa)
>test
ACGT
>test2
TGCG


## shuffle

Usage
Expand Down
4 changes: 2 additions & 2 deletions seqkit/cmd/concate.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import (
// concateCmd represents the concatenate command
var concateCmd = &cobra.Command{
Use: "concate",
Short: "concatenate sequences from multiple files",
Long: `concatenate sequences from multiple files
Short: "concatenate sequences with same ID from multiple files",
Long: `concatenate sequences with same ID from multiple files
`,
Run: func(cmd *cobra.Command, args []string) {
Expand Down
4 changes: 2 additions & 2 deletions seqkit/cmd/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ var qualityEncodingCode string
func init() {
RootCmd.AddCommand(convertCmd)

convertCmd.Flags().StringP("from", "", "", `source quality encoding`)
convertCmd.Flags().StringP("from", "", "", `source quality encoding. if not given, we'll guess it`)
convertCmd.Flags().StringP("to", "", "Sanger", `target quality encoding`)
convertCmd.Flags().BoolP("dry-run", "d", false, `dry run`)
convertCmd.Flags().BoolP("force", "f", false, `for Illumina-1.8+ -> Sanger, truncate scores > 40 to 40.`)
convertCmd.Flags().BoolP("force", "f", false, `for Illumina-1.8+ -> Sanger, truncate scores > 40 to 40`)
convertCmd.Flags().IntP("nrecords", "n", 1000, "number of records for guessing quality encoding")

convertCmd.Flags().IntP("thresh-B-in-n-most-common", "N", seq.NMostCommonThreshold, "threshold of 'B' in top N most common quality for guessing Illumina 1.5.")
Expand Down
Loading

0 comments on commit 1acc61f

Please sign in to comment.