logo Netzschleuder network catalog, repository, and centrifuge

History of hetionet

The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.

[entries] New entry: hetionet by Tiago de Paula Peixoto fc0a9f3
diff --git a/entries/hetionet/__init__.py b/entries/hetionet/__init__.py
new file mode 100644
index 0000000..3e29a64
--- /dev/null
+++ b/entries/hetionet/__init__.py
@@ -0,0 +1,136 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+from .. import *
+import bz2
+
+
+title = "Hetionet biomedical knowledge graph (v1.0, 2017)"
+description = """Hetionet is a heterogeneous network ("hetnet") of biomedical knowledge, built by Himmelstein et al. for Project Rephetio, which predicted new uses of existing drugs. It integrates data from 29 public resources (e.g. Entrez Gene, Gene Ontology, DrugBank, SIDER, Disease Ontology, Uberon, Reactome, WikiPathways, LINCS L1000, Bgee, MEDLINE topic co-occurrence), and contains nodes of 11 kinds: genes (20,945), biological processes (11,381), side effects (5,734), molecular functions (2,884), pathways (1,822), compounds (1,552, approved small-molecule drugs), cellular components (1,391), symptoms (438), anatomical structures (402), pharmacologic classes (345) and diseases (137). This is version 1.0 of the network.
+
+The edges are of 24 kinds (metaedges), each a relation between nodes of two given kinds, e.g. a compound *treats* a disease, a gene *participates* in a pathway, an anatomical structure *expresses* a gene, or a gene *regulates* another gene. A directed edge from node $i$ to node $j$ means that $i$ has the relation to $j$ (the source and target nodes of the data); only the relation *regulates* (between genes) is directional, while the others are symmetric relations, stated in the order of the kinds of their nodes. Pairs of nodes may be connected by several edges of different kinds.
+
+Some edges are "unbiased", i.e. come from systematic, genome-wide data (e.g. high-throughput experiments), rather than from the literature, which is biased towards well-studied genes. The original content of Hetionet is released into the public domain (CC0), but the integrated resources have their own licenses, recorded for each node and edge where known; some of them restrict the use of their data, e.g. to noncommercial purposes (CC BY-NC 4.0 for DrugBank, CC BY-NC-SA 4.0 for SIDER), and for some resources without a license, the authors obtained permission to include their data.
+
+The network has the following properties:
+
+- `kind`: the kind of the node (`Gene`, `Compound`, `Disease`, ...).
+- `identifier`: the identifier of the node in its source resource (e.g. the Entrez Gene id of a gene, the DrugBank id of a compound, the Disease Ontology id of a disease).
+- `name`: the name of the node.
+- `source`: the resource of the node.
+- `license`: the license of the node's data.
+- `url`: a web page of the node in its source resource (empty if absent).
+- `description` and `chromosome`: the description of a gene, and the chromosome where it is located (empty for other nodes).
+- `inchikey` and `inchi`: the InChIKey and InChI chemical identifiers of a compound (empty for other nodes).
+- `mesh_id` and `bto_id`: the Medical Subject Headings and BRENDA Tissue Ontology identifiers of an anatomical structure (empty for other nodes or if absent).
+- `class_type`: the type of a pharmacologic class (empty for other nodes).
+- Edge `kind`: the relation (`treats`, `participates`, `regulates`, ...); together with the kinds of its nodes, it gives the kind of the edge (metaedge).
+- Edge `sources`: the resources that the edge comes from.
+- Edge `license`: the license of the edge's data (empty if not given).
+- Edge `unbiased`: whether the edge comes from systematic, unbiased data.
+- Edge `urls`: web pages of the evidence for the edge (empty if absent).
+- Edge `pubmed_ids`: the PubMed identifiers of the publications supporting a compound-gene binding (empty if absent).
+- Edge `actions`: the actions of a compound on the gene it binds (e.g. `inhibitor`, `agonist`; empty if absent).
+- Edge `affinity_nm`: the binding affinity of a compound and a gene, in nanomolar (NaN if absent).
+- Edge `similarity`: the chemical similarity (Dice coefficient of extended connectivity fingerprints) of two compounds that resemble each other (NaN for other edges).
+- Edge `z_score`: the consensus z-score of the up- or downregulation of a gene by a compound in LINCS L1000 (NaN for other edges).
+- Edge `log2_fold_change`: the log2 fold change of the up- or downregulation of a gene by a disease (NaN for other edges).
+- Edge `method`: the LINCS L1000 method for the regulation of genes (`measured` or `imputed`; empty for other edges).
+- Edge `subtypes`: the kinds of perturbation of a gene that regulate another (e.g. `knockdown downregulates`; empty for other edges)."""
+tags = ['Biological', 'Protein interactions', 'Gene regulation', 'Drug interactions', 'Unweighted', 'Multigraph', 'Metadata']
+url = ['https://het.io', 'https://github.com/hetio/hetionet']
+citation = [('D. S. Himmelstein, A. Lizee, C. Hessler, L. Brueggeman, S. L. Chen, D. Hadley, A. Green, P. Khankhanian, S. E. Baranzini, "Systematic integration of biomedical knowledge prioritizes drugs for repurposing." eLife 6, e26726 (2017)', 'https://doi.org/10.7554/eLife.26726')]
+icon_hash = None
+upstream_license = ('CC0 1.0 (the integrated resources have their own licenses)', 'https://github.com/dhimmel/integrate/blob/d482033bcaa913a976faf4a6ee08497281c739c3/licenses/README.md')
+# The file is stored with Git LFS, served from media.githubusercontent.com
+upstream_prefix = 'https://media.githubusercontent.com/media/hetio/hetionet/8a6cc0c5604d0e2908786e4de38af67b8e46ee4a'
+files = [('hetnet/json/hetionet-v1.0.json.bz2', None, None)]
+
+def fetch_upstream(force=False):
+    return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+                                force)
+
+vprops = ["source", "license", "url", "description", "chromosome", "inchikey",
+          "inchi", "mesh_id", "bto_id", "class_type"]
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+    global files
+    name = __name__.split(".")[-1]
+    for fnames, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        with open_upstream_file(name, fnames, "rb") as f:
+            with bz2.open(f, "rt") as bf:
+                data = json.load(bf)
+
+        nodes = data["nodes"]
+        g = Graph(directed=True)
+        g.add_vertex(len(nodes))
+        idx = {(n["kind"], n["identifier"]): v for v, n in enumerate(nodes)}
+        assert len(idx) == len(nodes)
+        g.vp.kind = g.new_vp("string", vals=[n["kind"] for n in nodes])
+        g.vp.identifier = g.new_vp("string", vals=[str(n["identifier"]) for n in nodes])
+        g.vp.name = g.new_vp("string", vals=[n["name"] for n in nodes])
+        for k in vprops:
+            g.vp[k] = g.new_vp("string", vals=[n["data"].get(k, "") for n in nodes])
+        assert all(set(n["data"]) <= set(vprops) for n in nodes)
+        del nodes
+
+        edges = data.pop("edges")
+        del data
+        g.add_edge_list([(idx[tuple(e["source_id"])], idx[tuple(e["target_id"])])
+                         for e in edges])
+        assert all(e["direction"] == ("forward" if e["kind"] == "regulates" else "both")
+                   for e in edges)
+        nan = numpy.nan
+        g.ep.kind = g.new_ep("string", vals=[e["kind"] for e in edges])
+        g.ep.sources = g.new_ep("vector<string>")
+        g.ep.license = g.new_ep("string", vals=[e["data"].get("license", "") for e in edges])
+        g.ep.unbiased = g.new_ep("bool", vals=[e["data"]["unbiased"] for e in edges])
+        g.ep.urls = g.new_ep("vector<string>")
+        g.ep.pubmed_ids = g.new_ep("vector<int64_t>")
+        g.ep.actions = g.new_ep("vector<string>")
+        for k, uk in [("affinity_nM", "affinity_nm"), ("similarity", "similarity"),
+                      ("z_score", "z_score"), ("log2_fold_change", "log2_fold_change")]:
+            g.ep[uk] = g.new_ep("double", vals=[e["data"].get(k, nan) for e in edges])
+        g.ep.method = g.new_ep("string", vals=[e["data"].get("method", "") for e in edges])
+        g.ep.subtypes = g.new_ep("vector<string>")
+        known = {"source", "sources", "license", "unbiased", "url", "urls",
+                 "pubmed_ids", "actions", "affinity_nM", "similarity", "z_score",
+                 "log2_fold_change", "method", "subtypes"}
+        # The edges were added in the order of the data, so that their
+        # indices are the positions in the list
+        for ge in g.edges():
+            d = edges[g.edge_index[ge]]["data"]
+            assert set(d) <= known, d
+            g.ep.sources[ge] = d["sources"] if "sources" in d else [d["source"]]
+            if "url" in d:
+                g.ep.urls[ge] = [d["url"]]
+            elif "urls" in d:
+                g.ep.urls[ge] = d["urls"]
+            if "pubmed_ids" in d:
+                g.ep.pubmed_ids[ge] = [int(x) for x in d["pubmed_ids"]]
+            if "actions" in d:
+                g.ep.actions[ge] = d["actions"]
+            if "subtypes" in d:
+                g.ep.subtypes[ge] = d["subtypes"]
+        yield alt, g