Giter Club home page Giter Club logo

pybel-tools's Introduction

PyBEL zenodo Build Status Development Coverage Status Development Documentation Status Powered by the Bioregistry Code style: black

PyBEL is a pure Python package for parsing and handling biological networks encoded in the Biological Expression Language (BEL).

It facilitates data interchange between data formats like NetworkX, Node-Link JSON, JGIF, CSV, SIF, Cytoscape, CX, INDRA, and GraphDati; database systems like SQL and Neo4J; and web services like NDEx, BioDati Studio, and BEL Commons. It also provides exports for analytical tools like HiPathia, Drug2ways and SPIA; machine learning tools like PyKEEN and OpenBioLink; and others.

Its companion package, PyBEL Tools, contains a suite of functions and pipelines for analyzing the resulting biological networks.

We realize that we have a name conflict with the python wrapper for the cheminformatics package, OpenBabel. If you're looking for their python wrapper, see here.

Citation

If you find PyBEL useful for your work, please consider citing:

[1]Hoyt, C. T., et al. (2017). PyBEL: a Computational Framework for Biological Expression Language. Bioinformatics, 34(December), 1โ€“2.

Installation Current version on PyPI Stable Supported Python Versions MIT License

PyBEL can be installed easily from PyPI with the following code in your favorite shell:

$ pip install pybel

or from the latest code on GitHub with:

$ pip install git+https://github.com/pybel/pybel.git

See the installation documentation for more advanced instructions. Also, check the change log at CHANGELOG.rst.

Getting Started

More examples can be found in the documentation and in the PyBEL Notebooks repository.

Compiling and Saving a BEL Graph

This example illustrates how the a BEL document from the Human Brain Pharmacome project can be loaded and compiled directly from GitHub.

>>> import pybel
>>> url = 'https://raw.githubusercontent.com/pharmacome/conib/master/hbp_knowledge/proteostasis/kim2013.bel'
>>> graph = pybel.from_bel_script_url(url)

Other functions for loading BEL content from many formats can be found in the I/O documentation. Note that PyBEL can handle BEL 1.0 and BEL 2.0+ simultaneously.

After you have a BEL graph, there are numerous ways to save it. The pybel.dump function knows how to output it in many formats based on the file extension you give. For all of the possibilities, check the I/O documentation.

>>> import pybel
>>> graph = ...
>>> # write as BEL
>>> pybel.dump(graph, 'my_graph.bel')
>>> # write as Node-Link JSON for network viewers like D3
>>> pybel.dump(graph, 'my_graph.bel.nodelink.json')
>>> # write as GraphDati JSON for BioDati
>>> pybel.dump(graph, 'my_graph.bel.graphdati.json')
>>> # write as CX JSON for NDEx
>>> pybel.dump(graph, 'my_graph.bel.cx.json')
>>> # write as INDRA JSON for INDRA
>>> pybel.dump(graph, 'my_graph.indra.json')

Summarizing the Contents of the Graph

The BELGraph object has several "dispatches" which are properties that organize its various functionalities. One is the BELGraph.summarize dispatch, which allows for printing summaries to the console.

These examples will use the RAS Model from EMMAA, so you'll have to be sure to pip install indra first. The graph can be acquired and summarized with BELGraph.summarize.statistics() as in:

>>> import pybel
>>> graph = pybel.from_emmaa('rasmodel', date='2020-05-29-17-31-58')  # Needs
>>> graph.summarize.statistics()
---------------------  -------------------
Name                   rasmodel
Version                2020-05-29-17-31-58
Number of Nodes        126
Number of Namespaces   5
Number of Edges        206
Number of Annotations  4
Number of Citations    1
Number of Authors      0
Network Density        1.31E-02
Number of Components   1
Number of Warnings     0
---------------------  -------------------

The number of nodes of each type can be summarized with BELGraph.summarize.nodes() as in:

>>> graph.summarize.nodes(examples=False)
Type (3)        Count
------------  -------
Protein            97
Complex            27
Abundance           2

