History of open_targets_associations
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/open_targets_associations/__init__.py b/entries/open_targets_associations/__init__.py
index a783d34..121ac8f 100644
--- a/entries/open_targets_associations/__init__.py
+++ b/entries/open_targets_associations/__init__.py
@@ -87,7 +87,7 @@ tags = ['Biological', 'Weighted', 'Bipartite', 'Metadata']
url = ['https://platform.opentargets.org/', 'https://ftp.ebi.ac.uk/pub/databases/opentargets/platform/']
citation = [('A. Buniello, D. Suveges, C. Cruz-Castillo, M. B. Llinares, H. Cornu, I. Lopez, K. Tsukanov, J. M. Roldán-Romero, C. Mehta, L. Fumis, et al., "Open Targets Platform: facilitating therapeutic hypotheses building in drug discovery." Nucleic Acids Research 53, D1467-D1475 (2025)',
'https://doi.org/10.1093/nar/gkae1128')]
-icon_hash = None
+date_added = '2026-10-31'
upstream_license = ('Creative Commons CC0 1.0 Universal (CC0 1.0)',
'https://creativecommons.org/publicdomain/zero/1.0/')
upstream_prefix = 'https://ftp.ebi.ac.uk/pub/databases/opentargets/platform'
[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/open_targets_associations/__init__.py b/entries/open_targets_associations/__init__.py
index 82401fc..a783d34 100644
--- a/entries/open_targets_associations/__init__.py
+++ b/entries/open_targets_associations/__init__.py
@@ -73,16 +73,16 @@ The scores by data source (finer than the data types), the yearly scores of rele
The networks have the following properties:
-- `is_target`: whether the node is a target (otherwise it is a disease).
-- `ot_id`: the identifier of the target (Ensembl gene, e.g. `ENSG00000141510`) or disease (e.g. `EFO_0000311`, `MONDO_0007254`).
-- `name`: the approved symbol of the gene, or the name of the disease.
-- `full_name` (targets): the approved name of the gene.
-- `biotype`, `chromosome` (targets): the biotype of the gene (e.g. `protein_coding`) and its chromosome.
-- `therapeutic_areas` (diseases): the therapeutic areas of the disease (their identifiers).
-- Edge `score`: the overall association score.
-- Edge `evidence_count`: the number of pieces of evidence of the association.
-- Edge `score_<datatype>` (direct associations): the association score from the evidence of each data type (`genetic_association`, `somatic_mutation`, `known_drug`, `affected_pathway`, `rna_expression`, `animal_model`, `literature`, and the types of the release; NaN if there is no evidence of the type).
-- Edge `novelty`, `first_year` (`2026`, `indirect_2026`): the current novelty of the association (a measure of how recent its evidence is), and the first year in which its score was positive (`-1` if unknown, e.g. for evidence without a date)."""
+- (Node) `is_target`: whether the node is a target (otherwise it is a disease).
+- (Node) `ot_id`: the identifier of the target (Ensembl gene, e.g. `ENSG00000141510`) or disease (e.g. `EFO_0000311`, `MONDO_0007254`).
+- (Node) `name`: the approved symbol of the gene, or the name of the disease.
+- (Node) `full_name` (targets): the approved name of the gene.
+- (Node) `biotype`, `chromosome` (targets): the biotype of the gene (e.g. `protein_coding`) and its chromosome.
+- (Node) `therapeutic_areas` (diseases): the therapeutic areas of the disease (their identifiers).
+- (Edge) `score`: the overall association score.
+- (Edge) `evidence_count`: the number of pieces of evidence of the association.
+- (Edge) `score_<datatype>` (direct associations): the association score from the evidence of each data type (`genetic_association`, `somatic_mutation`, `known_drug`, `affected_pathway`, `rna_expression`, `animal_model`, `literature`, and the types of the release; NaN if there is no evidence of the type).
+- (Edge) `novelty`, `first_year` (`2026`, `indirect_2026`): the current novelty of the association (a measure of how recent its evidence is), and the first year in which its score was positive (`-1` if unknown, e.g. for evidence without a date)."""
tags = ['Biological', 'Weighted', 'Bipartite', 'Metadata']
url = ['https://platform.opentargets.org/', 'https://ftp.ebi.ac.uk/pub/databases/opentargets/platform/']
citation = [('A. Buniello, D. Suveges, C. Cruz-Castillo, M. B. Llinares, H. Cornu, I. Lopez, K. Tsukanov, J. M. Roldán-Romero, C. Mehta, L. Fumis, et al., "Open Targets Platform: facilitating therapeutic hypotheses building in drug discovery." Nucleic Acids Research 53, D1467-D1475 (2025)',
[entries] New entry: open_targets_associations 54bfa5b
diff --git a/entries/open_targets_associations/__init__.py b/entries/open_targets_associations/__init__.py
new file mode 100644
index 0000000..82401fc
--- /dev/null
+++ b/entries/open_targets_associations/__init__.py
@@ -0,0 +1,218 @@
+#! /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 pyarrow as pa
+import pyarrow.compute as pc
+import pyarrow.parquet as pq
+
+from .. import *
+
+# Parquet tables of the releases of September of each year (the files of a
+# table are named part-<n>-<uuid>-c000.<codec>.parquet, n = 0, ..., count-1)
+TABLES = {
+ ("2021", "direct"): ("21.09/output/etl/parquet/associationByOverallDirect", "7a31e018-0f22-47da-b7b4-0b3dce43b838", 200, "snappy"),
+ ("2021", "datatype"): ("21.09/output/etl/parquet/associationByDatatypeDirect", "88d97dfe-336d-4036-95ae-6591939e51e4", 200, "snappy"),
+ ("2021", "disease"): ("21.09/output/etl/parquet/diseases", "23e37190-c97c-4458-afcd-adff63715d00", 16, "snappy"),
+ ("2021", "target"): ("21.09/output/etl/parquet/targets", "4fad51a0-1fbf-48ec-9a0f-67620d20a68b", 200, "snappy"),
+ ("2022", "direct"): ("22.09/output/etl/parquet/associationByOverallDirect", "4480aa60-455c-4f7a-abb8-ec51b970e479", 200, "snappy"),
+ ("2022", "datatype"): ("22.09/output/etl/parquet/associationByDatatypeDirect", "7efc886a-818b-45ed-be1e-8943d3c5b8d8", 200, "snappy"),
+ ("2022", "disease"): ("22.09/output/etl/parquet/diseases", "9d8cd6ea-1877-4420-81d4-58350c9f3fa2", 200, "snappy"),
+ ("2022", "target"): ("22.09/output/etl/parquet/targets", "54ecf72b-b4c6-476e-9826-7a044486f7d1", 200, "snappy"),
+ ("2023", "direct"): ("23.09/output/etl/parquet/associationByOverallDirect", "f96bc7c3-79fa-4d2a-8c16-5dfe4f3b853d", 200, "snappy"),
+ ("2023", "datatype"): ("23.09/output/etl/parquet/associationByDatatypeDirect", "64c06cff-7009-4f47-b9c9-27c2c8ce65aa", 200, "snappy"),
+ ("2023", "disease"): ("23.09/output/etl/parquet/diseases", "e2a1713c-e8cb-4d40-96c5-ce4884c5a968", 200, "snappy"),
+ ("2023", "target"): ("23.09/output/etl/parquet/targets", "5b7beb9c-a75e-4593-906f-a05ffdbcac3d", 200, "snappy"),
+ ("2024", "direct"): ("24.09/output/etl/parquet/associationByOverallDirect", "295fcb7d-1489-45d2-b62a-221584d49fe9", 200, "snappy"),
+ ("2024", "datatype"): ("24.09/output/etl/parquet/associationByDatatypeDirect", "0844d963-a0aa-44df-83e5-a58c12248c2e", 200, "snappy"),
+ ("2024", "disease"): ("24.09/output/etl/parquet/diseases", "2ff72ead-930e-42aa-a51d-ba726a0d3e02", 200, "snappy"),
+ ("2024", "target"): ("24.09/output/etl/parquet/targets", "b2a23987-7e43-4651-a89c-1eb34ec9f9f5", 200, "snappy"),
+ ("2025", "direct"): ("25.09/output/association_overall_direct", "115d4937-47d3-4de3-a70b-eb4fc9f78010", 20, "snappy"),
+ ("2025", "datatype"): ("25.09/output/association_by_datatype_direct", "615fa756-f0e4-4e2b-b1aa-40d0f0202228", 20, "snappy"),
+ ("2025", "disease"): ("25.09/output/disease", "disease.parquet", None, None),
+ ("2025", "target"): ("25.09/output/target", "016eadfd-f300-4e8f-a9fe-ec4ce8b8bdc6", 10, "snappy"),
+ ("2026", "direct"): ("26.09/output/association_overall_direct", "a3ed3cdf-4640-405e-af76-16c0f0fba85a", 14, "zstd"),
+ ("2026", "datatype"): ("26.09/output/association_by_datatype_direct", "3d8673e2-3337-48a5-97f4-a27c4a57b281", 15, "zstd"),
+ ("2026", "indirect"): ("26.09/output/association_overall_indirect", "3674162f-e2e6-4aaa-bc45-86ea584c3d56", 39, "zstd"),
+ ("2026", "disease"): ("26.09/output/disease", "00000000.parquet", None, None),
+ ("2026", "target"): ("26.09/output/target", "ddfc1f8c-60a1-40fe-885a-2c1dd3f9a9c1", 3, "zstd"),
+}
+
+def table_files(year, kind):
+ path, uuid, count, codec = TABLES[(year, kind)]
+ if count is None:
+ return [f"{path}/{uuid}"]
+ return [f"{path}/part-{i:05d}-{uuid}-c000.{codec}.parquet" for i in range(count)]
+
+NETWORKS = {f"{y}": (y, "direct") for y in ["2021", "2022", "2023", "2024", "2025", "2026"]}
+NETWORKS["indirect_2026"] = ("2026", "indirect")
+
+title = "Open Targets target-disease associations (2021-2026)"
+description = r"""Bipartite networks of genes (drug targets) and diseases or phenotypes, from the Open Targets Platform, which integrates the evidence that a gene is involved in a disease from many sources (genetic associations, somatic mutations, known drugs, affected pathways, gene expression, animal models, and text mining of the literature) into association scores between 0 and 1, to help the selection of drug targets.
+
+Nodes are targets (Ensembl genes) and diseases (terms of the Experimental Factor Ontology, EFO, and of the ontologies it imports, such as MONDO, HP, Orphanet and GO), and an edge connects a target and a disease that have an association, with its overall score, and its scores by type of evidence (data type).
+
+- `2021` ... `2026`: the direct associations (from evidence for the disease itself) of the releases of September of each year (21.09 to 26.09).
+- `indirect_2026`: the indirect associations of release 26.09, where the evidence for a disease is also propagated to all its ancestors in the ontology (only the overall score).
+
+The scores by data source (finer than the data types), the yearly scores of release 26.09 (except the first year with a positive score), and the indirect associations of the earlier releases are left out.
+
+The networks have the following properties:
+
+- `is_target`: whether the node is a target (otherwise it is a disease).
+- `ot_id`: the identifier of the target (Ensembl gene, e.g. `ENSG00000141510`) or disease (e.g. `EFO_0000311`, `MONDO_0007254`).
+- `name`: the approved symbol of the gene, or the name of the disease.
+- `full_name` (targets): the approved name of the gene.
+- `biotype`, `chromosome` (targets): the biotype of the gene (e.g. `protein_coding`) and its chromosome.
+- `therapeutic_areas` (diseases): the therapeutic areas of the disease (their identifiers).
+- Edge `score`: the overall association score.
+- Edge `evidence_count`: the number of pieces of evidence of the association.
+- Edge `score_<datatype>` (direct associations): the association score from the evidence of each data type (`genetic_association`, `somatic_mutation`, `known_drug`, `affected_pathway`, `rna_expression`, `animal_model`, `literature`, and the types of the release; NaN if there is no evidence of the type).
+- Edge `novelty`, `first_year` (`2026`, `indirect_2026`): the current novelty of the association (a measure of how recent its evidence is), and the first year in which its score was positive (`-1` if unknown, e.g. for evidence without a date)."""
+tags = ['Biological', 'Weighted', 'Bipartite', 'Metadata']
+url = ['https://platform.opentargets.org/', 'https://ftp.ebi.ac.uk/pub/databases/opentargets/platform/']
+citation = [('A. Buniello, D. Suveges, C. Cruz-Castillo, M. B. Llinares, H. Cornu, I. Lopez, K. Tsukanov, J. M. Roldán-Romero, C. Mehta, L. Fumis, et al., "Open Targets Platform: facilitating therapeutic hypotheses building in drug discovery." Nucleic Acids Research 53, D1467-D1475 (2025)',
+ 'https://doi.org/10.1093/nar/gkae1128')]
+icon_hash = None
+upstream_license = ('Creative Commons CC0 1.0 Universal (CC0 1.0)',
+ 'https://creativecommons.org/publicdomain/zero/1.0/')
+upstream_prefix = 'https://ftp.ebi.ac.uk/pub/databases/opentargets/platform'
+files = [(tuple(f for k in (kind, "datatype", "disease", "target")
+ if (year, k) in TABLES and not (k == "datatype" and kind == "indirect")
+ for f in table_files(year, k)), alt, None)
+ for alt, (year, kind) in NETWORKS.items()]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+def read(name, year, kind, columns=None):
+ tables = []
+ for f in table_files(year, kind):
+ with open_upstream_file(name, f, "rb", seekable=True) as fp:
+ pf = pq.ParquetFile(fp)
+ cols = None if columns is None else \
+ [c for c in columns if c in pf.schema_arrow.names]
+ tables.append(pf.read(columns=cols))
+ return pa.concat_tables(tables, promote_options="default")
+
+def whole(x):
+ "A pyarrow array from a chunked array (or the array itself)."
+ return x.combine_chunks() if isinstance(x, pa.ChunkedArray) else x
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ name = __name__.split(".")[-1]
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ year, kind = NETWORKS[alt]
+ a = read(name, year, kind, ["diseaseId", "targetId", "score", "associationScore",
+ "evidenceCount", "currentNovelty"])
+ if "associationScore" in a.column_names:
+ a = a.rename_columns(["score" if c == "associationScore" else c
+ for c in a.column_names])
+ tids = whole(pc.unique(a["targetId"]))
+ dids = whole(pc.unique(a["diseaseId"]))
+ nt = len(tids)
+ src = pc.index_in(a["targetId"], value_set=tids).to_numpy()
+ tgt = pc.index_in(a["diseaseId"], value_set=dids).to_numpy() + nt
+ g = Graph(directed=False)
+ g.add_vertex(nt + len(dids))
+ g.add_edge_list(numpy.stack([src, tgt], axis=1).astype("int64"))
+ g.ep.score = g.new_ep("double", vals=a["score"].to_numpy())
+ g.ep.evidence_count = g.new_ep("int64_t", vals=a["evidenceCount"].to_numpy())
+ if "currentNovelty" in a.column_names:
+ g.ep.novelty = g.new_ep("double", vals=a["currentNovelty"].fill_null(float("nan")).to_numpy())
+ # first year with a positive score, from the yearly scores
+ # (read file by file, in the same order as the rows)
+ first = []
+ for f in table_files(year, kind):
+ with open_upstream_file(name, f, "rb", seekable=True) as fp:
+ ts = whole(pq.ParquetFile(fp).read(columns=["timeseries"])["timeseries"])
+ flat = pc.list_flatten(ts)
+ parent = pc.list_parent_indices(ts).to_numpy()
+ years = flat.field("year").fill_null(-1).to_numpy(zero_copy_only=False)
+ scores = flat.field("associationScore").to_numpy(zero_copy_only=False)
+ sel = (years >= 0) & (scores > 0)
+ fy = numpy.full(len(ts), numpy.iinfo("int64").max)
+ numpy.minimum.at(fy, parent[sel], years[sel])
+ fy[fy == numpy.iinfo("int64").max] = -1
+ first.append(fy)
+ del ts, flat, parent, years, scores, sel
+ first = numpy.concatenate(first)
+ assert len(first) == len(a)
+ g.ep.first_year = g.new_ep("int32_t", vals=first)
+ del first
+ if kind == "direct":
+ # scores by data type, aligned to the edges by (target, disease)
+ d = read(name, year, "datatype", ["diseaseId", "targetId", "datatypeId",
+ "aggregationValue", "score",
+ "associationScore"])
+ if "aggregationValue" in d.column_names:
+ d = d.rename_columns([{"associationScore": "score",
+ "aggregationValue": "datatypeId"}.get(c, c)
+ for c in d.column_names])
+ key = numpy.asarray(src, dtype="int64") * len(dids) + (tgt - nt)
+ order = numpy.argsort(key)
+ ds = pc.index_in(d["targetId"], value_set=tids).to_numpy(zero_copy_only=False)
+ dd = pc.index_in(d["diseaseId"], value_set=dids).to_numpy(zero_copy_only=False)
+ dkey = ds.astype("int64") * len(dids) + dd.astype("int64")
+ pos = numpy.searchsorted(key[order], dkey)
+ pos = numpy.minimum(pos, len(key) - 1)
+ found = key[order][pos] == dkey
+ eidx = order[pos]
+ dtypes = d["datatypeId"].to_numpy(zero_copy_only=False)
+ dscore = d["score"].to_numpy()
+ for t in sorted(set(dtypes)):
+ x = numpy.full(len(key), numpy.nan)
+ m = found & (dtypes == t)
+ x[eidx[m]] = dscore[m]
+ g.ep[f"score_{t}"] = g.new_ep("double", vals=x)
+ del d, key, order, ds, dd, dkey, pos, found, eidx, dtypes, dscore
+ del a, src, tgt
+
+ tg = read(name, year, "target", ["id", "approvedSymbol", "approvedName",
+ "biotype", "genomicLocation"])
+ tinfo = {r["id"]: r for r in tg.to_pylist()}
+ di = read(name, year, "disease", ["id", "name", "therapeuticAreas"])
+ dinfo = {r["id"]: r for r in di.to_pylist()}
+ tl = tids.to_pylist()
+ dl = dids.to_pylist()
+ g.vp.is_target = g.new_vp("bool", vals=[True] * nt + [False] * len(dl))
+ g.vp.ot_id = g.new_vp("string", vals=tl + dl)
+ def tget(t, k):
+ r = tinfo.get(t)
+ if r is None:
+ return ""
+ if k == "chromosome":
+ return (r.get("genomicLocation") or {}).get("chromosome") or ""
+ return r.get(k) or ""
+ g.vp.name = g.new_vp("string", vals=[tget(t, "approvedSymbol") for t in tl] +
+ [(dinfo.get(x) or {}).get("name") or "" for x in dl])
+ g.vp.full_name = g.new_vp("string", vals=[tget(t, "approvedName") for t in tl] +
+ [""] * len(dl))
+ g.vp.biotype = g.new_vp("string", vals=[tget(t, "biotype") for t in tl] +
+ [""] * len(dl))
+ g.vp.chromosome = g.new_vp("string", vals=[tget(t, "chromosome") for t in tl] +
+ [""] * len(dl))
+ g.vp.therapeutic_areas = g.new_vp(
+ "vector<string>", vals=[[]] * nt +
+ [list((dinfo.get(x) or {}).get("therapeuticAreas") or []) for x in dl])
+ yield alt, g