Exemple #1
0
 def gene_from_rule(rule_name, agent_ix):
     rule_stmt = stmt_from_rule(rule_name, model, stmts)
     if not rule_stmt:
         print("Could not get stmt for rule %s" % rule_name)
         return None
     agent = rule_stmt.agent_list()[agent_ix]
     gene_id = agent.db_refs.get('HGNC')
     gene_name = hgnc_client.get_hgnc_name(gene_id)
     return gene_name
def make_english_output(results, model, stmts):
    citations = {}
    citation_count = 1
    for source, target, polarity, value, found_path, paths, flag in results:
        cond = 'How does treatment with %s %s %s?' % \
            (source, 'increase' if polarity == 'positive' else
                     'decrease', target)
        print(cond)
        print('=' * len(cond))
        if paths:
            path = paths[0]
            sentences = []
            for i, (path_rule, sign) in enumerate(path):
                for rule in model.rules:
                    if rule.name == path_rule:
                        stmt = stmt_from_rule(path_rule, model, stmts)
                        if i == 0:
                            sentences.append('%s is a target of %s.' %
                                            (stmt.agent_list()[0].name, source))

                        # Make citations
                        pmids = [ev.pmid for ev in stmt.evidence if ev.pmid]
                        cit_nums = []
                        for pmid in pmids:
                            cit_num = citations.get(pmid)
                            if cit_num is None:
                                citations[pmid] = citation_count
                                cit_num = citation_count
                                citation_count += 1
                            cit_nums.append(cit_num)
                        if cit_nums:
                            cit_nums = sorted(list(set(cit_nums)))
                            cit_str = ' [%s]' % (','.join([str(c) for c
                                                          in cit_nums]))
                        else:
                            cit_str = ''
                        ea = EnglishAssembler([stmt])
                        sentence = ea.make_model()
                        sentence = sentence[:-1] + cit_str + '.'
                        sentences.append(sentence)
            sentences[-1] = sentences[-1][:-1] + \
                ', which is measured by %s.' % target
            text = ' '.join(sentences)
            print('INDRA\'s hypothesis: ' + text)
        elif found_path:
            print('INDRA determined that there exists an explanation but'
                  ' it is intractable to reconstruct.')
        else:
            print('INDRA couldn\'t find an explanation for this observation.')
        print('\n')
    references = 'References\n==========\n'
    for k, v in sorted(citations.items(), key=lambda x: x[1]):
        references += '[%d] https://www.ncbi.nlm.nih.gov/pubmed/%s\n' % (v, k)
    print(references)
Exemple #3
0
 def prune_influence_map_degrade_bind_positive(self, model_stmts):
     """Prune positive edges between X degrading and X forming a
     complex with Y."""
     im = self.get_im()
     edges_to_prune = []
     for r1, r2, data in im.edges(data=True):
         s1 = stmt_from_rule(r1, self.model, model_stmts)
         s2 = stmt_from_rule(r2, self.model, model_stmts)
         # Make sure this is a degradation/binding combo
         s1_is_degrad = (s1 and isinstance(s1, DecreaseAmount))
         s2_is_bind = (s2 and isinstance(s2, Complex) and 'bind' in r2)
         if not s1_is_degrad or not s2_is_bind:
             continue
         # Make sure what is degraded is part of the complex
         if s1.obj.name not in [m.name for m in s2.members]:
             continue
         # Make sure we're dealing with a positive influence
         if data['sign'] == 1:
             edges_to_prune.append((r1, r2))
     logger.info('Removing %d edges from influence map' %
                 len(edges_to_prune))
     im.remove_edges_from(edges_to_prune)
def export_json(results, model, stmts):
    """Export a set of paths in JSON format for visualization."""
    json_dict = {}
    for drug, ab, relation, value, path_found, paths, flag in results:
        if json_dict.get(drug) is None:
            json_dict[drug] = {}
        if json_dict[drug].get(ab) is None:
            json_dict[drug][ab] = {}
        for idx, path in enumerate(paths):
            path_stmts = []
            for rule_name, sign in path[:-1]:
                stmt = stmt_from_rule(rule_name, model, stmts)
                path_stmts.append(stmt.uuid)
            json_dict[drug][ab][idx] = path_stmts
    return json_dict
