Source code for ontobio.ontol

"""
A module for representing simple graph-oriented views of an ontology

See also:

 - ontol_factory.py

"""

import networkx as nx
import logging
import re

logger = logging.getLogger(__name__)

[docs]class Ontology(): """An object that represents a basic graph-oriented view over an ontology. The ontology may be represented in memory, or it may be located remotely. See subclasses for details. The default implementation is an in-memory wrapper onto the python networkx library """ def __init__(self, handle=None, id=None, graph=None, xref_graph=None, meta=None, payload=None, graphdoc=None): """ initializes based on an ontology name. **Note**: do not call this directly, use OntologyFactory instead """ self.handle = handle self.meta = meta if id is None: if payload is not None: id = payload.get('id') if id is None: id = handle self.id = id # networkx object self.graph = graph if self.graph is None: self.graph = nx.MultiDiGraph() logger.debug('Graph initialized, nodes={}'.format(self.graph.nodes())) self.xref_graph = xref_graph # obograph self.graphdoc = graphdoc self.all_logical_definitions = [] self.all_property_chain_axioms = [] # alternatively accept a payload object if payload is not None: self.meta = payload.get('meta') self.graph = payload.get('graph') self.xref_graph = payload.get('xref_graph') self.graphdoc = payload.get('graphdoc') self.all_logical_definitions = payload.get('logical_definitions') self.all_property_chain_axioms = payload.get('property_chain_axioms') def __str__(self): return '{} handle: {} meta: {}'.format(self.id, self.handle, self.meta) def __repr__(self): return self.__str__()
[docs] def get_graph(self): """ Return a networkx graph for the whole ontology. Note: Only implemented for *eager* implementations Return ------ nx.MultiDiGraph A networkx MultiDiGraph object representing the complete ontology """ return self.graph
# consider caching
[docs] def get_filtered_graph(self, relations=None, prefix=None): """ Returns a networkx graph for the whole ontology, for a subset of relations Only implemented for eager methods. Implementation notes: currently this is not cached Arguments --------- - relations : list list of object property IDs, e.g. subClassOf, BFO:0000050. If empty, uses all. - prefix : String if specified, create a subgraph using only classes with this prefix, e.g. ENVO, PATO, GO Return ------ nx.MultiDiGraph A networkx MultiDiGraph object representing the filtered ontology """ # trigger synonym cache self.all_synonyms() self.all_obsoletes() # default method - wrap get_graph srcg = self.get_graph() if prefix is not None: srcg = srcg.subgraph([n for n in srcg.nodes() if n.startswith(prefix+":")]) if relations is None: logger.info("No filtering on "+str(self)) return srcg logger.info("Filtering {} for {}".format(self, relations)) g = nx.MultiDiGraph() # TODO: copy full metadata logger.info("copying nodes") for (n,d) in srcg.nodes(data=True): g.add_node(n, **d) logger.info("copying edges") num_edges = 0 for (x,y,d) in srcg.edges(data=True): if d['pred'] in relations: num_edges += 1 g.add_edge(x,y,**d) logger.info("Filtered edges: {}".format(num_edges)) return g
[docs] def merge(self, ontologies): """ Merges specified ontology into current ontology """ if self.xref_graph is None: self.xref_graph = nx.MultiGraph() logger.info("Merging source: {} xrefs: {}".format(self, len(self.xref_graph.edges()))) for ont in ontologies: logger.info("Merging {} into {}".format(ont, self)) g = self.get_graph() srcg = ont.get_graph() for n in srcg.nodes(): g.add_node(n, **srcg.nodes[n]) for (o,s,m) in srcg.edges(data=True): g.add_edge(o,s,**m) if ont.xref_graph is not None: for (o,s,m) in ont.xref_graph.edges(data=True): self.xref_graph.add_edge(o,s,**m) if ont.all_logical_definitions is not None: for ld in ont.all_logical_definitions: self.add_logical_definition(ld) if ont.all_property_chain_axioms is not None: for pca in ont.all_property_chain_axioms: self.add_property_chain_axiom(pca)
[docs] def subgraph(self, nodes=None): """ Return an induced subgraph By default this wraps networkx subgraph, but this may be overridden in specific implementations """ if nodes is None: nodes = [] return self.get_graph().subgraph(nodes)
[docs] def subontology(self, nodes=None, minimal=False, relations=None): """ Return a new ontology that is an extract of this one Arguments --------- - nodes: list list of node IDs to include in subontology. If None, all are used - relations: list list of relation IDs to include in subontology. If None, all are used """ g = None if nodes is not None: g = self.subgraph(nodes) else: g = self.get_graph() if minimal: from ontobio.slimmer import get_minimal_subgraph g = get_minimal_subgraph(g, nodes) ont = Ontology(graph=g, xref_graph=self.xref_graph) # TODO - add metadata if relations is not None: g = ont.get_filtered_graph(relations) ont = Ontology(graph=g, xref_graph=self.xref_graph) return ont
[docs] def create_slim_mapping(self, subset=None, subset_nodes=None, relations=None, disable_checks=False): """ Create a dictionary that maps between all nodes in an ontology to a subset Arguments --------- ont : `Ontology` Complete ontology to be mapped. Assumed pre-filtered for relationship types subset : str Name of subset to map to, e.g. goslim_generic nodes : list If no named subset provided, subset is passed in as list of node ids relations : list List of relations to filter on disable_checks: bool Unless this is set, this will prevent a mapping being generated with non-standard relations. The motivation here is that the ontology graph may include relations that it is inappropriate to propagate gene products over, e.g. transports, has-part Return ------ dict maps all nodes in ont to one or more non-redundant nodes in subset Raises ------ ValueError if the subset is empty """ if subset is not None: subset_nodes = self.extract_subset(subset) logger.info("Extracting subset: {} -> {}".format(subset, subset_nodes)) if subset_nodes is None or len(subset_nodes) == 0: raise ValueError("subset nodes is blank") subset_nodes = set(subset_nodes) logger.debug("SUBSET: {}".format(subset_nodes)) # Use a sub-ontology for mapping subont = self if relations is not None: subont = self.subontology(relations=relations) if not disable_checks: for r in subont.relations_used(): if r != 'subClassOf' and r != 'BFO:0000050' and r != 'subPropertyOf': raise ValueError("Not safe to propagate over a graph with edge type: {}".format(r)) m = {} for n in subont.nodes(): ancs = subont.ancestors(n, reflexive=True) ancs_in_subset = subset_nodes.intersection(ancs) m[n] = list(subont.filter_redundant(ancs_in_subset)) return m
[docs] def filter_redundant(self, ids): """ Return all non-redundant ids from a list """ sids = set(ids) for id in ids: sids = sids.difference(self.ancestors(id, reflexive=False)) return sids
[docs] def extract_subset(self, subset, contract=True): """ Return all nodes in a subset. We assume the oboInOwl encoding of subsets, and subset IDs are IRIs, or IR fragments """ return [n for n in self.nodes() if subset in self.subsets(n, contract=contract)]
[docs] def subsets(self, nid, contract=True): """ Retrieves subset ids for a class or ontology object """ n = self.node(nid) subsets = [] meta = self._meta(nid) if 'subsets' in meta: subsets = meta['subsets'] else: subsets = [] if contract: subsets = [self._contract_subset(s) for s in subsets] return subsets
def _contract_subset(self, s): if s.find("#") > -1: return s.split('#')[-1] else: return s def _meta(self, nid): n = self.node(nid) return n.get("meta", {})
[docs] def prefixes(self): """ list all prefixes used """ pset = set() for n in self.nodes(): pfx = self.prefix(n) if pfx is not None: pset.add(pfx) return list(pset)
[docs] def prefix_fragment(self, nid): """ Return prefix and fragment/localid for a node """ sep=':' if nid.startswith('http'): if '#' in nid: sep='#' else: sep='/' parts = nid.split(sep) frag = parts.pop() prefix = sep.join(parts) return prefix, frag
[docs] def prefix(self, nid): """ Return prefix for a node """ pfx,_ = self.prefix_fragment(nid) return pfx
[docs] def nodes(self): """ Return all nodes in ontology Wraps networkx by default """ return self.get_graph().nodes()
[docs] def node(self, id): """ Return a node with a given ID. If the node with the ID exists the Node object is returned, otherwise None is returned. Wraps networkx by default """ return self.get_graph().nodes.get(id, None)
[docs] def has_node(self, id): """ True if id identifies a node in the ontology graph """ return id in self.get_graph().nodes()
[docs] def sorted_nodes(self): """ Returns all nodes in ontology, after topological sort """ return nx.topological_sort(self.get_graph())
[docs] def node_type(self, id): """ If stated, either CLASS, PROPERTY or INDIVIDUAL """ return self.node(id).get('type', None)
[docs] def relations_used(self): """ Return list of all relations used to connect edges """ g = self.get_graph() types = set() for (x,y,d) in g.edges(data=True): types.add(d['pred']) return list(types)
def neighbors(self, node, relations=None): return self.parents(node, relations=relations) + self.children(node, relations=relations)
[docs] def child_parent_relations(self, subj, obj, graph=None): """ Get all relationship type ids between a subject and a parent. Typically only one relation ID returned, but in some cases there may be more than one Arguments --------- subj: string Child (subject) id obj: string Parent (object) id Returns ------- list """ if graph is None: graph = self.get_graph() preds = set() for _,ea in graph[obj][subj].items(): preds.add(ea['pred']) logger.debug('{}->{} = {}'.format(subj,obj,preds)) return preds
[docs] def parents(self, node, relations=None): """ Return all direct 'parents' of specified node. Note that in the context of ontobio, 'parent' means any node that is traversed in a single hop along an edge from a subject to object. For example, if the ontology has an edge "finger part-of some hand", then "hand" is the parent of finger. This can sometimes be counter-intutitive, for example, if the ontology contains has-part axioms. If the ontology has an edge "X receptor activity has-part some X binding", then "X binding" is the 'parent' of "X receptor activity" over a has-part edge. Wraps networkx by default. Arguments --------- node: string identifier for node in ontology relations: list of strings list of relation (object property) IDs used to filter """ g = self.get_graph() if node in g: parents = list(g.predecessors(node)) if relations is None: return parents else: rset = set(relations) return [p for p in parents if len(self.child_parent_relations(node, p, graph=g).intersection(rset)) > 0 ] else: return []
[docs] def children(self, node, relations=None): """ Return all direct children of specified node. Wraps networkx by default. Arguments --------- node: string identifier for node in ontology relations: list of strings list of relation (object property) IDs used to filter """ g = self.get_graph() if node in g: children = list(g.successors(node)) if relations is None: return children else: rset = set(relations) return [c for c in children if len(self.child_parent_relations(c, node, graph=g).intersection(rset)) > 0 ] else: return []
[docs] def ancestors(self, node, relations=None, reflexive=False): """Return all ancestors of specified node. The default implementation is to use networkx, but some implementations of the Ontology class may use a database or service backed implementation, for large graphs. Arguments --------- node : str identifier for node in ontology reflexive : bool if true, return query node in graph relations : list relation (object property) IDs used to filter Returns ------- list[str] ancestor node IDs """ seen = set() nextnodes = [node] while len(nextnodes) > 0: nn = nextnodes.pop() if not nn in seen: seen.add(nn) nextnodes += self.parents(nn, relations=relations) if not reflexive: seen -= {node} return list(seen)
[docs] def descendants(self, node, relations=None, reflexive=False): """ Returns all descendants of specified node. The default implementation is to use networkx, but some implementations of the Ontology class may use a database or service backed implementation, for large graphs. Arguments --------- node : str identifier for node in ontology reflexive : bool if true, return query node in graph relations : list relation (object property) IDs used to filter Returns ------- list[str] descendant node IDs """ seen = set() nextnodes = [node] while len(nextnodes) > 0: nn = nextnodes.pop() if not nn in seen: seen.add(nn) nextnodes += self.children(nn, relations=relations) if not reflexive: seen -= {node} return list(seen)
[docs] def equiv_graph(self): """ Returns ------- graph bidirectional networkx graph of all equivalency relations """ eg = nx.Graph() for (u,v,d) in self.get_graph().edges(data=True): if d['pred'] == 'equivalentTo': eg.add_edge(u,v) return eg
[docs] def traverse_nodes(self, qids, up=True, down=False, **args): """ Traverse (optionally) up and (optionally) down from an input set of nodes Arguments --------- qids : list[str] list of seed node IDs to start from up : bool if True, include ancestors down : bool if True, include descendants relations : list[str] list of relations used to filter Return ------ list[str] nodes reachable from qids """ g = self.get_filtered_graph(**args) nodes = set() for id in qids: # reflexive - always add self nodes.add(id) if down: nodes.update(nx.descendants(g, id)) if up: nodes.update(nx.ancestors(g, id)) return nodes
[docs] def get_roots(self, relations=None, prefix=None): """ Get all nodes that lack parents Arguments --------- relations : list[str] list of relations used to filter prefix : str E.g. GO. Exclude nodes that lack this prefix when testing parentage """ g = self.get_filtered_graph(relations=relations, prefix=prefix) # note: we also eliminate any singletons, which includes obsolete classes roots = [n for n in g.nodes() if len(list(g.predecessors(n))) == 0 and len(list(g.successors(n))) > 0] return roots
[docs] def get_level(self, level, relations=None, **args): """ Get all nodes at a particular level Arguments --------- relations : list[str] list of relations used to filter """ g = self.get_filtered_graph(relations) nodes = self.get_roots(relations=relations, **args) for i in range(level): logger.info(" ITERATING TO LEVEL: {} NODES: {}".format(i, nodes)) nodes = [c for n in nodes for c in g.successors(n)] logger.info(" FINAL: {}".format(nodes)) return nodes
[docs] def parent_index(self, relations=None): """ Returns a mapping of nodes to all direct parents Arguments --------- relations : list[str] list of relations used to filter Returns: list list of lists [[CLASS_1, PARENT_1,1, ..., PARENT_1,N], [CLASS_2, PARENT_2,1, PARENT_2,2, ... ] ... ] """ g = None if relations is None: g = self.get_graph() else: g = self.get_filtered_graph(relations) l = [] for n in g: l.append([n] + list(g.predecessors(n))) return l
[docs] def text_definition(self, nid): """ Retrieves logical definitions for a class or relation id Arguments --------- nid : str Node identifier for entity to be queried Returns ------- TextDefinition """ tdefs = [] meta = self._meta(nid) if 'definition' in meta: obj = meta['definition'] return TextDefinition(nid, **obj) else: return None
[docs] def logical_definitions(self, nid): """ Retrieves logical definitions for a class id Arguments --------- nid : str Node identifier for entity to be queried Returns ------- LogicalDefinition """ ldefs = self.all_logical_definitions if ldefs is not None: #print("TESTING: {} AGAINST LD: {}".format(nid, str(ldefs))) return [x for x in ldefs if x.class_id == nid] else: return []
def add_logical_definition(self, logical_def): if self.all_logical_definitions is None: self.all_logical_definitions = [] self.all_logical_definitions.append(logical_def)
[docs] def get_property_chain_axioms(self, nid): """ Retrieves property chain axioms for a class id Arguments --------- nid : str Node identifier for relation to be queried Returns ------- PropertyChainAxiom """ pcas = self.all_property_chain_axioms if pcas is not None: return [x for x in pcas if x.predicate_id == nid] else: return []
def add_property_chain_axiom(self, pca): if self.all_property_chain_axioms is None: self.all_property_chain_axioms = [] self.all_property_chain_axioms.append(pca) def get_node_type(self, nid): n = self.node(nid) if 'type' in n: return n['type'] return None def _get_meta_prop(self, nid, prop): n = self.node(nid) if 'meta' in n: meta = n['meta'] if prop in meta: return meta[prop] return None def _get_meta(self, nid): n = self.node(nid) if 'meta' in n: return n['meta'] return None def _get_basic_property_values(self, nid): r = self._get_meta_prop(nid, 'basicPropertyValues') if r is None: return [] else: return r def _get_basic_property_value(self, nid, prop): bpvs = self._get_basic_property_values(nid) return [x['val'] for x in bpvs if x['pred'] == prop]
[docs] def is_obsolete(self, nid): """ True if node is obsolete Arguments --------- nid : str Node identifier for entity to be queried """ dep = self._get_meta_prop(nid, 'deprecated') return dep is not None and dep
[docs] def replaced_by(self, nid, strict=True): """ Returns value of 'replaced by' (IAO_0100001) property for obsolete nodes Arguments --------- nid : str Node identifier for entity to be queried strict: bool If true, raise error if cardinality>1. If false, return list if cardinality>1 Return ------ None if no value set, otherwise returns node id (or list if multiple values, see strict setting) """ vs = self._get_basic_property_value(nid, 'IAO:0100001') if len(vs) > 1: msg = "replaced_by has multiple values: {}".format(vs) if strict: raise ValueError(msg) else: logger.error(msg) return vs
[docs] def synonyms(self, nid, include_label=False): """ Retrieves synonym objects for a class Arguments --------- nid : str Node identifier for entity to be queried include_label : bool If True, include label/names as Synonym objects Returns ------- list[Synonym] :class:`Synonym` objects """ n = self.node(nid) syns = [] if 'meta' in n: meta = n['meta'] if 'synonyms' in meta: for obj in meta['synonyms']: syns.append(Synonym(nid, **obj)) if include_label: syns.append(Synonym(nid, val=self.label(nid), pred='label')) return syns
def obo_namespace(self, nid): go_namespace = [predval for predval in self.get_graph().nodes .get(nid, {}) .get("meta", {}) .get("basicPropertyValues", []) if predval["pred"] == "OIO:hasOBONamespace"] if len(go_namespace) >= 1: return go_namespace[0]["val"] else: return None
[docs] def add_node(self, id, label=None, type='CLASS', meta=None): """ Add a new node to the ontology """ g = self.get_graph() if meta is None: meta={} g.add_node(id, label=label, type=type, meta=meta)
[docs] def add_text_definition(self, textdef): """ Add a new text definition to the ontology """ self._add_meta_element(textdef.subject, 'definition', textdef.as_dict())
def set_obsolete(self, nid): if nid not in self.get_graph(): self.add_node(nid) self._add_meta_element(nid, 'deprecated', True) def _add_meta_element(self, id, k, edict): n = self.node(id) if n is None: raise ValueError('no such node {}'.format(id)) if 'meta' not in n: n['meta'] = {} n['meta'][k] = edict
[docs] def inline_xref_graph(self): """ Copy contents of xref_graph to inlined meta object for each node """ xg = self.xref_graph for n in self.nodes(): if n in xg: self._add_meta_element(n, 'xrefs', [{'val':x} for x in xg.neighbors(n)])
[docs] def add_parent(self, id, pid, relation='subClassOf'): """ Add a new edge to the ontology """ g = self.get_graph() g.add_edge(pid, id, pred=relation)
[docs] def add_xref(self, id, xref): """ Adds an xref to the xref graph """ # note: does not update meta object if self.xref_graph is None: self.xref_graph = nx.MultiGraph() self.xref_graph.add_edge(xref, id)
[docs] def add_synonym(self, syn): """ Adds a synonym for a node """ n = self.node(syn.class_id) if 'meta' not in n: n['meta'] = {} meta = n['meta'] if 'synonyms' not in meta: meta['synonyms'] = [] meta['synonyms'].append(syn.as_dict())
[docs] def add_to_subset(self, id, s): """ Adds a node to a subset """ n = self.node(id) if 'meta' not in n: n['meta'] = {} meta = n['meta'] if 'subsets' not in meta: meta['subsets'] = [] meta['subsets'].append(s)
[docs] def all_synonyms(self, include_label=False): """ Retrieves all synonyms Arguments --------- include_label : bool If True, include label/names as Synonym objects Returns ------- list[Synonym] :class:`Synonym` objects """ syns = [] for n in self.nodes(): syns = syns + self.synonyms(n, include_label=include_label) return syns
[docs] def all_obsoletes(self): """ Returns all obsolete nodes """ return [n for n in self.nodes() if self.is_obsolete(n)]
[docs] def label(self, nid, id_if_null=False): """ Fetches label for a node Arguments --------- nid : str Node identifier for entity to be queried id_if_null : bool If True and node has no label return id as label Return ------ str """ g = self.get_graph() if nid in g: n = g.nodes[nid] if 'label' in n: return n['label'] else: if id_if_null: return nid else: return None else: if id_if_null: return nid else: return None
[docs] def xrefs(self, nid, bidirectional=False, prefix=None): """ Fetches xrefs for a node Arguments --------- nid : str Node identifier for entity to be queried bidirection : bool If True, include nodes xreffed to nid Return ------ list[str] """ xrefs = [] if self.xref_graph is not None: xg = self.xref_graph if nid not in xg: xrefs = [] else: if bidirectional: xrefs = list(xg.neighbors(nid)) else: xrefs = [x for x in xg.neighbors(nid) if xg[nid][x][0]['source'] == nid] if prefix is not None: xrefs = [x for x in xrefs if self.prefix(x) == prefix] return xrefs
[docs] def resolve_names(self, names, synonyms=False, **args): """ returns a list of identifiers based on an input list of labels and identifiers. Arguments --------- names: list search terms. '%' treated as wildcard synonyms: bool if true, search on synonyms in addition to labels is_regex : bool if true, treats each name as a regular expression is_partial_match : bool if true, treats each name as a regular expression .*name.* """ g = self.get_graph() r_ids = [] for n in names: logger.debug("Searching for {} syns={}".format(n,synonyms)) if len(n.split(":")) == 2: r_ids.append(n) else: matches = set([nid for nid in g.nodes() if self._is_match(self.label(nid), n, **args)]) if synonyms: logger.debug("Searching syns for {}".format(names)) for nid in g.nodes(): for s in self.synonyms(nid): if self._is_match(s.val, n, **args): matches.add(nid) r_ids += list(matches) return r_ids
def _is_match(self, label, term, is_partial_match=False, is_regex=False, **args): if term == '%': # always match if client passes '%' return True if label is None: label = '' if term.find('%') > -1: term = term.replace('%','.*') is_regex = True if is_regex: return re.search(term, label) is not None if is_partial_match: return label.find(term) > -1 else: return label == term
[docs] def search(self, searchterm, **args): """ Simple search. Returns list of IDs. Arguments --------- searchterm: list search term. '%' treated as wildcard synonyms: bool if true, search on synonyms in addition to labels is_regex : bool if true, treats each name as a regular expression is_partial_match : bool if true, treats each name as a regular expression .*name.* Return ------ list match node IDs """ return self.resolve_names([searchterm], **args)
[docs]class LogicalDefinition(): """ A simple OWL logical definition conforming to the pattern: :: class_id = (genus_id_1 AND ... genus_id_n) AND (P_1 some FILLER_1) AND ... (P_m some FILLER_m) See `obographs <https://github.com/geneontology/obographs>`_ docs for more details """ def __init__(self, class_id, genus_ids, restrictions): """ Arguments --------- class_id : string the class that is being defined genus_ids : list a list of named classes (typically length 1) restrictions : list a list of (PROPERTY_ID, FILLER_CLASS_ID) tuples """ self.class_id = class_id self.genus_ids = genus_ids self.restrictions = restrictions def __str__(self): return "{} =def {} AND {}".format(self.class_id, self.genus_ids, self.restrictions) def __repr__(self): return self.__str__()
class AbstractPropertyValue(object): """ Abstract superclass of all property-value mapping classes. These correspond to Annotations in OWL """ def __str__(self): return '{} "{}" {}'.format(self.subject, self.val, self.xrefs) def __repr__(self): return self.__str__() def __cmp__(self, other): (x,y) = (str(self),str(other)) if x > y: return 1 elif x < y: return -1 else: return 0 class TextDefinition(AbstractPropertyValue): """ Represents a textual definition for a class or relation """ def __init__(self, subject, val=None, xrefs=None, ontology=None): """ Arguments --------- - subject : string id for the class or relation that is being defined - val : string the definition itself - xrefs: list Provenance or cross-references to same usage """ self.subject = subject self.val = val self.xrefs = xrefs self.ontology = ontology def as_dict(self): """ Returns TextDefinition as obograph dict """ return { 'val': self.val, 'xrefs': self.xrefs }
[docs]class Synonym(AbstractPropertyValue): """ Represents a synonym using the OBO model """ predmap = dict( label='label', hasExactSynonym='exact', hasBroadSynonym='broad', hasNarrowSynonym='narrow', hasRelatedSynonym='related') def __init__(self, class_id, val=None, pred='hasRelatedSynonym', lextype=None, xrefs=None, ontology=None, confidence=1.0, synonymType=None): """ Arguments --------- - class_id : string the class that is being defined - val : string the synonym itself - pred: string oboInOwl predicate used to model scope. One of: has{Exact,Narrow,Related,Broad}Synonym - may also be 'label' - lextype: string From an open ended set of types - xrefs: list Provenance or cross-references to same usage """ pred = pred.replace("http://www.geneontology.org/formats/oboInOwl#", "") self.class_id = class_id self.val = val self.pred = pred self.lextype = lextype self.xrefs = xrefs self.ontology = ontology self.confidence = confidence self.synonymType = synonymType def __str__(self): return '{} "{}" {} {} {} {} {}'.format(self.class_id, self.val, self.pred, self.lextype, self.xrefs, self.confidence, self.synonymType) def __repr__(self): return self.__str__() def scope(self): if self.pred in self.predmap: return self.predmap[self.pred].upper() else: return self.pred.upper() def is_label(self): return self.pred == 'label' def is_abbreviation(self, v=None): if v is not None: self.lextype = 'abbreviation' return self.lextype is not None and self.lextype.lower() == 'abbreviation' def exact_or_label(self): return self.pred == 'hasExactSynonym' or self.pred == 'label'
[docs] def as_dict(self): """ Returns Synonym as obograph dict """ # TODO: complete metadata return { 'pred': self.pred, 'val': self.val, 'xrefs': self.xrefs }
def __cmp__(self, other): (x, y) = (str(self), str(other)) if x > y: return 1 if x < y: return -1 return 0
class PropertyChainAxiom(object): """ Represents a property chain axiom used to infer the existence of a property from a chain of properties. See the OWL primer for a description of property chains: https://www.w3.org/TR/owl2-primer/#Property_Chains """ def __init__(self, predicate_id, chain_predicate_ids): """ Arguments --------- - predicate_id : string the object property - chain_predicate_ids: list ordered list of chained properties """ self.predicate_id = predicate_id self.chain_predicate_ids = chain_predicate_ids def __str__(self): return '{} ({})'.format(self.predicate_id, " o ".join(self.chain_predicate_ids)) def as_dict(self): """ Returns PropertyChainAxiom as obograph dict """ return { "predicateId": self.predicate_id, "chainPredicateIds": self.chain_predicate_ids }