The number of nodes with each namespace can be summarized with BELGraph.summarize.namespaces() as in:

>>> graph.summarize.namespaces(examples=False)
Namespace (4)      Count
---------------  -------
HGNC                  94
FPLX                   3
CHEBI                  1
TEXT                   1

The edges can be summarized with BELGraph.summarize.edges() as in:

>>> graph.summarize.edges(examples=False)
Edge Type (12)                       Count
---------------------------------  -------
Protein increases Protein               64
Protein hasVariant Protein              48
Protein partOf Complex                  47
Complex increases Protein               20
Protein decreases Protein                9
Complex directlyIncreases Protein        8
Protein increases Complex                3
Abundance partOf Complex                 3
Protein increases Abundance              1
Complex partOf Complex                   1
Protein decreases Abundance              1
Abundance decreases Protein              1

Grounding the Graph

Not all BEL graphs contain both the name and identifier for each entity. Some even use non-standard prefixes (also called namespaces in BEL). Usually, BEL graphs are validated against controlled vocabularies, so the following demo shows how to add the corresponding identifiers to all nodes.

from urllib.request import urlretrieve

url = 'https://github.com/cthoyt/selventa-knowledge/blob/master/selventa_knowledge/large_corpus.bel.nodelink.json.gz'
urlretrieve(url, 'large_corpus.bel.nodelink.json.gz')

import pybel
graph = pybel.load('large_corpus.bel.nodelink.json.gz')

import pybel.grounding
grounded_graph = pybel.grounding.ground(graph)

Note: you have to install pyobo for this to work and be running Python 3.7+.

Displaying a BEL Graph in Jupyter

After installing jinja2 and ipython, BEL graphs can be displayed in Jupyter notebooks.

>>> from pybel.examples import sialic_acid_graph
>>> from pybel.io.jupyter import to_jupyter
>>> to_jupyter(sialic_acid_graph)

Using the Parser

If you don't want to use the pybel.BELGraph data structure and just want to turn BEL statements into JSON for your own purposes, you can directly use the pybel.parse() function.

>>> import pybel
>>> pybel.parse('p(hgnc:4617 ! GSK3B) regulates p(hgnc:6893 ! MAPT)')
{'source': {'function': 'Protein', 'concept': {'namespace': 'hgnc', 'identifier': '4617', 'name': 'GSK3B'}}, 'relation': 'regulates', 'target': {'function': 'Protein', 'concept': {'namespace': 'hgnc', 'identifier': '6893', 'name': 'MAPT'}}}

This functionality can also be exposed through a Flask-based web application with python -m pybel.apps.parser after installing flask with pip install flask. Note that the first run requires about a ~2 second delay to generate the parser, after which each parse is very fast.

Using the CLI

PyBEL also installs a command line interface with the command pybel for simple utilities such as data conversion. In this example, a BEL document is compiled then exported to GraphML for viewing in Cytoscape.

$ pybel compile ~/Desktop/example.bel
$ pybel serialize ~/Desktop/example.bel --graphml ~/Desktop/example.graphml

In Cytoscape, open with Import > Network > From File.

Contributing

Contributions, whether filing an issue, making a pull request, or forking, are appreciated. See CONTRIBUTING.rst for more information on getting involved.

Acknowledgements

Support

The development of PyBEL has been supported by several projects/organizations (in alphabetical order):

Funding

Logo

The PyBEL logo was designed by Scott Colby.

pybel-tools's People

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pybel-tools's Issues

Allowed function in OWL Ontology

Waiting on Reagon for a standard format for adding allowed function usage for each term in an ontology. Have the parser pick these out and add to the [Values] section of the BEL namespace

Induce subgraph around single node

For Reagon's NPA variant, all of the upstream controllers of a given node are grabbed, then possibly recurring on their upstream controllers as well

Collapse based on orthology

Make a function that collapses nodes based on their orthology connections

