Operators
我们可以使用operators
修改channel的内容。例如前面就使用了view
来查看channel的内容。operators大概可以分为以下几类:
- Filtering:根据给定的规则过滤出想要的元素;
- Transforming:转换channel中的值;
- Splitting:将channel中的元素分成块;
- Combining:合并多个channel;
- Forking:可以将一个channel分割成多个channel;
- Maths:在channel上使用数学函数;
- Other:不在上述类别的操作,如view;
使用Operators
使用operator方式为:channel_obj.<operator>()
。
view
作用是打印channel中的每一项到控制台:
ch = channel.of('1', '2', '3')
ch.view()
也可以传递一个闭包{}
来格式化打印:
ch = channel
.of('1', '2', '3')
.view({ "chr$it" })
Filtering operators
filter
可以过滤出满足某个条件的项,过滤条件可以为:
- 正则表达式
- 字面值
- 数据类型限定符,如:Number,String,Boolean
- 布尔语句
数据类型限定符
例如可以使用Number
来过滤出数字项:
chr_ch = channel.of( 1..22, 'X', 'Y' )
autosomes_ch =chr_ch.filter( Number )
autosomes_ch.view()
正则表达式
例如匹配以1打头的所有项:
chr_ch = channel
.of( 1..22, 'X', 'Y' )
.filter(~/^1.*/)
.view()
布尔语句
例如找到小于5的数字:
channel
.of( 1..22, 'X', 'Y' )
.filter(Number)
.filter { it < 5 }
.view()
上面的例子省略了括号,因为操作符的参数是一个闭包。完整写法:
filter({ it<5})
字面值
如果我们只想要特定值的元素,我们可以指定一个字面值:
channel
.of( 1..22, 'X', 'Y' )
.filter('X')
.view()
Transforming operators
map
map
操作符可以为channel中的每一项应用传入的映射函数,并且将其返回作为一个新的channel。例如:
chr = channel
.of( 'chr1', 'chr2' )
.map ({ it.replaceAll("chr","") })
chr.view()
我们也可以使用map
来将每个元素转为tuple:
fq_ch = channel
.fromPath( 'data/yeast/reads/*.fq.gz' )
.map ({ file -> [file, file.countFastq()] })
.view ({ file, numreads -> "file $file contains $numreads reads" })
flatten
flatten
操作符能将list
或tuple
中的项展开:
list1 = [1,2,3]
ch = channel
.of(list1)
.view()
// [1, 2, 3]
ch =channel
.of(list1)
.flatten()
.view()
/*
1
2
3
*/
效果等同于Channel.fromList
collect
flatten
操作的逆向就是collect
,它能将channel中的所有项当作一个list返回。当组合多个进程的输出或单个进程多次运行的结果时,这非常有用。
ch = channel
.of( 1, 2, 3, 4 )
.collect()
.view()
// [1,2,3,4]
collect返回结果是一个value
channel,能被多次使用。
groupTuple
groupTuple
能将list或tuple中的元素按照key来分组:
ch = channel
.of( ['wt','wt_1.fq'], ['wt','wt_2.fq'], ["mut",'mut_1.fq'], ['mut', 'mut_2.fq'] )
.groupTuple()
.view()
/*
[wt, [wt_1.fq, wt_1.fq]]
[mut, [mut_1.fq, mut_2.fq]]
*/
如果我们知道要分组的项目数,可以使用size
参数。
ch = channel
.of( ['wt','wt_1.fq'], ['wt','wt_1.fq'], ["mut",'mut_1.fq'])
.groupTuple(size:2)
.view()
// [wt, [wt_1.fq, wt_1.fq]]
Combining operators
合并操作符能将通道合并在一起。
mix
mix
操作符将两个(或多个)通道发出的项组合到一个通道中。
ch1 = channel.of( 1,2,3 )
ch2 = channel.of( 'X','Y' )
ch3 = channel.of( 'mt' )
ch4 = ch1.mix(ch2,ch3).view()
结果中元素的顺序可能以任何顺序出现,不管通道的先后顺序。
join
join
操作符按照匹配的键将两个通道中的项连接在一起。默认情况下,键为每一项的第一个元素。
reads1_ch = channel
.of(['wt', 'wt_1.fq'], ['mut','mut_1.fq'])
reads2_ch= channel
.of(['wt', 'wt_2.fq'], ['mut','mut_2.fq'])
reads_ch = reads1_ch
.join(reads2_ch)
.view()
/*
[wt, wt_1.fq, wt_2.fq]
[mut, mut_1.fq, mut_2.fq]
*/
Forking operators
分叉操作符将单个通道拆分为多个通道。
MultiMap
MultiMap
操作符允许将源通道发出的项转发到两个或多个输出通道,这些通道将每个输入值映射为一个单独的元素。
映射标准是通过指定一个闭包来定义的,该闭包指定由一个唯一标识符标记的目标通道,后面跟着一个表达式语句,该表达式语句计算分配给这种通道的值。
Channel
.from(1,2,3,4)
.multiMap { it ->
foo: it + 1
bar: it * it
}
.set { result }
result.foo.view { "foo $it" }
result.bar.view { "bar $it" }
/*
foo 2
foo 3
foo 4
foo 5
bar 1
bar 4
bar 9
bar 16
*/
若要创建一个multiMap的映射作为一个变量,该变量可以作为参数传递给多个 multiMap 操作符,可以使用 multiMapCriteria
内置方法,如下所示:
def criteria = multiMapCriteria {
small: it < 10
large: it > 10
}
Channel.from(1,2,30).multiMap(criteria).set { ch1 }
Channel.from(10,20,1).multiMap(criteria).set { ch2 }
Maths operators
数学操作符允许使用简单的数学函数在通道上。例如:
- count
- min
- max
- sum
- toInterger
count
count
操作符会返回源通道中的所有项目数:
ch = channel
.of(1..22,'X','Y')
.count()
.view()
// 24
Splitting operators
有时需要将通道中单个项(如文件或字符串)的内容分割成更小的块,这些块可以由下游操作符或进程处理,例如存储在 CSV 文件中的条目。
nextflow有以下此类操作符:
- splitCsv:splitCsv 操作符允许您解析通道发出的,并使用 CSV 格式进行格式化的文本项,并将它们分割为记录或将它们分组为具有指定长度的记录列表。
- splitFasta:splitFasta 操作符允许分割通道发出的条目,这些条目使用 FASTA 格式进行格式化。
- splitFastq:splitFastq操作符可以分割FASTQ格式的条目。
- splitText:splitText操作符可以将源通道发出的多行字符串或文本文件先拆分为包含n行的块。
splitCsv
splitCsv
操作符可以解析具有CSV格式的文本文件。例如:
/* data/yeast/samples.csv
sample_id,fastq_1,fastq_2
ref1,data/yeast/reads/ref1_1.fq.gz,data/yeast/reads/ref1_2.fq.gz
ref2,data/yeast/reads/ref2_1.fq.gz,data/yeast/reads/ref2_2.fq.gz
*/
csv_ch=channel
.fromPath('data/yeast/samples.csv')
.splitCsv()
csv_ch.view()
/* output
[sample_id, fastq_1, fastq_2]
[ref1, data/yeast/reads/ref1_1.fq.gz, data/yeast/reads/ref1_2.fq.gz]
[ref2, data/yeast/reads/ref2_1.fq.gz, data/yeast/reads/ref2_2.fq.gz]
*/
可以通过位置索引来访问值,例如访问第一列可以使用[0]
:
csv_ch=channel
.fromPath('data/yeast/samples.csv')
.splitCsv()
csv_ch
.view({it[0]})
/*
sample_id
ref1
ref2
*/
当csv文件有列头时,可以使用参数header: true
,这样可以通过列名来索引:
csv_ch=channel
.fromPath('data/yeast/samples.csv')
.splitCsv(header:true)
csv_ch.view({it.fastq_1})
/*
data/yeast/reads/ref1_1.fq.gz
data/yeast/reads/ref2_1.fq.gz
*/
如果想要分割以tab
分界的文件,可以使用sep
参数。例如:
Channel.of("val1\tval2\tval3\nval4\tval5\tval6\n")
.splitCsv(sep: "\t")
.view()
/*
[val1, val2, val3]
[val4, val5, val6]
*/