Exemple #5
0
 def add_namespace_to_influence_map(self, model_stmts):
     """Add a namespace to each node in influence map."""
     im = self.get_im()
     for node, data in im.nodes(data=True):
         ag = None
         # Node is observable
         if node.endswith('obs'):
             ag = agent_from_obs(node, self.model)
         # Node is rule
         else:
             stmt = stmt_from_rule(node, self.model, model_stmts)
             if stmt:
                 agents = [ag for ag in stmt.agent_list() if ag is not None]
                 if agents:
                     ag = agents[0]
         if ag:
             ns_order = default_ns_order + ['PUBCHEM', 'TEXT']
             ns = ag.get_grounding(ns_order)[0]
             data['ns'] = ns
         else:
             logger.warning('Could not get grounding for %s' % node)
Exemple #6
0
    def get_nodes_to_agents(self, model_stmts, add_namespaces=False):
        """Return a dictionary mapping influence map nodes to INDRA agents.

        Parameters
        ----------
        model_stmts : list[indra.statements.Statement]
            A list of INDRA statements used to assemble PySB model.
        add_namespaces : bool
            Whether to propagate namespaces to node data. Default: False.

        Returns
        -------
        nodes_to_agents : dict
            A dictionary mapping influence map nodes to INDRA agents.
        """
        if self.nodes_to_agents:
            return self.nodes_to_agents

        im = self.get_im()
        for node, data in im.nodes(data=True):
            ag = None
            # Node is observable
            if node.endswith('obs'):
                ag = agent_from_obs(node, self.model)
            # Node is rule
            else:
                stmt = stmt_from_rule(node, self.model, model_stmts)
                if stmt:
                    agents = [ag for ag in stmt.agent_list() if ag is not None]
                    if agents:
                        ag = agents[0]
            if ag:
                self.nodes_to_agents[node] = ag
                if add_namespaces:
                    ns_order = default_ns_order + ['PUBCHEM', 'TEXT']
                    ns = ag.get_grounding(ns_order)[0]
                    data['ns'] = ns
            else:
                logger.warning('Could not get agent for %s' % node)
        return self.nodes_to_agents
Exemple #7
0
 def check_explanation(self):
     if self.model is None:
         raise ValueError('check_explanation requires a PySB model.')
     if self.explain is None:
         raise ValueError('check_explanation requires an explanation goal.')
     result = {}
     mc = PysbModelChecker(self.model, [self.explain])
     try:
         pr = mc.check_statement(self.explain, max_paths=0)
         result['has_explanation'] = pr.path_found
     except Exception as e:
         logger.error("Error checking statement for paths: %s" % str(e))
         result['has_explanation'] = False
     # If we found a path get a path
     if result['has_explanation']:
         try:
             pr = mc.check_statement(self.explain,
                                     max_paths=1,
                                     max_path_length=8)
             path_stmts = stmts_from_pysb_path(pr.paths[0], self.model,
                                               self.statements)
             result['explanation_path'] = path_stmts
         except Exception as e:
             logger.error("Error getting paths for statement: %s" % str(e))
     # If we don't already have an explanation, see if we can propose one
     else:
         # Get the source rules associated with the statement to explain
         source_rules = []
         subj_mps = grounded_monomer_patterns(self.model,
                                              self.explain.agent_list()[0])
         for subj_mp in subj_mps:
             source_rules += mc._get_input_rules(subj_mp)
         obs_container = mc.stmt_to_obs[self.explain]
         # If we've got both source rules and observable names, add dummy
         # nodes for the source (connected to all input rules) and the
         # target (connected to all observables) so we only have to deal
         # with a single source and a single target
         if source_rules and obs_container:
             new_edges = [('SOURCE', sr) for sr in source_rules]
             new_edges += [(on, 'TARGET')
                           for on, _ in obs_container.main_nodes]
             im = mc.get_im()
             im.add_edges_from(new_edges)
             # Now, we know that there is no path between SOURCE and TARGET.
             # Instead, we consider connections among all possible pairs
             # of nodes in the graph and count the number of nodes in
             # the path between source and target:
             best_edge = (None, 0)
             for u, v in itertools.permutations(im.nodes(), 2):
                 # Add the edge to the graph
                 im.add_edge(u, v)
                 # Find longest path between source and target
                 simple_paths = list(
                     nx.all_simple_paths(im, 'SOURCE', 'TARGET'))
                 simple_paths.sort(key=lambda p: len(p), reverse=True)
                 if simple_paths and len(simple_paths[0]) > best_edge[1]:
                     best_edge = ((u, v), len(simple_paths[0]))
                 # Now remove the edge we added before going on to the next
                 im.remove_edge(u, v)
             if best_edge[0]:
                 result['connect_rules'] = best_edge[0]
                 u_stmt = stmt_from_rule(best_edge[0][0], self.model,
                                         self.statements)
                 v_stmt = stmt_from_rule(best_edge[0][1], self.model,
                                         self.statements)
                 if u_stmt and v_stmt:
                     result['connect_stmts'] = (u_stmt, v_stmt)
                     logger.info("Model statements: %s" %
                                 str(self.statements))
                     logger.info("To explain %s, try connecting %s and %s" %
                                 (self.explain, u_stmt, v_stmt))
     return result