def collapse_by_orthology(graph, priority_list=None):
   """Collapses a graph based on the orthology between nodes"""
   priority_list = ['HGNC', 'MGI', 'RGD'] if priority_list is none else priority_list
   ...

Citation processing

Acquisition

  1. Get all PubMed ID's in a graph
  2. Look up the information for the given PMID. Store in a dictionary so multiple lookup isn't necessary
  3. Stick in the network

Storage

  • Export data to pybel.manager.models.Citation table for long term storage
  • Provide inverse functions to relationalize/unrelationalize the citations in a BEL Graph

Summary

  • Get all authors across all the citations in a given BEL Graph
  • Get all authors, grouped by a given annotation (usually subgraph) in a given BEL Graph

See: pybel/pybel#60

Again, from aetionomy.pybel2 line 62:

def get_pubmedInfos_by_pmidList(self,pmids):
    """
    fetch from NCBI all publication information.
    @param pmids: PMID identifiers
    @type pmids: list
    @type pmids; tuple
    @return: dict with PMID as key and value => dict with keys: authors,title,pubdate,lastauthor,journal,volume,issue,pages,firstauthor,pmcId
    """
    pmids=list(set(list(pmids)))
    resultDict={}
    n = 200
    url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=%s&retmode=json"
    for pmidList in [','.join(pmids[i:i+n]) for i in xrange(0, len(pmids), n)]:
        pmidsJson = json.loads(urllib2.urlopen(url % pmidList).read())
        for pmid in pmidsJson['result']['uids']:
            p=pmidsJson['result'][pmid]
            if 'error' not in p:
                authors = ', '.join([x['name'] for x in p['authors']]) if 'authors' in p else None 
                pubdate = None
                if re.search('^[12][0-9]{3} [a-zA-Z]{3} \d{1,2}$',p['pubdate']):
                    pubdate = datetime.datetime.strptime(p['pubdate'], '%Y %b %d').strftime('%Y-%m-%d')
                elif re.search('^[12][0-9]{3} [a-zA-Z]{3}$',p['pubdate']):
                    pubdate = datetime.datetime.strptime(p['pubdate'], '%Y %b').strftime('%Y-%m-01')
                elif re.search('^[12][0-9]{3}$',p['pubdate']):
                    pubdate = p['pubdate']+"-01-01"
                elif re.search('^[12][0-9]{3} [a-zA-Z]{3}-[a-zA-Z]{3}$',p['pubdate']):
                    pubdate = datetime.datetime.strptime(p['pubdate'][:-4], '%Y %b').strftime('%Y-%m-01')
                else:
                    print pubdate
                pmcIds = [x['value'] for x in p['articleids'] if x['idtype']=='pmc']
                pmcId = pmcIds[0] if pmcIds else None  
                resultDict[pmid]={
                    'authors':authors,
                    'title':p['title'],
                    'pubdate':pubdate,
                    'lastauthor':p['lastauthor'],
                    'journal':p['fulljournalname'],
                    'volume':p['volume'],
                    'issue':p['issue'],
                    'pages':p['pages'],
                    'firstauthor':p['sortfirstauthor'],
                    'pmcId':pmcId}
            else:
                print "probelms with following id:%s\nhttp://www.ncbi.nlm.nih.gov/pubmed/%s" % (pmid,pmid)
        time.sleep(1)
    return resultDict

see also: pybel_tools.boilerplate line 154 for grabbing information about abstracts

Merge DatabaseService with CacheManager

Since the functions in the database service are just simple wrappers around queries in the graph cache manager, would it make sense to just stick them in it? Or should we keep the cache manager just for functions of filling up and retrieving the cache, while query systems can wrap it and just use its connection?

Merge all node variants by value

Make a function that merge all node variants to its original protein/gene so we can infer all the neighborhood around that original node.

Validation checks for nodes and edges

