App-Dazz
view release on metacpan or search on metacpan
lib/App/Dazz/Command/layout.pm view on Meta::CPAN
package App::Dazz::Command::layout;
use strict;
use warnings;
use autodie;
use App::Dazz -command;
use App::Dazz::Common;
sub abstract {
return 'layout anchors within a group';
}
sub opt_spec {
return (
[ "outfile|o=s", "output filename", ],
[ 'border=i', 'length of borders in anchors', { default => 500 }, ],
[ "max=i", "max distance", { default => 5000 }, ],
[ 'pa=s', 'prefix of anchors', { default => "anchor" }, ],
[ 'oa=s', 'overlaps between anchors', ],
[ "png", "write a png file via graphviz", ],
{ show_defaults => 1, },
);
}
sub usage_desc {
return "dazz layout [options] <strand.fasta> <.ovlp.tsv> <.relation.tsv>";
}
sub description {
my $desc;
$desc .= ucfirst(abstract) . ".\n";
return $desc;
}
sub validate_args {
my ( $self, $opt, $args ) = @_;
if ( @{$args} != 3 ) {
my $message = "This command need three input files.\n\tIt found";
$message .= sprintf " [%s]", $_ for @{$args};
$message .= ".\n";
$self->usage_error($message);
}
for ( @{$args} ) {
if ( !Path::Tiny::path($_)->is_file ) {
$self->usage_error("The input file [$_] doesn't exist.");
}
}
if ( $opt->{oa} ) {
if ( !Path::Tiny::path( $opt->{oa} )->is_file ) {
$self->usage_error("The overlap file [$opt->{oa}] doesn't exist.\n");
}
}
if ( !exists $opt->{outfile} ) {
$opt->{outfile} = Path::Tiny::path( $args->[1] )->absolute . ".contig.fasta";
}
}
sub execute {
my ( $self, $opt, $args ) = @_;
#----------------------------#
# loading sequences
#----------------------------#
my $seq_of = App::Fasops::Common::read_fasta( $args->[0] );
my %is_anchor;
for my $id ( keys %{$seq_of} ) {
if ( index( $id, $opt->{pa} . "/" ) == 0 ) {
$is_anchor{$id} = 1;
}
}
#----------------------------#
# load overlaps and build graph
#----------------------------#
my $graph = Graph->new( directed => 1 );
my $links_of = {}; # long_id => { anchor_id => overlap_on_long, }
{
lib/App/Dazz/Command/layout.pm view on Meta::CPAN
# we've orient all sequences to the same strand
next if $info->{g_strand} == 1;
# skip duplicated overlaps
my $pair = join( "-", sort ( $info->{f_id}, $info->{g_id} ) );
next if $seen_pair{$pair};
$seen_pair{$pair}++;
if ( $info->{f_B} > 0 ) {
if ( $info->{f_E} == $info->{f_len} ) {
# f.B f.E
# f ========+---------->
# g -----------+=======>
# g.B g.E
$graph->add_weighted_edge( $info->{f_id}, $info->{g_id},
$info->{g_len} - $info->{g_E} );
}
else {
# f.B f.E
# f ========+----------+=======>
# g ----------->
# g.B g.E
$graph->add_weighted_edge( $info->{g_id}, $info->{f_id},
$info->{f_len} - $info->{f_E} );
}
}
else {
if ( $info->{g_E} == $info->{g_len} ) {
# f.B f.E
# f -----------+=======>
# g ========+---------->
# g.B g.E
$graph->add_weighted_edge( $info->{g_id}, $info->{f_id},
$info->{f_len} - $info->{f_E} );
}
else {
# f.B f.E
# f ----------->
# g ========+----------+=======>
# g.B g.E
$graph->add_weighted_edge( $info->{f_id}, $info->{g_id},
$info->{g_len} - $info->{g_E} );
}
}
if ( $is_anchor{ $info->{f_id} } and !$is_anchor{ $info->{g_id} } ) {
my ( $beg, $end ) = App::Dazz::Common::beg_end( $info->{g_B}, $info->{g_E}, );
$links_of->{ $info->{g_id} }{ $info->{f_id} }
= AlignDB::IntSpan->new->add_pair( $beg, $end );
}
elsif ( $is_anchor{ $info->{g_id} } and !$is_anchor{ $info->{f_id} } ) {
my ( $beg, $end ) = App::Dazz::Common::beg_end( $info->{f_B}, $info->{f_E}, );
$links_of->{ $info->{f_id} }{ $info->{g_id} }
= AlignDB::IntSpan->new->add_pair( $beg, $end );
}
}
close $in_fh;
}
if ( $opt->{png} ) {
App::Dazz::Common::g2gv( $graph, $args->[1] . ".linker.png" );
}
#----------------------------#
# Graph of anchors
#----------------------------#
my $anchor_graph = Graph->new( directed => 1 );
{
my @nodes = $graph->vertices;
my @linkers = grep { !$is_anchor{$_} } @nodes;
for my $l (@linkers) {
my @p = grep { $is_anchor{$_} } $graph->predecessors($l);
my @s = grep { $is_anchor{$_} } $graph->successors($l);
for my $p (@p) {
for my $s (@s) {
$anchor_graph->add_edge( $p, $s );
}
}
if ( @p > 1 ) {
@p = map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [ $_, $graph->get_edge_weight( $_, $l ) ] } @p;
for my $i ( 0 .. $#p - 1 ) {
$anchor_graph->add_edge( $p[$i], $p[ $i + 1 ] );
}
}
if ( @s > 1 ) {
@s = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, $graph->get_edge_weight( $l, $_, ) ] } @s;
for my $i ( 0 .. $#s - 1 ) {
$anchor_graph->add_edge( $s[$i], $s[ $i + 1 ] );
}
}
}
# add anchors missed in $anchor_graph, i.e., not correctly linked to long.fasta
for my $id ( keys %is_anchor ) {
if ( !$anchor_graph->has_vertex($id) ) {
$anchor_graph->add_vertex($id);
}
}
if ( $opt->{png} ) {
App::Dazz::Common::g2gv( $anchor_graph, $args->[1] . ".png" );
}
App::Dazz::Common::transitive_reduction($anchor_graph);
if ( $opt->{png} ) {
App::Dazz::Common::g2gv( $anchor_graph, $args->[1] . ".reduced.png" );
}
}
#----------------------------#
# existing relations
#----------------------------#
my $relation_of = {};
{
for my $line ( Path::Tiny::path( $args->[2] )->lines( { chomp => 1 } ) ) {
my @fields = split "\t", $line;
my $anchor_0 = $fields[0];
my $anchor_1 = $fields[1];
my @distances = split ",", $fields[2];
my @long_reads = split ",", $fields[3];
my $pair = join "-", sort ( $anchor_0, $anchor_1, );
$relation_of->{$pair} = {
distances => \@distances,
long_reads => \@long_reads,
};
}
}
#----------------------------#
# link anchors and break branches
#----------------------------#
my @paths;
if ( $anchor_graph->is_dag ) {
if ( scalar $anchor_graph->exterior_vertices == 2 ) {
print STDERR " Linear\n";
my @ts = $anchor_graph->topological_sort;
my %idx_of;
for my $idx ( 0 .. $#ts ) {
$idx_of{ $ts[$idx] } = $idx;
}
for my $wcc ( $anchor_graph->weakly_connected_components ) {
my @cc = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, $idx_of{$_} ] } @{$wcc};
push @paths, \@cc;
}
}
else {
print STDERR " Branched\n";
my @ts = $anchor_graph->topological_sort;
my @branchings;
my %idx_of;
for my $idx ( 0 .. $#ts ) {
$idx_of{ $ts[$idx] } = $idx;
if ( $anchor_graph->out_degree( $ts[$idx] ) > 1
or $anchor_graph->in_degree( $ts[$idx] ) > 1 )
{
push @branchings, $ts[$idx];
( run in 2.167 seconds using v1.01-cache-2.11-cpan-364913b4093 )