ensembl-hive  2.6
AltAlleleGroup.pm
Go to the documentation of this file.
1 =head1 LICENSE
2 
3 Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
4 Copyright [2016-2024] EMBL-European Bioinformatics Institute
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 =cut
19 
20 
21 =head1 CONTACT
22 
23  Please email comments or questions to the public Ensembl
24  developers list at <http://lists.ensembl.org/mailman/listinfo/dev>.
25 
26  Questions may also be sent to the Ensembl help desk at
27  <http://www.ensembl.org/Help/Contact>.
28 
29 =cut
30 
31 =head1 NAME
32 
34 
35 =head1 SYNOPSIS
36 
39 
40  my $aag_adaptor = Bio::EnsEMBL::Registry->get_DBAdaptor("Human","core","AltAlleleGroup");
41 
42  # For a known Gene, find the reference alternative allele
43  my $aag = $aag_adaptor->fetch_Group_by_dbID($gene->dbID);
44  my $reference_gene = $aag->get_representative_Gene;
45 
46  # Get a list of AltAlleleGroups
47  my $list = $aag_adaptor->fetch_all_Groups_by_type('HAS_CODING_POTENTIAL');
48  $list = $aag_adaptor->fetch_all_Groups();
49 
50  while ($aag = shift @$list) {
51  $aag->get_all_Genes;
52  # Do your important things ...
53  }
54 
55  # Creating and editing an AltAlleleGroup
56 
57  my %type_flags = ('IS_MOST_COMMON_ALLELE' => '1','AUTOMATICALLY_ASSIGNED' => '1');
58 
60  -MEMBERS => [ [$gene_id,\%type_flags ] ],
61  );
62  $aag->remove_all_members;
63  $aag->add_member($gene_id,\%type_flags);
64 
65  my $dbID = $aag_adaptor->store($aag);
66 
67 
68 =head1 DESCRIPTION
69 
70  Alt allele groups keep track of which alleles are tied to a particular Gene
71  They allow related genes to be located. This class allows fetching of both
72  IDs and fully fledged Gene objects.
73 
74  AltAlleleGroup members are assigned types to differentiate them by their
75  origin. These types are set as flags, allowing you to select the union of
76  types as well as by individual ones.
77 
78  No flags set denotes a situation of no information.
79  Valid flags are as follows:
80  'IS_REPRESENTATIVE',
81  'IS_MOST_COMMON_ALLELE',
82  'IN_CORRECTED_ASSEMBLY',
83  'HAS_CODING_POTENTIAL',
84  'IN_ARTIFICIALLY_DUPLICATED_ASSEMBLY',
85  'IN_SYNTENIC_REGION',
86  'HAS_SAME_UNDERLYING_DNA_SEQUENCE',
87  'IN_BROKEN_ASSEMBLY_REGION',
88  'IS_VALID_ALTERNATE',
89  'SAME_AS_REPRESENTATIVE',
90  'SAME_AS_ANOTHER_ALLELE',
91  'MANUALLY_ASSIGNED',
92  'AUTOMATICALLY_ASSIGNED'
93 =cut
94 
96 
97 use strict;
98 use warnings;
99 #use constant {
100 # IS_REPRESENTATIVE => 1,
101 # IS_MOST_COMMON_ALLELE => 2,
102 # IN_CORRECTED_ASSEMBLY => 3,
103 # HAS_CODING_POTENTIAL => 4,
104 # IN_ARTIFICIALLY_DUPLICATED_ASSEMBLY => 5,
105 # IN_SYNTENIC_REGION => 6,
106 # HAS_SAME_UNDERLYING_DNA_SEQUENCE => 7,
107 # IN_BROKEN_ASSEMBLY_REGION => 8,
108 # IS_VALID_ALTERNATE => 9,
109 # SAME_AS_REPRESENTATIVE => 10,
110 # SAME_AS_ANOTHER_ALLELE => 11,
111 # MANUALLY_ASSIGNED => 12,
112 # AUTOMATICALLY_ASSIGNED => 13,
113 #};
114 
115 
116 use Bio::EnsEMBL::Utils::Argument qw(rearrange);
117 use Bio::EnsEMBL::Utils::Exception qw(warning throw);
118 use Bio::EnsEMBL::Utils::Scalar qw(check_ref assert_integer assert_ref);
119 
120 use base qw/Bio::EnsEMBL::Storable/;
121 
122 =head2 new
123 
124  Arg [-MEMBERS]: A list reference of [gene_id,type_flags]
125  : gene_id is a dbID for Gene (consistent only within one release)
126  : type_flags is a hash ref of attributes for this member
127  Example : $aag = Bio::EnsEMBL::AltAlleleGroup->new(
128  -MEMBERS => [ [1,{$type} ], [2,{$other_type}],[3,{$type}],
129  );
130  Description: Creates a new alt-allele group object
131  Returntype : Bio::EnsEMBL::AltAlleleGroup
132  Exceptions : none
133  Caller : general
134 
135 =cut
136 
137 sub new {
138  my $caller = shift;
139 
140  my $class = ref($caller) || $caller;
141  my $self = $class->SUPER::new(@_);
142  my ( $list ) = rearrange( [ 'MEMBERS'], @_ );
143 
144  $self->{'MEMBERS'} = $list || [];
145 
146  return $self;
147 }
148 
149 =head2 add_member
150 
151  Arg [1] : Gene dbID
152  Arg [2] : Type List, used for assigning type flags of this member, see Description above
153  Description : Adds a record of one new member to the AltAlleleGroup. Once a
154  change is made, this must be persisted to the database with
155  AltAlleleGroupAdaptor->store or ->update
156  Example : $aag->add_member(1040032,$types_hash);
157  $aaga->update($aag); # updating the whole group is necessary.
158 =cut
159 
160 sub add_member {
161  my ($self, $gene_id,$type_hash) = @_;
162  if(!$self->contains_member($gene_id)) {
163  push(@{$self->{MEMBERS}}, [$gene_id, {}]);
164  $self->set_attribs($gene_id, $type_hash);
165  }
166  return;
167 }
168 
169 =head2 get_all_members_with_type
170 
171  Arg [1] : String The type to search members by
172  Description : Loops through the internal members array returning all
173  attributes of the same type as what has been specified
174  Example : my $members = $aag->get_all_members_with_type('IS_VALID_ALTERNATE');
175 
176 =cut
177 
178 sub get_all_members_with_type {
179  my $self = shift;
180  my $type = shift;
181 
182  my @filtered_members;
183  my $members = $self->{'MEMBERS'};
184  foreach my $member (@$members) {
185  if (exists($member->[1]->{$type})) {
186  push @filtered_members,$member;
187  }
188  }
189  return \@filtered_members;
190 }
191 
192 =head2 attribs
193 
194  Arg [1] : Int gene id to record attributes against
195  Description : Returns all known attributes of the given gene id. Attributes
196  are returned as a HashRef but is a copy of the interally
197  held attribute list
198  Returntype : HashRef copy of all the given id's attributes
199  Example : $aag->attribs(10, 'IS_VALID_ALTERNATE');
200  $aag->attribs(10, [ 'IS_VALID_ALTERNATE' ]);
201  $aag->attribs(10, {IS_VALID_ALTERNATE => 1});
202 
203 =cut
204 
205 sub attribs {
206  my ($self, $gene_id) = @_;
207  assert_integer($gene_id, 'gene_id');
208  foreach my $member (@{$self->{MEMBERS}}) {
209  if($member->[0] == $gene_id) {
210  my $attribs = $member->[1];
211  return { %{$attribs} }; # make a copy. never leak
212  }
213  }
214  return {};
215 }
216 
217 =head2 set_attribs
218 
219  Arg [1] : Int gene id to set attributes against
220  Arg [2] : ArrayRef/HashRef/Scalar The attribute you wish to record
221  Description : Adds the given type to the specified gene id in this group. You
222  can specify the type using an ArrayRef, HashRef or a single scalar
223  Example : $aag->attribs(10, 'IS_VALID_ALTERNATE');
224  $aag->attribs(10, [ 'IS_VALID_ALTERNATE' ]);
225  $aag->attribs(10, {IS_VALID_ALTERNATE => 1});
226 
227 =cut
228 
229 sub set_attribs {
230  my ($self, $gene_id, $attribs) = @_;
231  assert_integer($gene_id, 'gene_id');
232  my $current_attribs = $self->attribs($gene_id);
233  if(check_ref($attribs, 'ARRAY')) {
234  #Loop & add
235  $current_attribs->{uc($_)} = 1 for @{$attribs};
236  }
237  elsif(check_ref($attribs, 'HASH')) {
238  #loop through the keys adding them in
239  foreach my $key (keys %{$attribs}) {
240  $current_attribs->{uc($key)} = 1;
241  }
242  }
243  #Simple scalar value so just add it in
244  else {
245  $current_attribs->{uc($attribs)} = 1;
246  }
247  foreach my $member (@{$self->{MEMBERS}}) {
248  if($member->[0] == $gene_id) {
249  $member->[1] = $current_attribs;
250  }
251  }
252  return;
253 }
254 
255 =head2 remove_attribs
256 
257  Arg [1] : Int gene id to retrieve attributes against
258  Arg [2] : ArrayRef/HashRef/Scalar The attribute you wish to remove
259  Description : Removes the given type from this group against the specified
260  gene identifier
261  Example : $aag->remove_attribs(10, 'IS_VALID_ALTERNATE');
262  $aag->remove_attribs(10, [ 'IS_VALID_ALTERNATE' ]);
263  $aag->remove_attribs(10, {IS_VALID_ALTERNATE => 1});
264 
265 =cut
266 
267 sub remove_attribs {
268  my ($self, $gene_id, $attribs) = @_;
269  assert_integer($gene_id, 'gene_id');
270  my @to_remove;
271  if(check_ref($attribs, 'ARRAY')) {
272  @to_remove = map { uc($_) } @{$attribs};
273  }
274  elsif(check_ref($attribs, 'HASH')) {
275  @to_remove = map { uc($_) } keys %{$attribs};
276  }
277  #Simple scalar value so just add it in
278  else {
279  @to_remove = uc($attribs);
280  }
281  foreach my $member (@{$self->{MEMBERS}}) {
282  if($member->[0] == $gene_id) {
283  my $current_attribs = $member->[1];
284  delete $current_attribs->{$_} for @to_remove;
285  }
286  }
287  return;
288 }
289 
290 =head2 remove_member
291 
292  Arg [1] : Int gene id to retrieve attributes against
293  Arg [2] : ArrayRef/HashRef/Scalar The attribute you wish to remove
294  Description : Removes the given member from this group. Any changes
295  must be persisted back to the database via update() or
296  store() methods in Bio::EnsEMBL::DBSQL::AltAlleleGroupAdaptor.
297  Example : $aag->remove_member(10);
298 
299 =cut
300 
301 sub remove_member {
302  my ($self, $gene_id) = @_;
303  assert_integer($gene_id, 'gene_id');
304  my $members = $self->{MEMBERS};
305  my $size = scalar(@{$members});
306  for(my $i = 0; $i < $size; $i++) {
307  my $current_id = $members->[$i]->[0];
308  #If this was the ID then splice it out of the array and exit
309  if($current_id == $gene_id) {
310  splice(@{$members}, $i, 1);
311  last;
312  }
313  }
314  return;
315 }
316 
317 =head2 contains_member
318 
319  Arg [1] : Int gene id to retrieve attributes against
320  Description : Searches through the members list looking for the
321  specified gene id. Returns true if it was found
322  or false if not.
323  Returntype : Boolean indicating if the given gene id is held in this group
324  Example : $aag->contains_member(10);
325 
326 =cut
327 
328 sub contains_member {
329  my ($self, $gene_id) = @_;
330  assert_integer($gene_id, 'gene_id');
331  foreach my $member (@{$self->{MEMBERS}}) {
332  if($member->[0] == $gene_id) {
333  return 1;
334  }
335  }
336  return 0;
337 }
338 
339 =head2 remove_all_members
340 
341  Description : Remove members from this object, but NOT the database. See
342  AltAlleleGroupAdaptor->remove() to remove the group from the
343  database
344 =cut
345 
346 sub remove_all_members {
347  my $self = shift;
348  $self->{'MEMBERS'} = [];
349  return;
350 }
351 
352 =head2 rep_Gene_id
353 
354  Arg[1] : Optional - set a new representative Gene id for the group
355  Description : Reports or sets the representative Gene for this AltAlleleGroup
356  If you wish to remove the representative status of all genes without
357  setting a new one, see unset_rep_Gene_id
358  Returntype : Integer or undef if none set
359 =cut
360 
361 sub rep_Gene_id {
362  my $self = shift;
363  my $new_id = shift;
364  my $list = $self->{'MEMBERS'};
365  my $change;
366 
367  foreach my $allele (@$list) {
368  my ($gene_id,$type) = @$allele;
369  if (exists($type->{IS_REPRESENTATIVE}) && !defined($new_id) ) {
370  return $gene_id;
371  }
372 
373  if ($new_id) {
374  unless ($gene_id == $new_id) {delete($allele->[1]->{IS_REPRESENTATIVE})}
375  else {
376  $allele->[1]->{IS_REPRESENTATIVE} = 1;
377  $change = $new_id;
378  }
379  }
380  }
381 
382  if ($change) {
383  $self->{'MEMBERS'} = $list;
384  return $new_id;
385  } elsif ($new_id && !$change) {
386  my $db_id = $self->dbID() || 'unknown';
387  throw("Requested representative gene ID was not set because it is not in this AltAlleleGroup, ID $db_id");
388  }
389  else {
390  warning("No representative allele currently set for this AltAlleleGroup");
391  return;
392  }
393 }
394 
395 =head2 unset_rep_Gene_id
396 
397  Description : Removes the representative Gene flag from this AltAlleleGroup.
398  This action is not possible through rep_Gene_id due to
399  validation of inputs.
400 
401 =cut
402 
403 sub unset_rep_Gene_id {
404  my $self = shift;
405  my $list = $self->{'MEMBERS'};
406 
407  foreach my $allele (@$list) {
408  delete($allele->[1]->{IS_REPRESENTATIVE});
409  }
410  $self->{'MEMBERS'} = $list;
411  return;
412 }
413 
414 =head2 get_all_Gene_ids
415 
416  Arg[1] : Boolean - Do not include representative gene in list of ids.
417  Arg[2] : ArrayRef - Can contain dbIDs or Gene objects to exclude from the returned list
418  Description : fetches all the Gene dbIDs within the allele group. It can also
419  be used to list those ids that are not the representative Gene.
420  Returntype : ArrayRef of gene dbIDs
421 
422 =cut
423 
424 sub get_all_Gene_ids {
425  my $self = shift;
426  my $all_but_rep = shift;
427  my $excluded_genes = shift;
428  my $list = $self->{'MEMBERS'};
429 
430  my %gene_exclusions;
431  if($excluded_genes) {
432  assert_ref($excluded_genes, 'ARRAY', 'excluded genes');
433  foreach my $gene (@{$excluded_genes}) {
434  my $gene_id = (ref($gene)) ? $gene->dbID() : $gene;
435  $gene_exclusions{$gene_id} = $gene_id;
436  }
437  }
438 
439  my @gene_ids;
440 
441  foreach my $allele (@$list) {
442  my ($gene_id,$type) = @$allele;
443  if ($all_but_rep && $type->{IS_REPRESENTATIVE}) {next;}
444  if(exists $gene_exclusions{$gene_id}) { next; }
445  push @gene_ids,$gene_id;
446  }
447  return [sort {$a <=> $b} @gene_ids];
448 }
449 
450 =head2 get_representative_Gene
451 
452  Description : Used to fetch a Gene object which has been marked as the
453  representative Gene for this alt allele group.
454  Returntype : Bio::EnsEMBL::Gene object which is the representative gene
455 
456 =cut
457 
458 
459 sub get_representative_Gene {
460  my $self = shift;
461  my $ga = $self->adaptor->db->get_GeneAdaptor;
462 
463  return $ga->fetch_by_dbID($self->rep_Gene_id);
464 }
465 
466 =head2 get_all_Genes
467 
468  Arg[1] : Boolean - Do not include representative gene in list of ids.
469  Arg[2] : ArrayRef - Can contain dbIDs or Gene objects to exclude from the returned list
470  Description : Fetches all the Gene objects within the allele group. It can also
471  be used to list those Genes that are not the representative Gene.
472  Returntype : ArrayRef of Bio::EnsEMBL::Gene objects
473 
474 =cut
475 
476 
477 sub get_all_Genes {
478  my ($self, $all_but_rep, $excluded_genes) = @_;
479  my $gene_ids = $self->get_all_Gene_ids($all_but_rep, $excluded_genes);
480  return $self->adaptor()->db()->get_GeneAdaptor()->fetch_all_by_dbID_list($gene_ids);
481 }
482 
483 
484 =head2 get_all_Genes_types
485 
486  Arg[1] : Boolean - Do not include representative gene in list of ids.
487  Arg[2] : ArrayRef - Can contain dbIDs or Gene objects to exclude from the returned list
488  Description : Fetches all the Gene objects within the allele group and their
489  associcated attributes. It can also be used to list those
490  Genes that are not the representative Gene.
491  Returntype : ArrayRef. 2 dimensional holding [Bio::EnsEMBL::Gene, {attribute_hash}]
492 
493 =cut
494 
495 sub get_all_Genes_types {
496  my ($self, $all_but_rep, $excluded_genes) = @_;
497  my $gene_ids = $self->get_all_Gene_ids($all_but_rep, $excluded_genes);
498  my $ga = $self->adaptor()->db()->get_GeneAdaptor();
499  my @output;
500  my $members = $self->{MEMBERS};
501  foreach my $allele (@{$members}) {
502  my ($gene_id,$attribs) = @$allele;
503  if ($all_but_rep && $attribs->{IS_REPRESENTATIVE}) {next;}
504  my $gene = $ga->fetch_by_dbID($gene_id);
505  my %attribs_copy = %{$attribs};
506  push(@output, [$gene, \%attribs_copy])
507  }
508  return \@output;
509 }
510 
511 =head2 size
512 
513  Description : Returns the current size of this group in members
514  Returntype : Int the size of the current alt allele group
515 
516 =cut
517 
518 sub size {
519  my $self = shift;
520  my $list = $self->{'MEMBERS'};
521  return scalar(@$list);
522 }
523 
524 
525 =head2 get_all_members
526 
527  Description : Retrieves all of the information about all members. Be aware
528  that this emits the interal data structure so direct modification
529  should be done with caution.
530  Returntype : ArrayRef of id and type list: [gene_id,type]
531  Caller : AltAlleleGroupAdaptor->store
532 
533 =cut
534 
535 sub get_all_members {
536  my $self = shift;
537  my $members = $self->{'MEMBERS'};
538  return $members;
539 }
540 
541 
542 1;
Bio::EnsEMBL::AltAlleleGroup
Definition: AltAlleleGroup.pm:67
Bio::EnsEMBL::Storable
Definition: Storable.pm:23
Bio::EnsEMBL::Gene
Definition: Gene.pm:37
Bio::EnsEMBL::Registry
Definition: Registry.pm:113
Bio::EnsEMBL::Registry::get_DBAdaptor
public DBAdaptor get_DBAdaptor()
Bio::EnsEMBL::Utils::Scalar
Definition: Scalar.pm:66
Bio::EnsEMBL::AltAlleleGroup::remove_all_members
public remove_all_members()
Bio::EnsEMBL::AltAlleleGroup::new
public Bio::EnsEMBL::AltAlleleGroup new()
Bio::EnsEMBL::Utils::Argument
Definition: Argument.pm:34
Bio::EnsEMBL::Utils::Exception
Definition: Exception.pm:68
Bio::EnsEMBL::DBSQL::AltAlleleGroupAdaptor
Definition: AltAlleleGroupAdaptor.pm:36