Validate if:

  1. enzyme activity is described by the IUBMB EC classification system (http://www.chem.qmul.ac.uk/iubmb/)
  2. a dbSNP RS identifier is correctly linked to a gene
  3. substrates and products in a (bio-)chemical reaction are correct
    Please write comments if you have more suggestions

This issue has been migrated from pybel/pybel#65

From Reagon:

Find the statements that don't have a disease state (normal, AD, etc) to get flagged.

This could either be done on compile time, or the line number for each statement could be included in the graph.

This has been migrated from pybel/pybel#17.

Download orthology data

Build a simple function that download all orthology data from HGNC's dump:

def download_orthology_dict():
   """Downloads orthology data from HGNC's data service

   :rtype: dict
   """
   pass

Filters for subgraph overlap

Chemicals shouldn't be counted, neither should pathologies, or pathologies

Maybe just pick genes after collapsing to genes?

Download and merge orthology data

def integrate_orthology(graph, orthology_dict=None):
   """Integrates the information from the HGNC orthology data dump. 
  
   :param graph: A BEL Graph
   :type graph: BELGraph
   :param orthology_dict: A dictionary of parsed orthology data from HGNC's data service If :code:`None`, downloads and parses the data. 
   :type orthology_dict: dict
   """
   pass

Left Network Merge

Make an asymmetric network merge merge(A, B) where the data from network A's nodes take preference over the data from network B

Use case:
Build network to represent Gene - SNP connections, but don't add any node dicts. I just want to add the edges, but not mess with the nodes in another graph.

Better MVC for /explorer/ endpoint

We need to be able to give GET parameters to the /explorer/ endpoint and have those passed along to the ajax calls update the network. The ajax calls can conversely update the window's path to match any changes made without needing a hard reload.

Alternatively, the entire app could be model/view controller, like @cebel wanted in the first place.

With this all in place, it becomes trivial to implement the subgraph seeding

Filter by annotation value

It would be great if the next step in the visualization system is to have a way to filter by annotations.

The obvious use case would be to filter by a specific subgraph, defined in the AD and PD assemblies.

Additionally, it might be nice to have a keyword argument to pre-specify which annotation to filter by, so the whole graph can be loaded in javascript, but only a specific slice would be shown initially

Component Connection Algorithm

For any two subgraphs and their parent graph, find the shortest path between the components. Do this with directed paths, and undirected path transformations.

Overlay tabular data on nodes

Code skeleton:

def overlay_data(graph, data, label):
    """
    :type graph: :class:`pybel.BELGraph`
    :param data: a dictionary of {pybel node: data for that node}
    :type data: dict
    :param label:
    :type label: str
    """
    pass

Use Cases:

  • I have differential gene expression data that I want to add as an attribute to all of my RNA nodes so I can do RCR or NPA later.
  • I have a list of functional consequences for all of my SNPs and want to include this information in my network

Complete origin on miRNA

Most miRNA can be written with g(HGNC:YFG) transcribedTo m(HGNC:YFG) so the inference of the central dogma should also make these edges.

I'm also curious about miRNA's themselves, since there's a differentiation between a "premature" and a "mature" sequence. Does the premature sequence count as an RNA and not an miRNA?

Thoughts @cebel, @dexterpratt?

Merge database API endpoints using params

Some endpoints have optional arguments, like offsets. Rather than having a more confusing API with many more routes, make these request parameters and switch on their existence using flask.request.args

Completion of origin

Need external functions that allow for inference of translation and transcription

Define colors for non common BEL functions (e.g., reactant...)

.Pathology {
fill: #FF7F0E;
}

.Abundance {
fill: #AEC7E8;
}

.Gene {
fill: #FFBB78;
}

.miRNA {
fill: #D62728;
}

.Protein {
fill: #1F77B4;
}

.RNA {
fill: #FF9896;
}

.BiologicalProcess {
fill: #2CA02C;
}

.Pathology {
fill: #FF7F0E;
}

.Complex {
fill: #98DF8A;
}

.Composite {
fill: #9467BD;
}

// ADD MORE HERE

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.