Exemple #8
0
def pysb_to_gromet(pysb_model, model_name, statements=None, fname=None):
    """Convert PySB model to GroMEt object and save it to a JSON file.

    Parameters
    ----------
    pysb_model : pysb.Model
        PySB model object.
    model_name : str
        A name of EMMAA model.
    statements : Optional[list[indra.statements.Statement]]
        A list of INDRA Statements a PySB model was assembled from. If
        provided the statement hashes will be propagated into GroMEt metadata.
    fname : Optional[str]
        If given, the GroMEt will be dumped into JSON file.

    Returns
    -------
    g : automates.script.gromet.gromet.Gromet
        A GroMEt object built from PySB model.
    """
    from gromet import Gromet, gromet_to_json, \
        Junction, Wire, UidJunction, UidType, UidWire, Relation, \
        UidBox, UidGromet, Literal, Val
    from gromet_metadata import IndraAgent, IndraAgentReferenceSet, \
        ReactionReference, UidMetadatum, MetadatumMethod, Provenance, \
        get_current_datetime, ModelInterface
    from pysb import Parameter, WILD
    from pysb.bng import generate_equations

    logger.info('Generating equations ...')
    generate_equations(pysb_model)

    logger.info('Creating GroMEt')
    junctions = []
    wires = []
    # Get all species values
    species_values = {}
    for initial in pysb_model.initials:
        ix = pysb_model.get_species_index(initial.pattern)
        if initial.value:
            species_values[ix] = Literal(uid=None,
                                         type=UidType("Integer"),
                                         value=Val(initial.value.value),
                                         name=None,
                                         metadata=None)

    # Get groundings for monomers
    groundings_by_monomer = {}
    # Build up db_refs for each monomer object
    for ann in pysb_model.annotations:
        if ann.predicate == 'is':
            m = ann.subject
            db_name, db_id = parse_identifiers_url(ann.object)
            if m in groundings_by_monomer:
                groundings_by_monomer[m][db_name] = db_id
            else:
                groundings_by_monomer[m] = {db_name: db_id}
    # Store species names to refer later
    species_nodes = [str(sp) for sp in pysb_model.species]
    # Add all species junctions
    for ix, sp in enumerate(pysb_model.species):
        # Map to a list of agents
        agents = []
        for mp in sp.monomer_patterns:
            mods = []
            if hasattr(mp.monomer, 'site_annotations'):
                for site, state in mp.site_conditions.items():
                    if isinstance(state, tuple) and state[1] == WILD:
                        state = state[0]
                    mod, mod_type, res, pos = None, None, None, None
                    for ann in mp.monomer.site_annotations:
                        if ann.subject == (site, state):
                            mod_type = ann.object
                        elif ann.subject == site and \
                                ann.predicate == 'is_residue':
                            res = ann.object
                        if ann.subject == site and \
                                ann.predicate == 'is_position':
                            pos = ann.object
                        if mod_type:
                            not_mod, mod = states[mod_type]
                            if state == mod:
                                is_mod = True
                            elif state == not_mod:
                                is_mod = False
                            else:
                                logger.warning('Unknown state %s for %s, '
                                               'setting as not modified' %
                                               (state, mod_type))
                                is_mod = False
                            mod = ModCondition(mod_type, res, pos, is_mod)
                    if mod:
                        mods.append(mod)
            if not mods:
                mods = None
            ag = Agent(mp.monomer.name,
                       mods=mods,
                       db_refs=groundings_by_monomer.get(mp.monomer))
            agents.append(ag)
        agent_metadata = IndraAgentReferenceSet(
            uid=UidMetadatum(f'{species_nodes[ix]}_metadata'),
            provenance=Provenance(method=MetadatumMethod('from_emmaa_model'),
                                  timestamp=get_current_datetime()),
            indra_agent_references=[IndraAgent(ag.to_json()) for ag in agents])
        junctions.append(
            Junction(uid=UidJunction(f'J:{species_nodes[ix]}'),
                     type=UidType('State'),
                     name=species_nodes[ix],
                     value=species_values.get(ix),
                     value_type=UidType('Integer'),
                     metadata=[agent_metadata]))
    # Add wires for each reaction
    rate_counts = defaultdict(int)
    for rxn in pysb_model.reactions:
        rate_params = [
            rate_term for rate_term in rxn['rate'].args
            if isinstance(rate_term, Parameter)
        ]
        assert len(rate_params) == 1
        rate = rate_params[0].name
        rate_counts[rate] += 1
        rate_node = f'{rate}:{rate_counts[rate]}'
        # Get metadata for rate node
        assert len(rxn['rule']) == 1
        assert len(rxn['reverse']) == 1
        rule = rxn['rule'][0]
        reverse = rxn['reverse'][0]
        if statements:
            stmt = stmt_from_rule(rule, pysb_model, statements)
        # Add rate junction for a reaction (uid and name are the same for now)
        reaction_metadata = ReactionReference(
            uid=UidMetadatum(f'{rate_node}_metadata'),
            provenance=Provenance(method=MetadatumMethod('from_emmaa_model'),
                                  timestamp=get_current_datetime()),
            indra_stmt_hash=stmt.get_hash(),
            reaction_rule=rule,
            is_reverse=reverse)
        wire_count = defaultdict(int)
        junctions.append(
            Junction(uid=UidJunction(f'J:{rate_node}'),
                     type=UidType('Rate'),
                     name=rate,
                     value=Literal(uid=None,
                                   type=UidType("Float"),
                                   value=Val(rate_params[0].value),
                                   name=None,
                                   metadata=None),
                     value_type=UidType('Float'),
                     metadata=[reaction_metadata]))
        # Add wires from reactant to rate
        for reactant_ix in rxn['reactants']:
            reactant = species_nodes[reactant_ix]
            wire = f'{reactant}_{rate_node}'
            wire_count[wire] += 1
            wires.append(
                Wire(uid=UidWire(f'W:{wire}:w{wire_count[wire]}'),
                     type=None,
                     value_type=None,
                     name=None,
                     value=None,
                     metadata=None,
                     src=UidJunction(f'J:{reactant}'),
                     tgt=UidJunction(f'J:{rate_node}')))
        # Add wires from rate to product
        for prod_ix in rxn['products']:
            prod = species_nodes[prod_ix]
            wire = f'{rate_node}_{prod}'
            wire_count[wire] += 1
            wires.append(
                Wire(uid=UidWire(f'W:{wire}:w{wire_count[wire]}'),
                     type=None,
                     value_type=None,
                     name=None,
                     value=None,
                     metadata=None,
                     src=UidJunction(f'J:{rate_node}'),
                     tgt=UidJunction(f'J:{prod}')))
    # Create relation
    pnc = Relation(
        uid=UidBox(model_name),
        type=UidType("PetriNetClassic"),
        name=model_name,
        ports=None,
        # contents
        junctions=[j.uid for j in junctions],
        wires=[w.uid for w in wires],
        boxes=None,
        metadata=None)
    boxes = [pnc]

    # Create model interface metadata
    model_interface = \
        ModelInterface(
            uid=UidMetadatum(f'{model_name}_model_interface'),
            provenance=Provenance(method=MetadatumMethod('from_emmaa_model'),
                                  timestamp=get_current_datetime()),
            variables=[j.uid for j in junctions],
            parameters=[j.uid for j in junctions if j.type == 'Rate'],
            initial_conditions=[j.uid for j in junctions if j.type == 'State'])
    # Create Gromet object
    g = Gromet(uid=UidGromet(f'{model_name}_pnc'),
               name=model_name,
               type=UidType("PetriNetClassic"),
               root=pnc.uid,
               types=None,
               literals=None,
               junctions=junctions,
               ports=None,
               wires=wires,
               boxes=boxes,
               variables=None,
               metadata=[model_interface])
    logger.info('Created GroMEt')
    # Optionally save Gromet to JSON file
    if fname:
        gromet_to_json(g, fname)
    return g