I generated a file starting with the following bed lines:
$ head -6 /tmp/bed_with_gene_ids.bed
I 3746 3909 "WBGene00023193" . -
I 3746 3909 "WBGene00023193" . -
I 4118 4220 "WBGene00022277" . -
I 4118 4358 "WBGene00022277" . -
I 4118 10230 "WBGene00022277" . -
I 4220 4223 "WBGene00022277" . -
I would like to merge them based on the name field (the 4-th column), taking the min for the start and the max for the end. Other fields are expected to be the same for all records having the same name.
Expected result:
I 3746 3909 "WBGene00023193" . -
I 4118 10230 "WBGene00022277" . -
I found a potential solution based on bedtools groupby
here: https://www.biostars.org/p/145751/#145775
Sample data:
cat genes.bed
chr14 49894259 49895806 ENSMUST00000053290 0.000000 ...
chr14 49894873 49894876 ENSMUST00000053290 0.000000 ...
chr14 49894876 49895800 ENSMUST00000053291 0.000000 ...
chr14 49895797 49895800 ENSMUST00000053291 0.000000 ...
chr14 49901908 49901941 ENSMUST00000053291 0.000000 ...
Example output:
sort -k4,4 genes.bed \
| groupBy -g 1,4 -c 4,2,3 -o count,min,max \
| awk -v OFS='\t' '{print $1, $4, $5, $2, $3}'
chr14 49894259 49895806 ENSMUST00000053290 2
chr14 49894876 49901941 ENSMUST00000053291 3
However:
I don't understand the groupBy behaviour (Why
-g 1,4
and not just-g 4
?, Why-c 4,2,3
in this order and then rearrange things usingawk
?)This code doesn't work for me.
Here is what happens when I try the solution given above:
$ head -3 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 1,4 -c 4,2,3 -o count,min,max | awk -v OFS='\t' '{print $1, $4, $5, $2, $3}'
3 3746 4220
Here are attempt based on what I thought could work according to the documentation:
$ head -6 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 4 -c 1,2,3,4,5,6 -o first,min,max,distinct,first,first
I 3746 10230 "WBGene00022277","WBGene00023193" . -
$ head -6 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 4 -c 1,2,3,4,5,6 -o first,min,max,last,first,first
I 3746 10230 "WBGene00022277" . -
$ head -6 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 4 -c 1,2,3,5,6 -o first,min,max,first,first
I 3746 10230 . -
I don't get why when I group based on the 4-th column, for which I have two distinct values, I cannot obtain two lines in the resulting output.
I understand based on the comments on the documentation page that the documentation is not up-to-date. In particular, there is a -full
option that is needed if one wants all fields to be outputted. Re-reading the solution mentioned above, I think I now understand the reason for the multiple columns for the -g option
and for the awk
rearrangement. Hence the following attempt.
$ head -6 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 1,4,5,6 -c 2,3 -o min,max -full
I 3746 3909 "WBGene00023193" . - 3746 10230
But this still doesn't give me two lines.
Are there other tools that could do what I want efficiently?
Edit: Solution
According to this answer, the problem with bedtools is that there is a bug in the latest release (2.26.0 as of august 2017). In order to have a functional bedtools groupby
, one needs to get the development version from github.
With the github version of bedtools, I can now get the expected result as follows:
$ head -6 /tmp/bed_with_gene_ids.bed | bedtools groupby -g 1,4,5,6 -c 2,3 -o min,max | awk -v OFS="\t" '{print $1,$5,$6,$2,$3,$4}'
I 3746 3909 "WBGene00023193" . -
I 4118 10230 "WBGene00022277" . -
I include fields 1, 5 and 6 in -g
(besides field 4) in order to have them printed out. In my bed file, they should be the same for a given value of field 4. The awk
part is needed because one has apparently not total control on the output order: the -g
fields come before the -c
fields.
Note (added 23/12/2020): As specified in bedtools groupby
documentation, the input bed file should be sorted according to (chromosome (1) and) name (4) field(s) for this to work properly. Otherwise, duplicate (i.e. non-merged) names may appear in the output.