如何使用perl删除gff3文件中的重叠区域?

时间:2017-11-07 12:37:10

标签: perl

我正在尝试从9列gff3文件中删除重叠区域。

**Input file:**
scaffold591 Source gene 3322458 3376057 0.41 - . ID=g24007
scaffold591 Source transcript 3322458 3376057 0.41 - . ID=g24007.t1;Parent=g24007
scaffold591 Source transcription_end_site 3322458 3322458 . - . Parent=g24007.t1
scaffold591 Source gene 3322500 3346055 0.41 - . ID=g24007
scaffold591 Source transcript 3322500 3346055 0.41 - . ID=g24007.t1;Parent=g24007
scaffold591 Source transcription_end_site 3322500 3322500 . - . Parent=g24007.t1
scaffold591 Source gene 3377307 3513095 0.46 + . ID=g24008
scaffold591 Source transcript 3377307 3513095 0.41 + . ID=g24008.t1;Parent=g24008
scaffold591 Source transcription_end_site 3377307 3377307 . + . Parent=g24008.t1

这里我试图仅比较具有相同链“基因”的行,即“ - ”或“+”(第7列)。

例如第1行和第4行。

scaffold591 Source gene 3322458 3376057 0.41 - . ID=g24007
scaffold591 Source gene 3322500 3346055 0.41 - . ID=g24007

它们是来自相同支架的“基因”和相同的“ - ”链(第7列)。 row4坐标(第4列和第5列)位于第1行坐标的范围内。在这种情况下,我的代码应该删除重叠的行4并保留具有更大范围的row1。

**My expected output:**
scaffold591 Source gene 3322458 3376057 0.41 - . ID=g24007
scaffold591 Source transcript 3322458 3376057 0.41 - . ID=g24007.t1;Parent=g24007
scaffold591 Source transcription_end_site 3322458 3322458 . - . Parent=g24007.t1
scaffold591 Source gene 3377307 3513095 0.46 + . ID=g24008
scaffold591 Source transcript 3377307 3513095 0.41 + . ID=g24007.t1;Parent=g24008
scaffold591 Source transcription_end_site 3377307 3377307 . + . Parent=g24008.t1

我的代码打印row1及其后续行两次

My code:
#!/usr/bin/perl
use warnings;
use strict;
use List::Util qw{ max };

open (IN, "<scaffold_sample.txt");

my $previous_seqid ="";
my $previous_strand;
my $previous_start;
my $previous_end;
my @gff;
my @tmp;
while (<IN>)
 {
    chomp;
    my ($seqid,$source, $region, $start, $end, $score, $strand, $frame, $attribute) = split ("\t",$_);  
    @gff = ($seqid,$source, $region, $start, $end, $score, $strand, $frame, $attribute);

    if ($seqid eq $previous_seqid && $strand eq $previous_strand && $region eq 'gene')
    {
        if($start < $previous_end && $end < $previous_end)
        {
            @gff = @tmp;
            $previous_seqid = $gff[0];
            $previous_strand = $gff[6];
            $previous_start = $gff[3];
            $previous_end = $gff[4];
            print join "\t",@gff;
            print "\n";
        }
        else
        {
            @tmp = @gff;
        }

    }
    else
    {
        @tmp = ($seqid,$source, $region, $start, $end, $score, $strand, $frame, $attribute);
        $previous_seqid = $seqid;
        $previous_strand = $strand;
        $previous_start = $start;
        $previous_end = $end;
        print join "\t",@tmp;
        print "\n";
    }

}

请帮忙。

1 个答案:

答案 0 :(得分:1)

这是一个有趣的问题。您想要对行进行重复数据删除,但(我认为)如果您在文件中稍后找到更大的范围,则需要在找到原始较小范围的位置输出此大范围。

说实话,我没有看你的解决方案,而是从头开始。

我使用了两种数据结构。 %line_data包含我们处理的行的详细信息。它是一个多级哈希,键入seqid,strand和region。如果新记录与哈希值不匹配,那么我们首次将seqid,strand和region组合在一起。如果新记录确实匹配,那么我们之前已经看过这个组合,我们计算出两者中哪一个具有最大范围并在必要时覆盖。

然后是@lines,其中包含我们要输出的数据。它包含对%line_data中哈希的引用。当发现更大的范围时,需要一些保持更新的房屋保养。

所以这就是我最终的结果。它为您的输入提供了正确的输出,但我不知道它是否会在更多变化的输入上中断。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my @lines;
my %line_data;

# Column names (for use as hash keys)    
my @cols = qw[seqid source region start end score strand frame attribute];

# Store the input data in DATA for easier testing
while (<DATA>) {
  my %record;
  # Split a record into a hash
  @record{@cols} = split;

  # If this key combination exists...
  if (exists $line_data{$record{seqid}}{$record{strand}}{$record{region}}) {
    # Get the previous record with these keys...
    my $prev = $line_data{$record{seqid}}{$record{strand}}{$record{region}};
    # See if the new range is larger...
    if ($record{start} > $prev->{start} and $record{end} > $prev->{end}) {
      # If so, overwrite it.
      $line_data{$record{seqid}}{$record{strand}}{$record{region}} = \%record;
      $lines[$prev->{pos}] = \%record;
      $record{post} = $prev->{pos};
    }
  } else {
    # We haven't seen this key combination before.
    # So just store it.
    $line_data{$record{seqid}}{$record{strand}}{$record{region}} = \%record;
    push @lines, \%record;
    $record{pos} = $#lines;
  }
}

# Having processed the data, we walk the @lines array,
# de-referencing the hash and joining the values with a space.
foreach (@lines) {
  say join ' ', @$_{@cols};
}

__DATA__
scaffold591 Source gene 3322458 3376057 0.41 - . ID=g24007
scaffold591 Source transcript 3322458 3376057 0.41 - . ID=g24007.t1;Parent=g24007
scaffold591 Source transcription_end_site 3322458 3322458 . - . Parent=g24007.t1
scaffold591 Source gene 3322500 3346055 0.41 - . ID=g24007
scaffold591 Source transcript 3322500 3346055 0.41 - . ID=g24007.t1;Parent=g24007
scaffold591 Source transcription_end_site 3322500 3322500 . - . Parent=g24007.t1
scaffold591 Source gene 3377307 3513095 0.46 + . ID=g24008
scaffold591 Source transcript 3377307 3513095 0.41 + . ID=g24008.t1;Parent=g24008
scaffold591 Source transcription_end_site 3377307 3377307 . + . Parent=g24008.t1