History of chembl_bioactivity
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] Add the date when each entry was added, and remove icon_hash beff7c9
The dates are those of the commits that first added the entries' files (2020-08-11 for the entries of the initial commit); renamed entries keep the date of their first name. Changed: none
diff --git a/entries/chembl_bioactivity/__init__.py b/entries/chembl_bioactivity/__init__.py
index 1cce03b..a5942de 100644
--- a/entries/chembl_bioactivity/__init__.py
+++ b/entries/chembl_bioactivity/__init__.py
@@ -51,7 +51,7 @@ citation = [('B. Zdrazil et al., "The ChEMBL Database in 2023: a drug discovery
'https://doi.org/10.1093/nar/gkad1004'),
('D. Mendez et al., "ChEMBL: towards direct deposition of bioassay data." Nucleic Acids Research 47, D930-D940 (2019)',
'https://doi.org/10.1093/nar/gky1075')]
-icon_hash = None
+date_added = '2026-10-28'
# ChEMBL asks that the release be displayed: "ChEMBL data is from
# http://www.ebi.ac.uk/chembl - the version of ChEMBL is chembl_37"
upstream_license = ("CC BY-SA 3.0 (ChEMBL data is from http://www.ebi.ac.uk/chembl; the version of ChEMBL is chembl_37)",
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) bc3dbbd
The lists of properties at the end of the descriptions marked edge properties with "Edge" but left node properties unmarked, or grouped them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property was often unclear. Every item now starts with (Node), (Edge) or (Graph), followed by the property names, a colon and the explanation, one item per property or group of properties; qualifications (kinds of nodes, networks) follow the names in parentheses. Properties that were only named got a short explanation, and a few items that named the wrong kind of property were corrected.
diff --git a/entries/chembl_bioactivity/__init__.py b/entries/chembl_bioactivity/__init__.py
index c87b8d2..1cce03b 100644
--- a/entries/chembl_bioactivity/__init__.py
+++ b/entries/chembl_bioactivity/__init__.py
@@ -27,23 +27,23 @@ The targets are mostly single proteins, but also protein complexes and families,
The network has the following properties:
-- `is_compound`: whether the node is a compound (otherwise it is a target).
-- `chembl_id`: the ChEMBL identifier of the compound or target (e.g. `CHEMBL25`, aspirin; `CHEMBL203`, the epidermal growth factor receptor), whose page is `https://www.ebi.ac.uk/chembl/explore/compound/<chembl_id>` or `https://www.ebi.ac.uk/chembl/explore/target/<chembl_id>`.
-- `name`: the preferred name of the compound or target (empty for most compounds, which have no name).
-- `molecule_type` (compounds): the type of the compound, e.g. `Small molecule`, `Protein`, `Antibody` (empty for targets).
-- `max_phase` (compounds): the maximum clinical phase reached by the compound: 4 (approved drug), 3, 2, 1, 0.5 (early phase 1), or -1 (preclinical or unknown, also for targets).
-- `target_type` (targets): the type of the target, e.g. `SINGLE PROTEIN`, `PROTEIN COMPLEX`, `CELL-LINE`, `ORGANISM` (empty for compounds).
-- `organism` (targets): the organism of the target (empty if none, and for compounds).
-- `tax_id` (targets): the NCBI taxonomy identifier of the organism (-1 if none, and for compounds).
-- Edge `standard_type`: the type of the measurement, standardized, e.g. `IC50`, `Ki`, `Potency`, `Inhibition`.
-- Edge `standard_relation`: the relation of the measured value: `=`, `<`, `>`, `<=`, `>=`, `~` (empty if there is no value).
-- Edge `standard_value`: the measured value, standardized (NaN if there is none).
-- Edge `standard_units`: the units of the value, e.g. `nM`, `%` (empty if none).
-- Edge `pchembl_value`: the negative logarithm (base 10) of the molar concentration (e.g. IC50, Ki, EC50), for comparable measures of potency (NaN if not applicable).
-- Edge `assay_type`: the type of the assay: `B` (binding), `F` (functional), `A` (absorption, distribution, metabolism and excretion), `T` (toxicity), `P` (physicochemical) or `U` (unclassified).
-- Edge `year`: the year of publication of the document the measurement comes from (-1 if not known, e.g. for deposited datasets).
-- Edge `data_validity_comment`: a comment on the validity of the measurement, e.g. `Outside typical range`, `Potential transcription error` (empty if none).
-- Edge `potential_duplicate`: whether the measurement is a possible duplicate of one reported in another document."""
+- (Node) `is_compound`: whether the node is a compound (otherwise it is a target).
+- (Node) `chembl_id`: the ChEMBL identifier of the compound or target (e.g. `CHEMBL25`, aspirin; `CHEMBL203`, the epidermal growth factor receptor), whose page is `https://www.ebi.ac.uk/chembl/explore/compound/<chembl_id>` or `https://www.ebi.ac.uk/chembl/explore/target/<chembl_id>`.
+- (Node) `name`: the preferred name of the compound or target (empty for most compounds, which have no name).
+- (Node) `molecule_type` (compounds): the type of the compound, e.g. `Small molecule`, `Protein`, `Antibody` (empty for targets).
+- (Node) `max_phase` (compounds): the maximum clinical phase reached by the compound: 4 (approved drug), 3, 2, 1, 0.5 (early phase 1), or -1 (preclinical or unknown, also for targets).
+- (Node) `target_type` (targets): the type of the target, e.g. `SINGLE PROTEIN`, `PROTEIN COMPLEX`, `CELL-LINE`, `ORGANISM` (empty for compounds).
+- (Node) `organism` (targets): the organism of the target (empty if none, and for compounds).
+- (Node) `tax_id` (targets): the NCBI taxonomy identifier of the organism (-1 if none, and for compounds).
+- (Edge) `standard_type`: the type of the measurement, standardized, e.g. `IC50`, `Ki`, `Potency`, `Inhibition`.
+- (Edge) `standard_relation`: the relation of the measured value: `=`, `<`, `>`, `<=`, `>=`, `~` (empty if there is no value).
+- (Edge) `standard_value`: the measured value, standardized (NaN if there is none).
+- (Edge) `standard_units`: the units of the value, e.g. `nM`, `%` (empty if none).
+- (Edge) `pchembl_value`: the negative logarithm (base 10) of the molar concentration (e.g. IC50, Ki, EC50), for comparable measures of potency (NaN if not applicable).
+- (Edge) `assay_type`: the type of the assay: `B` (binding), `F` (functional), `A` (absorption, distribution, metabolism and excretion), `T` (toxicity), `P` (physicochemical) or `U` (unclassified).
+- (Edge) `year`: the year of publication of the document the measurement comes from (-1 if not known, e.g. for deposited datasets).
+- (Edge) `data_validity_comment`: a comment on the validity of the measurement, e.g. `Outside typical range`, `Potential transcription error` (empty if none).
+- (Edge) `potential_duplicate`: whether the measurement is a possible duplicate of one reported in another document."""
tags = ['Biological', 'Chemical', 'Drug interactions', 'Weighted', 'Multigraph', 'Metadata']
url = ['https://www.ebi.ac.uk/chembl/',
'https://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/releases/chembl_37/']
[entries] New entry: chembl_bioactivity 0568538
diff --git a/entries/chembl_bioactivity/__init__.py b/entries/chembl_bioactivity/__init__.py
new file mode 100644
index 0000000..c87b8d2
--- /dev/null
+++ b/entries/chembl_bioactivity/__init__.py
@@ -0,0 +1,193 @@
+#! /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/>.
+
+import sqlite3
+
+from .. import *
+
+title = "ChEMBL compound-target bioactivities (2026)"
+description = r"""A bipartite network of the compounds and the biological targets of ChEMBL, the manually curated database of bioactive molecules with drug-like properties of the European Bioinformatics Institute (EMBL-EBI), release 37 (May 2026). An edge is a bioactivity measurement of a compound in an assay on a target, e.g. an inhibition constant ($K_i$) or a half-maximal inhibitory concentration (IC50), so that a compound and a target are connected by as many edges as there are measurements. The measurements are mostly extracted from the scientific literature (medicinal chemistry journals), and also come from deposited datasets (e.g. PubChem BioAssays, patents via BindingDB and SureChEMBL, screening campaigns against malaria and other neglected diseases).
+
+The targets are mostly single proteins, but also protein complexes and families, nucleic acids, cell lines, tissues and whole organisms, as given by the node property `target_type`; the compounds are mostly small molecules, but also e.g. antibodies and other proteins. All the 24.5 million activities of the release are included, also those with a comment about their validity (e.g. a possible transcription error, or units that are outside the typical range for that activity type) and those flagged as possible duplicates, as well as activities without a numerical value (e.g. those only reported as active or inactive). The assays and documents of the activities (other than the year of publication), their original (unstandardized) values, and the structures of the compounds are not included.
+
+The network has the following properties:
+
+- `is_compound`: whether the node is a compound (otherwise it is a target).
+- `chembl_id`: the ChEMBL identifier of the compound or target (e.g. `CHEMBL25`, aspirin; `CHEMBL203`, the epidermal growth factor receptor), whose page is `https://www.ebi.ac.uk/chembl/explore/compound/<chembl_id>` or `https://www.ebi.ac.uk/chembl/explore/target/<chembl_id>`.
+- `name`: the preferred name of the compound or target (empty for most compounds, which have no name).
+- `molecule_type` (compounds): the type of the compound, e.g. `Small molecule`, `Protein`, `Antibody` (empty for targets).
+- `max_phase` (compounds): the maximum clinical phase reached by the compound: 4 (approved drug), 3, 2, 1, 0.5 (early phase 1), or -1 (preclinical or unknown, also for targets).
+- `target_type` (targets): the type of the target, e.g. `SINGLE PROTEIN`, `PROTEIN COMPLEX`, `CELL-LINE`, `ORGANISM` (empty for compounds).
+- `organism` (targets): the organism of the target (empty if none, and for compounds).
+- `tax_id` (targets): the NCBI taxonomy identifier of the organism (-1 if none, and for compounds).
+- Edge `standard_type`: the type of the measurement, standardized, e.g. `IC50`, `Ki`, `Potency`, `Inhibition`.
+- Edge `standard_relation`: the relation of the measured value: `=`, `<`, `>`, `<=`, `>=`, `~` (empty if there is no value).
+- Edge `standard_value`: the measured value, standardized (NaN if there is none).
+- Edge `standard_units`: the units of the value, e.g. `nM`, `%` (empty if none).
+- Edge `pchembl_value`: the negative logarithm (base 10) of the molar concentration (e.g. IC50, Ki, EC50), for comparable measures of potency (NaN if not applicable).
+- Edge `assay_type`: the type of the assay: `B` (binding), `F` (functional), `A` (absorption, distribution, metabolism and excretion), `T` (toxicity), `P` (physicochemical) or `U` (unclassified).
+- Edge `year`: the year of publication of the document the measurement comes from (-1 if not known, e.g. for deposited datasets).
+- Edge `data_validity_comment`: a comment on the validity of the measurement, e.g. `Outside typical range`, `Potential transcription error` (empty if none).
+- Edge `potential_duplicate`: whether the measurement is a possible duplicate of one reported in another document."""
+tags = ['Biological', 'Chemical', 'Drug interactions', 'Weighted', 'Multigraph', 'Metadata']
+url = ['https://www.ebi.ac.uk/chembl/',
+ 'https://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/releases/chembl_37/']
+citation = [('B. Zdrazil et al., "The ChEMBL Database in 2023: a drug discovery platform spanning multiple bioactivity data types and time periods." Nucleic Acids Research 52, D1180-D1192 (2024)',
+ 'https://doi.org/10.1093/nar/gkad1004'),
+ ('D. Mendez et al., "ChEMBL: towards direct deposition of bioassay data." Nucleic Acids Research 47, D930-D940 (2019)',
+ 'https://doi.org/10.1093/nar/gky1075')]
+icon_hash = None
+# ChEMBL asks that the release be displayed: "ChEMBL data is from
+# http://www.ebi.ac.uk/chembl - the version of ChEMBL is chembl_37"
+upstream_license = ("CC BY-SA 3.0 (ChEMBL data is from http://www.ebi.ac.uk/chembl; the version of ChEMBL is chembl_37)",
+ "https://creativecommons.org/licenses/by-sa/3.0/")
+# The directory of release 37 (published once); the SQLite archive is 5.4 GB,
+# the database in it 30.5 GB
+upstream_prefix = 'https://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/releases/chembl_37'
+files = [("chembl_37_sqlite.tar.gz:chembl_37/chembl_37_sqlite/chembl_37.db", None, None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+# For checks only: if set, only this many activities are read
+_check_rows = None
+
+def categorical_ep(g, codes, labels, name):
+ """Store the integer codes `codes` (indices into the list of strings
+ `labels`) as the string edge property `name`."""
+ c = g.new_ep("int", vals=codes)
+ p = g.new_ep("string")
+ map_property_values(c, p, lambda i: labels[i])
+ g.ep[name] = p
+
+class Codes(dict):
+ "Integer codes of strings (None is coded as the empty string)."
+ def __call__(self, s):
+ if s is None:
+ s = ""
+ c = self.get(s)
+ if c is None:
+ c = self[s] = len(self)
+ return c
+ def labels(self):
+ return [s for s, c in sorted(self.items(), key=lambda x: x[1])]
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ name = __name__.split(".")[-1]
+ for fname, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ # SQLite needs a file: the database is extracted to a temporary file
+ os.makedirs("cache/temp", exist_ok=True)
+ with tempfile.NamedTemporaryFile(dir="cache/temp", suffix=".db") as tmp:
+ with open_upstream_file(name, fname, "rb") as f:
+ shutil.copyfileobj(f, tmp, 1 << 24)
+ tmp.flush()
+ db = sqlite3.connect(f"file:{tmp.name}?mode=ro", uri=True)
+ try:
+ yield alt, build_graph(db)
+ finally:
+ db.close()
+
+def build_graph(db):
+ mols = db.execute("SELECT molregno, chembl_id, pref_name, molecule_type, max_phase "
+ "FROM molecule_dictionary ORDER BY molregno").fetchall()
+ targets = db.execute("SELECT tid, chembl_id, pref_name, target_type, organism, tax_id "
+ "FROM target_dictionary ORDER BY tid").fetchall()
+ molregno = numpy.array([m[0] for m in mols], dtype="int64")
+ tids = numpy.array([t[0] for t in targets], dtype="int64")
+
+ q = ("SELECT a.molregno, s.tid, a.standard_type, a.standard_relation, "
+ "a.standard_value, a.standard_units, a.pchembl_value, s.assay_type, "
+ "d.year, a.data_validity_comment, a.potential_duplicate "
+ "FROM activities a JOIN assays s ON a.assay_id = s.assay_id "
+ "LEFT JOIN docs d ON a.doc_id = d.doc_id ORDER BY a.activity_id")
+ if _check_rows is not None:
+ q += f" LIMIT {int(_check_rows)}"
+ n = _check_rows or db.execute("SELECT count(*) FROM activities").fetchone()[0]
+ src = numpy.empty(n, dtype="int64")
+ tgt = numpy.empty(n, dtype="int64")
+ value = numpy.empty(n, dtype="float64")
+ pchembl = numpy.empty(n, dtype="float64")
+ year = numpy.empty(n, dtype="int16")
+ dup = numpy.empty(n, dtype="bool")
+ ctype, crel, cunits, cassay, cvalid = [numpy.empty(n, dtype="int32")
+ for i in range(5)]
+ types, rels, units, assays, valids = Codes(), Codes(), Codes(), Codes(), Codes()
+ i = 0
+ cur = db.execute(q)
+ while True:
+ rows = cur.fetchmany(1 << 18)
+ if not rows:
+ break
+ for (m, t, st, sr, sv, su, pv, at, y, dv, pd) in rows:
+ src[i] = m
+ tgt[i] = t
+ value[i] = numpy.nan if sv is None else sv
+ pchembl[i] = numpy.nan if pv is None else pv
+ year[i] = -1 if y is None else y
+ dup[i] = bool(pd)
+ ctype[i] = types(st)
+ crel[i] = rels(sr)
+ cunits[i] = units(su)
+ cassay[i] = assays(at)
+ cvalid[i] = valids(dv)
+ i += 1
+ assert i == n, (i, n)
+
+ Nm = len(mols)
+ g = Graph(directed=False)
+ g.add_vertex(Nm + len(targets))
+ s = numpy.searchsorted(molregno, src)
+ t = numpy.searchsorted(tids, tgt)
+ assert (molregno[s] == src).all() and (tids[t] == tgt).all()
+ del src, tgt
+ g.add_edge_list(numpy.column_stack([s, Nm + t]))
+ del s, t
+ categorical_ep(g, ctype, types.labels(), "standard_type")
+ categorical_ep(g, crel, rels.labels(), "standard_relation")
+ g.ep.standard_value = g.new_ep("double", vals=value)
+ categorical_ep(g, cunits, units.labels(), "standard_units")
+ g.ep.pchembl_value = g.new_ep("double", vals=pchembl)
+ categorical_ep(g, cassay, assays.labels(), "assay_type")
+ g.ep.year = g.new_ep("int16_t", vals=year)
+ categorical_ep(g, cvalid, valids.labels(), "data_validity_comment")
+ g.ep.potential_duplicate = g.new_ep("bool", vals=dup)
+ del value, pchembl, year, dup, ctype, crel, cunits, cassay, cvalid
+
+ g.vp.is_compound = g.new_vp("bool")
+ g.vp.is_compound.a[:Nm] = 1
+ g.vp.chembl_id = g.new_vp("string", vals=[m[1] for m in mols] +
+ [t[1] for t in targets])
+ g.vp.name = g.new_vp("string", vals=[m[2] or "" for m in mols] +
+ [t[2] or "" for t in targets])
+ g.vp.molecule_type = g.new_vp("string", vals=[m[3] or "" for m in mols] +
+ [""] * len(targets))
+ g.vp.max_phase = g.new_vp("double", vals=[-1 if m[4] is None else m[4] for m in mols] +
+ [-1] * len(targets))
+ g.vp.target_type = g.new_vp("string", vals=[""] * Nm +
+ [t[3] or "" for t in targets])
+ g.vp.organism = g.new_vp("string", vals=[""] * Nm +
+ [t[4] or "" for t in targets])
+ g.vp.tax_id = g.new_vp("int64_t", vals=[-1] * Nm +
+ [-1 if t[5] is None else t[5] for t in targets])
+ return g