Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 112 additions & 32 deletions ProtVar.pm
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,42 @@ sub new {

$self->{initial_pid} = $$;

$self->{dbh} = DBI->connect( "dbi:SQLite:dbname=" . $self->{db}, "", "" );
$self->{get_sth} = $self->{dbh}->prepare("SELECT md5, item, matrix FROM consequences WHERE md5 = ?");
$self->prepare_db_statements();

return $self;
}

sub prepare_db_statements {
my ($self) = @_;

$self->{dbh} ||= DBI->connect(
"dbi:SQLite:dbname=" . $self->{db},
"",
"",
{ RaiseError => 1, PrintError => 0, AutoCommit => 1 }
);
$self->{get_sth} = $self->{dbh}->prepare("SELECT md5, item, matrix FROM consequences WHERE md5 = ?");
$self->prepare_pocket_statements() if $self->{pocket};
}

sub prepare_pocket_statements {
my ($self) = @_;

$self->{pocket_attrib_sth} = $self->{dbh}->prepare(
"SELECT score, MpLDDT, energy, burriedness, RoG, residues FROM pocket_attribs WHERE md5 = ? AND pocket_id = ?"
);

my ($has_pocket_residues) = $self->{dbh}->selectrow_array(
"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'pocket_residues'"
);

$self->{pocket_residue_sth} = $has_pocket_residues
? $self->{dbh}->prepare(
"SELECT pocket_id FROM pocket_residues WHERE md5 = ? AND pos = ?"
)
: undef;
}

sub feature_types {
return ['Transcript'];
}
Expand All @@ -154,11 +184,7 @@ sub get_header_info {
}

