sync w/ main trunk
[bioperl-live.git] / Bio / Ontology / OBOEngine.pm
blob8d3d776f04d428b60aa57c76bde80d99d3e5de14
1 # $Id$
3 # BioPerl module for Bio::Ontology::OBOEngine
5 # POD documentation - main docs before the code
7 =head1 NAME
9 Bio::Ontology::OBOEngine - An Ontology Engine for OBO style flat file
10 format from the Gene Ontology Consortium
12 =head1 SYNOPSIS
14 use Bio::Ontology::OBOEngine;
16 my $parser = Bio::Ontology::OBOEngine->new
17 ( -file => "gene_ontology.obo" );
19 my $engine = $parser->parse();
21 =head1 DESCRIPTION
23 Needs Graph.pm from CPAN.
25 This module replaces SimpleGOEngine.pm, which is deprecated.
27 =head1 FEEDBACK
29 =head2 Mailing Lists
31 User feedback is an integral part of the evolution of this and other
32 Bioperl modules. Send your comments and suggestions preferably to the
33 Bioperl mailing lists Your participation is much appreciated.
35 bioperl-l@bioperl.org - General discussion
36 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
38 =head2 Support
40 Please direct usage questions or support issues to the mailing list:
42 L<bioperl-l@bioperl.org>
44 rather than to the module maintainer directly. Many experienced and
45 reponsive experts will be able look at the problem and quickly
46 address it. Please include a thorough description of the problem
47 with code and data examples if at all possible.
49 =head2 Reporting Bugs
51 Report bugs to the Bioperl bug tracking system to help us keep track
52 the bugs and their resolution. Bug reports can be submitted via
53 the web:
55 http://bugzilla.open-bio.org/
57 =head1 AUTHOR
59 Sohel Merchant
61 Email: s-merchant@northwestern.edu
63 Address:
65 Northwestern University
66 Center for Genetic Medicine (CGM), dictyBase
67 Suite 1206,
68 676 St. Clair st
69 Chicago IL 60611
71 =head2 CONTRIBUTOR
73 Hilmar Lapp, hlapp at gmx.net
74 Chris Mungall, cjm at fruitfly.org
76 =head1 APPENDIX
78 The rest of the documentation details each of the object
79 methods. Internal methods are usually preceded with a _
81 =cut
83 package Bio::Ontology::OBOEngine;
85 use Bio::Ontology::SimpleGOEngine::GraphAdaptor;
87 use strict;
88 use Bio::Ontology::RelationshipType;
89 use Bio::Ontology::RelationshipFactory;
90 use Data::Dumper;
92 use constant TRUE => 1;
93 use constant FALSE => 0;
94 use constant IS_A => "IS_A";
95 use constant PART_OF => "PART_OF";
96 use constant RELATED_TO => "RELATED_TO";
97 use constant TERM => "TERM";
98 use constant TYPE => "TYPE";
99 use constant ONTOLOGY => "ONTOLOGY";
100 use constant REGULATES => "REGULATES";
101 use constant POSITIVELY_REGULATES => "POSITIVELY_REGULATES";
102 use constant NEGATIVELY_REGULATES => "NEGATIVELY_REGULATES";
105 use base qw(Bio::Root::Root Bio::Ontology::OntologyEngineI);
109 =head2 new
111 Title : new
112 Usage : $engine = Bio::Ontology::OBOEngine->new()
113 Function: Creates a new OBOEngine
114 Returns : A new OBOEngine object
115 Args :
117 =cut
119 sub new {
120 my( $class, @args ) = @_;
122 my $self = $class->SUPER::new( @args );
124 $self->init();
126 return $self;
127 } # new
131 =head2 init
133 Title : init()
134 Usage : $engine->init();
135 Function: Initializes this Engine.
136 Returns :
137 Args :
139 =cut
141 sub init {
142 my ( $self ) = @_;
144 $self->{ "_is_a_relationship" } = Bio::Ontology::RelationshipType->get_instance( IS_A );
145 $self->{ "_part_of_relationship" } = Bio::Ontology::RelationshipType->get_instance( PART_OF );
146 $self->{ "_related_to_relationship" } = Bio::Ontology::RelationshipType->get_instance( RELATED_TO );
148 $self->{'_regulates_relationship'} = Bio::Ontology::RelationshipType->get_instance(REGULATES);
149 $self->{'_positively_regulate'} = Bio::Ontology::RelationshipType->get_instance(POSITIVELY_REGULATES);
150 $self->{'_negatively_regulate'} = Bio::Ontology::RelationshipType->get_instance(NEGATIVELY_REGULATES);
153 $self->graph( Bio::Ontology::SimpleGOEngine::GraphAdaptor->new() ); # NG 05-02-16
155 # set defaults for the factories
156 $self->relationship_factory(Bio::Ontology::RelationshipFactory->new(
157 -type => "Bio::Ontology::Relationship"));
159 } # init
163 =head2 is_a_relationship
165 Title : is_a_relationship()
166 Usage : $IS_A = $engine->is_a_relationship();
167 Function: Returns a Bio::Ontology::RelationshipType object for "is-a"
168 relationships
169 Returns : Bio::Ontology::RelationshipType set to "IS_A"
170 Args :
172 =cut
174 sub is_a_relationship {
175 my ( $self, $value ) = @_;
177 if ( defined $value ) {
178 $self->throw( "Attempted to change immutable field" );
181 return $self->{ "_is_a_relationship" };
182 } # is_a_relationship
186 =head2 part_of_relationship
188 Title : part_of_relationship()
189 Usage : $PART_OF = $engine->part_of_relationship();
190 Function: Returns a Bio::Ontology::RelationshipType object for "part-of"
191 relationships
192 Returns : Bio::Ontology::RelationshipType set to "PART_OF"
193 Args :
195 =cut
197 sub part_of_relationship {
198 my ( $self, $value ) = @_;
200 if ( defined $value ) {
201 $self->throw( "Attempted to change immutable field" );
204 return $self->{ "_part_of_relationship" };
205 } # part_of_relationship
208 =head2 related_to_relationship
210 Title : related_to_relationship()
211 Usage : $RELATED_TO = $engine->related_to_relationship();
212 Function: Returns a Bio::Ontology::RelationshipType object for "related-to"
213 relationships
214 Returns : Bio::Ontology::RelationshipType set to "RELATED_TO"
215 Args :
217 =cut
219 sub related_to_relationship {
220 my ( $self, $value ) = @_;
222 if ( defined $value ) {
223 $self->throw( "Attempted to change immutable field" );
226 return $self->{ "_related_to_relationship" };
227 } # related_to_relationship
229 =head2 regulates_relationship
231 Title : regulates_relationship()
232 Usage : $REGULATES = $engine->regulates_relationship();
233 Function: Returns a Bio::Ontology::RelationshipType object for "regulates"
234 relationships
235 Returns : Bio::Ontology::RelationshipType set to "REGULATES"
236 Args :
238 =cut
240 sub regulates_relationship {
241 my ( $self, $value ) = @_;
243 if ( defined $value ) {
244 $self->throw( "Attempted to change immutable field" );
247 return $self->{ "_regulates_relationship" };
248 } # is_a_relationship
250 =head2 positively_regulates_relationship
252 Title : positively_regulates_relationship()
253 Usage : $REGULATES = $engine->positively_regulates_relationship();
254 Function: Returns a Bio::Ontology::RelationshipType object for "positively_regulates"
255 relationships
256 Returns : Bio::Ontology::RelationshipType set to "POSITIVELY_REGULATES"
257 Args :
259 =cut
261 sub positively_regulates_relationship {
262 my ( $self, $value ) = @_;
264 if ( defined $value ) {
265 $self->throw( "Attempted to change immutable field" );
268 return $self->{ "_positively_regulate" };
271 =head2 negatively_regulates_relationship
273 Title : negatively_regulates_relationship()
274 Usage : $REGULATES = $engine->negatively_regulates_relationship();
275 Function: Returns a Bio::Ontology::RelationshipType object for "negatively_regulates"
276 relationships
277 Returns : Bio::Ontology::RelationshipType set to "POSITIVELY_REGULATES"
278 Args :
280 =cut
282 sub negatively_regulates_relationship {
283 my ( $self, $value ) = @_;
285 if ( defined $value ) {
286 $self->throw( "Attempted to change immutable field" );
289 return $self->{ "_negatively_regulate" };
293 =head2 add_term
295 Title : add_term
296 Usage : $engine->add_term( $term_obj );
297 Function: Adds a Bio::Ontology::TermI to this engine
298 Returns : true if the term was added and false otherwise (e.g., if the
299 term already existed in the ontology engine)
300 Args : Bio::Ontology::TermI
302 =cut
304 sub add_term {
305 my ( $self, $term ) = @_;
307 return FALSE if $self->has_term( $term );
309 my $goid = $self->_get_id($term);
311 $self->graph()->add_vertex( $goid );
312 $self->graph()->set_vertex_attribute( $goid, TERM, $term ); # NG 05-02-16
313 return TRUE;
315 } # add_term
319 =head2 has_term
321 Title : has_term
322 Usage : $engine->has_term( $term );
323 Function: Checks whether this engine contains a particular term
324 Returns : true or false
325 Args : Bio::Ontology::TermI
327 Term identifier (e.g. "GO:0012345")
329 =cut
331 sub has_term {
332 my ( $self, $term ) = @_;
333 $term = $self->_get_id( $term );
334 if ( $self->graph()->has_vertex( $term ) ) {
335 return TRUE;
337 else {
338 return FALSE;
341 } # has_term
344 =head2 add_relationship_type
346 Title : add_relationship_type
347 Usage : $engine->add_relationship_type( $type_name, $ont );
348 Function: Adds a new relationship type to the engine. Use
349 get_relationship_type($type_name) to retrieve.
350 Returns : true if successfully added, false otherwise
351 Args : relationship type name to add (scalar)
352 ontology to which to assign the relationship type
354 =cut
356 sub add_relationship_type{
357 my ($self,@args) = @_;
359 if(scalar(@_) == 3){
360 my $type_name = $args[0];
361 my $ont = $args[1];
362 $self->{ "_extra_relationship_types" }{$type_name} = Bio::Ontology::RelationshipType->get_instance($type_name,$ont);
363 #warn Dumper($self->{"_extra_relationship_types"}{$type_name});
364 return 1;
366 return 0;
370 =head2 get_relationship_type
372 Title : get_relationship_type
373 Usage : $engine->get_relationship_type( $type_name );
374 Function: Gets a Bio::Ontology::RelationshipI object corresponding
375 to $type_name
376 Returns : a Bio::Ontology::RelationshipI object
377 Args :
379 =cut
381 sub get_relationship_type{
382 my ($self,$type_name) = @_;
383 return $self->{ "_extra_relationship_types" }{$type_name};
386 =head2 add_relationship
388 Title : add_relationship
389 Usage : $engine->add_relationship( $relationship );
390 $engine->add_relatioship( $subject_term, $predicate_term,
391 $object_term, $ontology );
392 $engine->add_relatioship( $subject_id, $predicate_id,
393 $object_id, $ontology);
394 Function: Adds a relationship to this engine
395 Returns : true if successfully added, false otherwise
396 Args : The relationship in one of three ways:
398 a) subject (or child) term id, Bio::Ontology::TermI
399 (rel.type), object (or parent) term id, ontology
403 b) subject Bio::Ontology::TermI, predicate
404 Bio::Ontology::TermI (rel.type), object
405 Bio::Ontology::TermI, ontology
409 c) Bio::Ontology::RelationshipI-compliant object
411 =cut
413 # term objs or term ids
414 sub add_relationship {
415 my ( $self, $child, $type, $parent, $ont ) = @_;
417 if ( scalar( @_ ) == 2 ) {
418 $self->_check_class( $child, "Bio::Ontology::RelationshipI" );
419 $type = $child->predicate_term();
420 $parent = $child->object_term();
421 $ont = $child->ontology();
422 $child = $child->subject_term();
426 $self->_check_class( $type, "Bio::Ontology::TermI" );
428 my $parentid = $self->_get_id( $parent );
429 my $childid = $self->_get_id( $child );
431 my $g = $self->graph();
433 $self->add_term($child) unless $g->has_vertex( $childid );
434 $self->add_term($parent) unless $g->has_vertex( $parentid );
436 # This prevents multi graphs.
437 if ( $g->has_edge( $parentid, $childid ) ) {
438 return FALSE;
441 $g->add_edge( $parentid, $childid );
442 $g->set_edge_attribute( $parentid, $childid, TYPE, $type ); # NG 05-02-16
443 $g->set_edge_attribute( $parentid, $childid, ONTOLOGY, $ont ); # NG 05-02-16
445 return TRUE;
447 } # add_relationship
452 =head2 get_relationships
455 Title : get_relationships
456 Usage : $engine->get_relationships( $term );
457 Function: Returns all relationships of a term, or all relationships in
458 the graph if no term is specified.
459 Returns : Relationship
460 Args : term id
462 Bio::Ontology::TermI
464 =cut
466 sub get_relationships {
467 my ( $self, $term ) = @_;
469 my $g = $self->graph();
471 # obtain the ID if term provided
472 my $termid;
473 if($term) {
474 $termid = $self->_get_id( $term );
475 # check for presence in the graph
476 if ( ! $g->has_vertex( $termid ) ) {
477 $self->throw( "no term with identifier \"$termid\" in ontology" );
481 # now build the relationships
482 my $relfact = $self->relationship_factory();
483 # we'll build the relationships from edges
484 my @rels = ();
485 my @edges = $termid ? $g->edges_at( $termid ) : $g->edges(); # NG 05-02-13
486 while(@edges) {
487 my ( $startid, $endid ) = @{ shift @edges }; # NG 05-02-16
488 my $rel = $relfact->create_object
489 (-subject_term => $self->get_terms($endid),
490 -object_term => $self->get_terms($startid),
491 -predicate_term => $g->get_edge_attribute($startid, $endid, TYPE),
492 -ontology => $g->get_edge_attribute($startid, $endid, ONTOLOGY));
493 push( @rels, $rel );
497 return @rels;
499 } # get_relationships
501 =head2 get_all_relationships
504 Title : get_all_relationships
505 Usage : @rels = $engine->get_all_relationships();
506 Function: Returns all relationships in the graph.
507 Returns : Relationship
508 Args :
510 =cut
512 sub get_all_relationships {
513 return shift->get_relationships(@_);
514 } # get_all_relationships
518 =head2 get_predicate_terms
520 Title : get_predicate_terms
521 Usage : $engine->get_predicate_terms();
522 Function: Returns the types of relationships this engine contains
523 Returns : Bio::Ontology::RelationshipType
524 Args :
526 =cut
528 sub get_predicate_terms {
529 my ( $self ) = @_;
531 my @a = (
532 $self->is_a_relationship(),
533 $self->part_of_relationship(),
534 $self->related_to_relationship(),
535 $self->regulates_relationship(),
536 $self->positively_regulates_relationship(),
537 $self->negatively_regulates_relationship(),
540 foreach my $termname (keys %{$self->{ "_extra_relationship_types" }}){
541 push @a, $self->{ "_extra_relationship_types" }{ $termname };
544 return @a;
545 } # get_predicate_terms
550 =head2 get_child_terms
552 Title : get_child_terms
553 Usage : $engine->get_child_terms( $term_obj, @rel_types );
554 $engine->get_child_terms( $term_id, @rel_types );
555 Function: Returns the children of this term
556 Returns : Bio::Ontology::TermI
557 Args : Bio::Ontology::TermI, Bio::Ontology::RelationshipType
559 term id, Bio::Ontology::RelationshipType
561 if NO Bio::Ontology::RelationshipType is indicated: children
562 of ALL types are returned
564 =cut
566 sub get_child_terms {
567 my ( $self, $term, @types ) = @_;
569 return $self->_get_child_parent_terms_helper( $term, TRUE, @types );
571 } # get_child_terms
574 =head2 get_descendant_terms
576 Title : get_descendant_terms
577 Usage : $engine->get_descendant_terms( $term_obj, @rel_types );
578 $engine->get_descendant_terms( $term_id, @rel_types );
579 Function: Returns the descendants of this term
580 Returns : Bio::Ontology::TermI
581 Args : Bio::Ontology::TermI, Bio::Ontology::RelationshipType
583 term id, Bio::Ontology::RelationshipType
585 if NO Bio::Ontology::RelationshipType is indicated:
586 descendants of ALL types are returned
588 =cut
590 sub get_descendant_terms {
591 my ( $self, $term, @types ) = @_;
593 my %ids = ();
594 my @ids = ();
596 $term = $self->_get_id( $term );
598 if ( ! $self->graph()->has_vertex( $term ) ) {
599 $self->throw( "Ontology does not contain a term with an identifier of \"$term\"" );
602 $self->_get_descendant_terms_helper( $term, \%ids, \@types );
604 while( ( my $id ) = each ( %ids ) ) {
605 push( @ids, $id );
608 return $self->get_terms( @ids );
610 } # get_descendant_terms
613 =head2 get_parent_terms
615 Title : get_parent_terms
616 Usage : $engine->get_parent_terms( $term_obj, @rel_types );
617 $engine->get_parent_terms( $term_id, @rel_types );
618 Function: Returns the parents of this term
619 Returns : Bio::Ontology::TermI
620 Args : Bio::Ontology::TermI, Bio::Ontology::RelationshipType
622 term id, Bio::Ontology::RelationshipType
624 if NO Bio::Ontology::RelationshipType is indicated:
625 parents of ALL types are returned
627 =cut
629 sub get_parent_terms {
630 my ( $self, $term, @types ) = @_;
632 return $self->_get_child_parent_terms_helper( $term, FALSE, @types );
634 } # get_parent_terms
638 =head2 get_ancestor_terms
640 Title : get_ancestor_terms
641 Usage : $engine->get_ancestor_terms( $term_obj, @rel_types );
642 $engine->get_ancestor_terms( $term_id, @rel_types );
643 Function: Returns the ancestors of this term
644 Returns : Bio::Ontology::TermI
645 Args : Bio::Ontology::TermI, Bio::Ontology::RelationshipType
647 term id, Bio::Ontology::RelationshipType
649 if NO Bio::Ontology::RelationshipType is indicated:
650 ancestors of ALL types are returned
652 =cut
654 sub get_ancestor_terms {
655 my ( $self, $term, @types ) = @_;
657 my %ids = ();
658 my @ids = ();
660 $term = $self->_get_id( $term );
662 if ( ! $self->graph()->has_vertex( $term ) ) {
663 $self->throw( "Ontology does not contain a term with an identifier of \"$term\"" );
666 $self->_get_ancestor_terms_helper( $term, \%ids, \@types );
668 while( ( my $id ) = each ( %ids ) ) {
669 push( @ids, $id );
672 return $self->get_terms( @ids );
674 } # get_ancestor_terms
680 =head2 get_leaf_terms
682 Title : get_leaf_terms
683 Usage : $engine->get_leaf_terms();
684 Function: Returns the leaf terms
685 Returns : Bio::Ontology::TermI
686 Args :
688 =cut
690 sub get_leaf_terms {
691 my ( $self ) = @_;
693 my @a = $self->graph()->sink_vertices();
695 return $self->get_terms( @a );
701 =head2 get_root_terms()
703 Title : get_root_terms
704 Usage : $engine->get_root_terms();
705 Function: Returns the root terms
706 Returns : Bio::Ontology::TermI
707 Args :
709 =cut
711 sub get_root_terms {
712 my ( $self ) = @_;
715 my @a = $self->graph()->source_vertices();
717 return $self->get_terms( @a );
722 =head2 get_terms
724 Title : get_terms
725 Usage : @terms = $engine->get_terms( "GO:1234567", "GO:2234567" );
726 Function: Returns term objects with given identifiers
727 Returns : Bio::Ontology::TermI, or the term corresponding to the
728 first identifier if called in scalar context
729 Args : term ids
731 =cut
733 sub get_terms {
734 my ( $self, @ids ) = @_;
736 my @terms = ();
738 foreach my $id ( @ids ) {
739 if ( $self->graph()->has_vertex( $id ) ) {
740 push( @terms, $self->graph()->get_vertex_attribute( $id, TERM ) ); # NG 05-02-16
744 return wantarray ? @terms : shift(@terms);
746 } # get_terms
749 =head2 get_all_terms
751 Title : get_all_terms
752 Usage : $engine->get_all_terms();
753 Function: Returns all terms in this engine
754 Returns : Bio::Ontology::TermI
755 Args :
757 =cut
759 sub get_all_terms {
760 my ( $self ) = @_;
762 return( $self->get_terms( $self->graph()->vertices() ) );
764 } # get_all_terms
767 =head2 find_terms
769 Title : find_terms
770 Usage : ($term) = $oe->find_terms(-identifier => "SO:0000263");
771 Function: Find term instances matching queries for their attributes.
773 This implementation can efficiently resolve queries by
774 identifier.
776 Example :
777 Returns : an array of zero or more Bio::Ontology::TermI objects
778 Args : Named parameters. The following parameters should be recognized
779 by any implementations:
781 -identifier query by the given identifier
782 -name query by the given name
784 =cut
786 sub find_terms{
787 my ($self,@args) = @_;
788 my @terms;
790 my ($id,$name) = $self->_rearrange([qw(IDENTIFIER NAME)],@args);
792 if(defined($id)) {
793 @terms = $self->get_terms($id);
794 } else {
795 @terms = $self->get_all_terms();
797 if(defined($name)) {
798 @terms = grep { $_->name() eq $name; } @terms;
800 return @terms;
804 =head2 find_identically_named_terms
806 Title : find_identically_named_terms
807 Usage : ($term) = $oe->find_identically_named_terms($term0);
808 Function: Find term instances where names match the query term
809 name exactly
810 Example :
811 Returns : an array of zero or more Bio::Ontology::TermI objects
812 Args : a Bio::Ontology::TermI object
814 =cut
816 sub find_identically_named_terms{
817 my ($self,$qterm) = @_;
818 $self->throw("Argument doesn't implement Bio::Ontology::TermI. " . "Bummer." )
819 unless defined $qterm and $qterm->isa("Bio::Ontology::TermI");
821 my %matching_terms;
823 foreach my $term ($self->get_all_terms) {
824 $matching_terms{$term->identifier} = $term and next
825 if $term->name eq $qterm->name;
827 return values %matching_terms;
831 =head2 find_identical_terms
833 Title : find_identical_terms
834 Usage : ($term) = $oe->find_identical_terms($term0);
835 Function: Find term instances where name or synonym
836 matches the query exactly
837 Example :
838 Returns : an array of zero or more Bio::Ontology::TermI objects
839 Args : a Bio::Ontology::TermI object
841 =cut
843 sub find_identical_terms{
844 my ($self,$qterm) = @_;
845 $self->throw("Argument doesn't implement Bio::Ontology::TermI. " . "Bummer." )
846 unless defined $qterm and $qterm->isa("Bio::Ontology::TermI");
848 my %matching_terms;
850 foreach my $qstring ($qterm->name, $qterm->each_synonym) {
851 foreach my $term ($self->get_all_terms) {
852 foreach my $string ( $term->name, $term->each_synonym() ) {
853 $matching_terms{$term->identifier} = $term and next
854 if $string eq $qstring;
858 return values %matching_terms;
861 =head2 find_similar_terms
863 Title : find_similar_terms
864 Usage : ($term) = $oe->find_similar_terms($term0);
865 Function: Find term instances where name or synonym, or part of one,
866 matches the query.
867 Example :
868 Returns : an array of zero or more Bio::Ontology::TermI objects
869 Args : a Bio::Ontology::TermI object
871 =cut
873 sub find_similar_terms{
874 my ($self,$qterm) = @_;
875 $self->throw("Argument doesn't implement Bio::Ontology::TermI. " . "Bummer." )
876 unless defined $qterm and $qterm->isa("Bio::Ontology::TermI");
878 my %matching_terms;
880 foreach my $qstring ($qterm->name, $qterm->each_synonym) {
881 foreach my $term ($self->get_all_terms) {
883 foreach my $string ( $term->name, $term->each_synonym() ) {
884 $matching_terms{$term->identifier} = $term and next
885 if $string =~ /$qstring/ or $qstring =~ /$string/;
889 return values %matching_terms;
893 =head2 relationship_factory
895 Title : relationship_factory
896 Usage : $fact = $obj->relationship_factory()
897 Function: Get/set the object factory to be used when relationship
898 objects are created by the implementation on-the-fly.
900 Example :
901 Returns : value of relationship_factory (a Bio::Factory::ObjectFactoryI
902 compliant object)
903 Args : on set, a Bio::Factory::ObjectFactoryI compliant object
905 =cut
907 sub relationship_factory{
908 my $self = shift;
910 return $self->{'relationship_factory'} = shift if @_;
911 return $self->{'relationship_factory'};
914 =head2 term_factory
916 Title : term_factory
917 Usage : $fact = $obj->term_factory()
918 Function: Get/set the object factory to be used when term objects are
919 created by the implementation on-the-fly.
921 Note that this ontology engine implementation does not
922 create term objects on the fly, and therefore setting this
923 attribute is meaningless.
925 Example :
926 Returns : value of term_factory (a Bio::Factory::ObjectFactoryI
927 compliant object)
928 Args : on set, a Bio::Factory::ObjectFactoryI compliant object
930 =cut
932 sub term_factory{
933 my $self = shift;
935 if(@_) {
936 $self->warn("setting term factory, but ".ref($self).
937 " does not create terms on-the-fly");
938 return $self->{'term_factory'} = shift;
940 return $self->{'term_factory'};
943 =head2 graph
945 Title : graph()
946 Usage : $engine->graph();
947 Function: Returns the Graph this engine is based on
948 Returns : Graph
949 Args :
951 =cut
953 sub graph {
954 my ( $self, $value ) = @_;
956 if ( defined $value ) {
957 $self->_check_class( $value, 'Bio::Ontology::SimpleGOEngine::GraphAdaptor' ); # NG 05-02-16
958 $self->{ "_graph" } = $value;
961 return $self->{ "_graph" };
962 } # graph
965 # Internal methods
966 # ----------------
967 # Checks the correct format of a GOBO-formatted id
968 # Gets the id out of a term or id string
969 sub _get_id {
970 my ( $self, $term ) = @_;
971 my $id = $term;
973 if ( ref($term) ) {
975 # use TermI standard API
976 $self->throw(
977 "Object doesn't implement Bio::Ontology::TermI. " . "Bummer." )
978 unless $term->isa("Bio::Ontology::TermI");
979 $id = $term->identifier();
981 # if there is no ID, we need to fake one from ontology name and name
982 # in order to achieve uniqueness
983 if ( !$id ) {
984 $id = $term->ontology->name() if $term->ontology();
985 $id = $id ? $id . '|' : '';
986 $id .= $term->name();
990 return $id
992 # if $term->isa("Bio::Ontology::GOterm")||($id =~ /^[A-Z_]{1,8}:\d{1,}$/);
993 if $term->isa("Bio::Ontology::OBOterm") || ( $id =~ /^\w+:\w+$/ );
995 # prefix with something if only numbers
996 # if($id =~ /^\d+$/) {
997 # $self->warn(ref($self).": identifier [$id] is only numbers - ".
998 # "prefixing with 'GO:'");
999 # return "GO:" . $id;
1001 # we shouldn't have gotten here if it's at least a remotely decent ID
1002 $self->throw( ref($self) . ": non-standard identifier '$id'\n" )
1003 unless $id =~ /\|/;
1004 return $id;
1005 } # _get_id
1007 # Helper for getting children and parent terms
1008 sub _get_child_parent_terms_helper {
1009 my ( $self, $term, $do_get_child_terms, @types ) = @_;
1011 foreach my $type ( @types ) {
1012 $self->_check_class( $type, "Bio::Ontology::TermI" );
1015 my @relative_terms = ();
1017 $term = $self->_get_id( $term );
1018 if ( ! $self->graph()->has_vertex( $term ) ) {
1019 $self->throw( "Ontology does not contain a term with an identifier of \"$term\"" );
1022 my @all_relative_terms = ();
1023 if ( $do_get_child_terms ) {
1024 @all_relative_terms = $self->graph()->successors( $term );
1026 else {
1027 @all_relative_terms = $self->graph()->predecessors( $term );
1030 foreach my $relative ( @all_relative_terms ) {
1031 if ( scalar( @types ) > 0 ) {
1032 foreach my $type ( @types ) {
1033 my $relative_type;
1034 if ( $do_get_child_terms ) {
1035 $relative_type = $self->graph()->get_edge_attribute ($term, $relative, TYPE ); # NG 05-02-16
1037 else {
1038 $relative_type = $self->graph()->get_edge_attribute ($relative, $term, TYPE ); # NG 05-02-16
1040 if ( $relative_type->equals( $type ) ) {
1041 push( @relative_terms, $relative );
1045 else {
1046 push( @relative_terms, $relative );
1050 return $self->get_terms( @relative_terms );
1052 } # get_child_terms
1055 # Recursive helper
1056 sub _get_descendant_terms_helper {
1057 my ( $self, $term, $ids_ref, $types_ref ) = @_;
1059 my @child_terms = $self->get_child_terms( $term, @$types_ref );
1061 if ( scalar( @child_terms ) < 1 ) {
1062 return;
1065 foreach my $child_term ( @child_terms ) {
1066 my $child_term_id = $self->_get_id($child_term->identifier());
1067 $ids_ref->{ $child_term_id } = 0;
1068 $self->_get_descendant_terms_helper( $child_term_id, $ids_ref, $types_ref );
1071 } # _get_descendant_terms_helper
1074 # Recursive helper
1075 sub _get_ancestor_terms_helper {
1076 my ( $self, $term, $ids_ref, $types_ref ) = @_;
1078 my @parent_terms = $self->get_parent_terms( $term, @$types_ref );
1080 if ( scalar( @parent_terms ) < 1 ) {
1081 return;
1084 foreach my $parent_term ( @parent_terms ) {
1085 my $parent_term_id = $self->_get_id($parent_term->identifier());
1086 $ids_ref->{ $parent_term_id } = 0;
1087 $self->_get_ancestor_terms_helper( $parent_term_id, $ids_ref, $types_ref );
1090 } # get_ancestor_terms_helper
1092 sub _check_class {
1093 my ( $self, $value, $expected_class ) = @_;
1095 if ( ! defined( $value ) ) {
1096 $self->throw( "Found [undef] where [$expected_class] expected" );
1098 elsif ( ! ref( $value ) ) {
1099 $self->throw( "Found [scalar] where [$expected_class] expected" );
1101 elsif ( ! $value->isa( $expected_class ) ) {
1102 $self->throw( "Found [" . ref( $value ) . "] where [$expected_class] expected" );
1105 } # _check_class
1107 #################################################################
1108 # aliases
1109 #################################################################
1111 *get_relationship_types = \&get_predicate_terms;