if ( defined $self->{pocket} ) {
$header{ProtVar_pocket} = "Information about overlapping protein pocket. Output field(s) include: ";
$header{ProtVar_pocket} .=
$self->{config}->{output_format} eq "vcf"
? "(fields are separated by '&') "
: "(fields are separated by ',') ";
$header{ProtVar_pocket} = "Information about overlapping protein pocket. Output records are separated by '&'; field(s) include: ";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jamie-m-a , Looks good. 👍
For other output format the delimiter is , but for VCF it is &. So we need to update the header description here.

Also Needs to properly use delimiter in the output,
for VCF two pocket output are delimited by & as well as the fields for those pocket output, so we cannot separate two pockets -

P4&897.4969555629044&83.33136363636362&0.362285&0.789264&7.645393&p111p112p113p114p115p116p117p118p119p120p121p124p149p150p151p152p153p156p313p316p317p320&P12&515.7658017356196&87.736875&0.330738&0.747748&4.331085&p114p115p117p118p119p120p123p316p319p320p321p322p323p324p330p343

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - simplest was to follow standard field arrangement, so reverted to that.

$header{ProtVar_pocket} .= "id - Pocket id, ";
$header{ProtVar_pocket} .= "score - Combined score measuring confidence in pocket (score < 800: low confidence; score 800-900: high confidence; score > 900: very high confidence), ";
$header{ProtVar_pocket} .= "MpLDDT - Mean pLDDT score of all the residues from AlphaFold2 model used to form the pocket, ";
Expand Down Expand Up @@ -239,27 +265,66 @@ sub format_output {
my ( $self, $data, $item ) = @_;

my $result = {};
my @records = ref($data) eq 'ARRAY' ? @$data : ($data);

if ( $self->{output_json} ) {
my %hash;
%hash = map { $_ => $data->{$_} } keys %$data;
$result->{$item} = \%hash;
if ( ref($data) eq 'ARRAY' ) {
$result->{$item} = [
map {
my $record = $_;
+{ map { $_ => $record->{$_} } keys %$record };
} @records
];
}
else {
my %hash;
%hash = map { $_ => $data->{$_} } keys %$data;
$result->{$item} = \%hash;
}
}
else {
my $key = "ProtVar_" . $item;
my @formatted_records;

# replace comma in pocket residue position to avoid delimiter clash
if ($data->{residues}) {
$data->{residues} =~ s/,/p/g;
$data->{residues} = 'p'.$data->{residues};
foreach my $record (@records) {
my %formatted_data = %$record;

# replace comma in pocket residue position to avoid delimiter clash
if ($formatted_data{residues}) {
$formatted_data{residues} =~ s/,/p/g;
$formatted_data{residues} = 'p'.$formatted_data{residues};
}

push @formatted_records, join(",", map { $formatted_data{$_} } @{ $field_order->{$item} });
}

$result->{$key} = join(",", map { $data->{$_} } @{ $field_order->{$item} });
$result->{$key} = join("&", @formatted_records);
}

return $result;
}

sub get_pocket_ids {
my ( $self, $md5, $pos, $fallback_id ) = @_;

return ($fallback_id) unless $self->{pocket_residue_sth};

# Matrix positions are 0-based; pocket_residues stores UniProt positions.
eval {
my $residue_pos = "" . ( $pos + 1 );
$self->{pocket_residue_sth}->execute( $md5, $residue_pos );
};
return ($fallback_id) if $@;

my @ids;
while ( my $arrayref = $self->{pocket_residue_sth}->fetchrow_arrayref ) {
push @ids, $arrayref->[0];
}

@ids = sort { $a <=> $b } @ids;
return @ids ? @ids : ($fallback_id);
}

sub process_from_db {
my ( $self, $tva ) = @_;

Expand All @@ -279,12 +344,18 @@ sub process_from_db {

# forked, reconnect to DB
if ( $$ != $self->{initial_pid} ) {
$self->{dbh} = DBI->connect( "dbi:SQLite:dbname=" . $self->{db}, "", "" );
$self->{get_sth} = $self->{dbh}->prepare("SELECT md5, item, matrix FROM consequences WHERE md5 = ?");
$self->{dbh} = DBI->connect(
"dbi:SQLite:dbname=" . $self->{db},
"",
"",
{ RaiseError => 1, PrintError => 0, AutoCommit => 1 }
);
$self->prepare_db_statements();

# set this so only do once per fork
$self->{initial_pid} = $$;
}
$self->prepare_db_statements() unless $self->{get_sth};
$self->{get_sth}->execute($md5);

my $result_from_db = {};
Expand Down Expand Up @@ -350,21 +421,30 @@ sub process_from_db {

# format the output
if ($id) {
my $sth2 = $self->{dbh}->prepare( "SELECT score, MpLDDT, energy, burriedness, RoG, residues FROM pocket_attribs WHERE md5 = ? AND pocket_id = ?" );
$sth2->execute($md5, $id);
my ( $score, $MpLDDT, $energy, $burriedness, $RoG, $residues ) = @{ $sth2->fetchrow_arrayref };

my $data = {
id => 'P' . $id,
score => $score,
MpLDDT => $MpLDDT,
energy => $energy,
burriedness => $burriedness,
RoG => $RoG,
residues => $residues
};

my $formatted_output = $self->format_output( $data, $item );
my @pocket_data;
$self->prepare_pocket_statements() unless $self->{pocket_attrib_sth};

foreach my $pocket_id ( $self->get_pocket_ids( $md5, $pos, $id ) ) {
$self->{pocket_attrib_sth}->execute($md5, $pocket_id);
my $attribs = $self->{pocket_attrib_sth}->fetchrow_arrayref;
next unless $attribs;

my ( $score, $MpLDDT, $energy, $burriedness, $RoG, $residues ) = @$attribs;

push @pocket_data, {
id => 'P' . $pocket_id,
score => $score,
MpLDDT => $MpLDDT,
energy => $energy,
burriedness => $burriedness,
RoG => $RoG,
residues => $residues
};
}

next unless @pocket_data;

my $formatted_output = $self->format_output( @pocket_data > 1 ? \@pocket_data : $pocket_data[0], $item );
@$result_from_db{ keys %$formatted_output } = values %$formatted_output;
}
}
Expand Down