logo Netzschleuder network catalog, repository, and centrifuge

History of rhea_reactions

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 by Tiago de Paula Peixoto 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/rhea_reactions/__init__.py b/entries/rhea_reactions/__init__.py
index b2a1185..8e342ed 100644
--- a/entries/rhea_reactions/__init__.py
+++ b/entries/rhea_reactions/__init__.py
@@ -47,7 +47,7 @@ tags = ['Biological', 'Metabolic', 'Chemical', 'Unweighted', 'Bipartite', 'Metad
 url = ['https://www.rhea-db.org/', 'https://ftp.expasy.org/databases/rhea/']
 citation = [('P. Bansal, A. Morgat, K. B. Axelsen, V. Muthukrishnan, E. Coudert, L. Aimo, N. Hyka-Nouspikel, E. Gasteiger, A. Kerhornou, T. B. Neto, M. Pozzato, M.-C. Blatter, A. Ignatchenko, N. Redaschi, A. Bridge, "Rhea, the reaction knowledgebase in 2022." Nucleic Acids Research 50, D693-D700 (2022)',
              'https://doi.org/10.1093/nar/gkab1016')]
-icon_hash = None
+date_added = '2026-10-31'
 upstream_license = ('Creative Commons Attribution 4.0 International (CC BY 4.0)',
                     'https://creativecommons.org/licenses/by/4.0/')
 # The archived copy of release 142 (the files of the main directory are
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) by Tiago de Paula Peixoto 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/rhea_reactions/__init__.py b/entries/rhea_reactions/__init__.py
index e238257..b2a1185 100644
--- a/entries/rhea_reactions/__init__.py
+++ b/entries/rhea_reactions/__init__.py
@@ -30,19 +30,19 @@ description = r"""Bipartite networks of biochemical reactions and the compounds
 
 The networks have the following properties:
 
-- `rhea_id` (reactions): the accession of the master reaction (e.g. `RHEA:10000`), or of the compound: `CHEBI:...` for small molecules, `GENERIC:...` for generic compounds, `POLYMER:...` for polymers.
-- `is_reaction`: whether the node is a reaction (otherwise it is a compound).
-- `name`: the equation of the reaction, with the names of the compounds (e.g. `pentanamide + H2O = pentanoate + NH4(+)`), or the name of the compound.
-- `status`: the curation status of the reaction (`Approved` or `Preliminary`; empty for compounds).
-- `is_transport`, `is_balanced`: whether the reaction is a transport reaction, and whether it is chemically balanced.
-- `ec`: the EC numbers of the enzymes that catalyze the reaction.
-- `directional_ids`: the accessions of the left-to-right, right-to-left and bidirectional versions of the reaction.
-- `citations`: the PubMed identifiers of the articles that support the reaction.
-- `compound_class` (reactions): the kind of compound: `SmallMolecule`, `GenericPolypeptide`, `GenericPolynucleotide`, `GenericHeteropolysaccharide`, `GenericSmallMolecule`, `GenericCompound` or `Polymer` (empty for reactions).
-- `formula`, `charge`: the chemical formula and charge of the compound (empty if not given; for polymers they are given per repeating unit, e.g. `(-4)(-1)n`, as in Rhea).
-- `chebi_ids`: the ChEBI identifiers of the compound: itself for small molecules, the reactive parts for generic compounds, the underlying ChEBI entity for polymers.
-- Edge `coefficient` (reactions): the stoichiometric coefficient of the compound (e.g. `1`, `2`, `N`, `2n`, `N+1`).
-- Edge `location` (reactions): the side of the membrane of the compound in a transport reaction (`in` or `out`; empty otherwise)."""
+- (Node) `rhea_id` (reactions): the accession of the master reaction (e.g. `RHEA:10000`), or of the compound: `CHEBI:...` for small molecules, `GENERIC:...` for generic compounds, `POLYMER:...` for polymers.
+- (Node) `is_reaction`: whether the node is a reaction (otherwise it is a compound).
+- (Node) `name`: the equation of the reaction, with the names of the compounds (e.g. `pentanamide + H2O = pentanoate + NH4(+)`), or the name of the compound.
+- (Node) `status`: the curation status of the reaction (`Approved` or `Preliminary`; empty for compounds).
+- (Node) `is_transport`, `is_balanced`: whether the reaction is a transport reaction, and whether it is chemically balanced.
+- (Node) `ec`: the EC numbers of the enzymes that catalyze the reaction.
+- (Node) `directional_ids`: the accessions of the left-to-right, right-to-left and bidirectional versions of the reaction.
+- (Node) `citations`: the PubMed identifiers of the articles that support the reaction.
+- (Node) `compound_class` (reactions): the kind of compound: `SmallMolecule`, `GenericPolypeptide`, `GenericPolynucleotide`, `GenericHeteropolysaccharide`, `GenericSmallMolecule`, `GenericCompound` or `Polymer` (empty for reactions).
+- (Node) `formula`, `charge`: the chemical formula and charge of the compound (empty if not given; for polymers they are given per repeating unit, e.g. `(-4)(-1)n`, as in Rhea).
+- (Node) `chebi_ids`: the ChEBI identifiers of the compound: itself for small molecules, the reactive parts for generic compounds, the underlying ChEBI entity for polymers.
+- (Edge) `coefficient` (reactions): the stoichiometric coefficient of the compound (e.g. `1`, `2`, `N`, `2n`, `N+1`).
+- (Edge) `location` (reactions): the side of the membrane of the compound in a transport reaction (`in` or `out`; empty otherwise)."""
 tags = ['Biological', 'Metabolic', 'Chemical', 'Unweighted', 'Bipartite', 'Metadata']
 url = ['https://www.rhea-db.org/', 'https://ftp.expasy.org/databases/rhea/']
 citation = [('P. Bansal, A. Morgat, K. B. Axelsen, V. Muthukrishnan, E. Coudert, L. Aimo, N. Hyka-Nouspikel, E. Gasteiger, A. Kerhornou, T. B. Neto, M. Pozzato, M.-C. Blatter, A. Ignatchenko, N. Redaschi, A. Bridge, "Rhea, the reaction knowledgebase in 2022." Nucleic Acids Research 50, D693-D700 (2022)',
[entries] New entry: rhea_reactions by Tiago de Paula Peixoto ace5dc5
diff --git a/entries/rhea_reactions/__init__.py b/entries/rhea_reactions/__init__.py
new file mode 100644
index 0000000..e238257
--- /dev/null
+++ b/entries/rhea_reactions/__init__.py
@@ -0,0 +1,214 @@
+#! /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 gzip
+import xml.etree.ElementTree as ET
+from collections import defaultdict
+
+from .. import *
+
+title = "Rhea biochemical reactions (2026)"
+description = r"""Bipartite networks of biochemical reactions and the compounds that take part in them, from Rhea, the expert-curated knowledgebase of chemical and transport reactions of biological interest of the SIB Swiss Institute of Bioinformatics, which is the reference vocabulary for the enzymatic reactions annotated in UniProtKB. The data are those of release 142 (September 2, 2026).
+
+- `reactions`: the reactions and their participants. Each reaction of Rhea is described by a reaction with an undefined direction ("master" reaction, written with `=`), and by its two directional (left-to-right and right-to-left) and its bidirectional versions; only the master reactions are nodes here, and the directional ones are given as properties. An edge goes from each compound of the left side of the equation, as written by Rhea, to the reaction, and from the reaction to each compound of its right side, with the stoichiometric coefficient of the compound and, for transport reactions, the side of the membrane (`in` or `out`); since the direction of a master reaction is undefined, the direction of the edges is only that of the written equation. A compound that is transported appears on both sides of a reaction. The compounds are small molecules of the ChEBI ontology, generic compounds (e.g. `[protein]-dithiol`, described by their reactive parts) and polymers. Obsolete reactions have no participants, and are left out.
+- `hierarchy`: the classification of the reactions, where an edge goes from a reaction to a more general reaction of which it is an instance (relation `is_a`), e.g. the reaction of a specific alcohol to the reaction of "a primary alcohol". The nodes are the master reactions that take part in it; Rhea also lists the same relations between the corresponding directional reactions, which are left out.
+
+The networks have the following properties:
+
+- `rhea_id` (reactions): the accession of the master reaction (e.g. `RHEA:10000`), or of the compound: `CHEBI:...` for small molecules, `GENERIC:...` for generic compounds, `POLYMER:...` for polymers.
+- `is_reaction`: whether the node is a reaction (otherwise it is a compound).
+- `name`: the equation of the reaction, with the names of the compounds (e.g. `pentanamide + H2O = pentanoate + NH4(+)`), or the name of the compound.
+- `status`: the curation status of the reaction (`Approved` or `Preliminary`; empty for compounds).
+- `is_transport`, `is_balanced`: whether the reaction is a transport reaction, and whether it is chemically balanced.
+- `ec`: the EC numbers of the enzymes that catalyze the reaction.
+- `directional_ids`: the accessions of the left-to-right, right-to-left and bidirectional versions of the reaction.
+- `citations`: the PubMed identifiers of the articles that support the reaction.
+- `compound_class` (reactions): the kind of compound: `SmallMolecule`, `GenericPolypeptide`, `GenericPolynucleotide`, `GenericHeteropolysaccharide`, `GenericSmallMolecule`, `GenericCompound` or `Polymer` (empty for reactions).
+- `formula`, `charge`: the chemical formula and charge of the compound (empty if not given; for polymers they are given per repeating unit, e.g. `(-4)(-1)n`, as in Rhea).
+- `chebi_ids`: the ChEBI identifiers of the compound: itself for small molecules, the reactive parts for generic compounds, the underlying ChEBI entity for polymers.
+- Edge `coefficient` (reactions): the stoichiometric coefficient of the compound (e.g. `1`, `2`, `N`, `2n`, `N+1`).
+- Edge `location` (reactions): the side of the membrane of the compound in a transport reaction (`in` or `out`; empty otherwise)."""
+tags = ['Biological', 'Metabolic', 'Chemical', 'Unweighted', 'Bipartite', 'Metadata']
+url = ['https://www.rhea-db.org/', 'https://ftp.expasy.org/databases/rhea/']
+citation = [('P. Bansal, A. Morgat, K. B. Axelsen, V. Muthukrishnan, E. Coudert, L. Aimo, N. Hyka-Nouspikel, E. Gasteiger, A. Kerhornou, T. B. Neto, M. Pozzato, M.-C. Blatter, A. Ignatchenko, N. Redaschi, A. Bridge, "Rhea, the reaction knowledgebase in 2022." Nucleic Acids Research 50, D693-D700 (2022)',
+             'https://doi.org/10.1093/nar/gkab1016')]
+icon_hash = None
+upstream_license = ('Creative Commons Attribution 4.0 International (CC BY 4.0)',
+                    'https://creativecommons.org/licenses/by/4.0/')
+# The archived copy of release 142 (the files of the main directory are
+# replaced at every release)
+upstream_prefix = 'https://ftp.expasy.org/databases/rhea/old_releases'
+ARCHIVE = "142.tar.bz2"
+RDF = f"{ARCHIVE}:142/rdf/rhea.rdf.gz"
+RELATIONSHIPS = f"{ARCHIVE}:142/tsv/rhea-relationships.tsv"
+files = [((RDF,), "reactions", None),
+         ((RDF, RELATIONSHIPS), "hierarchy", None)]
+
+def fetch_upstream(force=False):
+    return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+                                force)
+
+RH = "http://rdf.rhea-db.org/"
+RDFNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+RDFS = "http://www.w3.org/2000/01/rdf-schema#"
+
+def read_rdf(name):
+    """The descriptions of the RDF file, as a dictionary of the subjects
+    (without the Rhea prefix) to lists of (predicate, value) pairs, where
+    the value is the resource (without the Rhea prefix) or the text."""
+    desc = defaultdict(list)
+    with open_upstream_file(name, RDF, "rb") as fz:
+        with gzip.open(fz, "rb") as f:
+            for ev, el in ET.iterparse(f, events=("end",)):
+                if el.tag != f"{{{RDFNS}}}Description":
+                    continue
+                about = el.get(f"{{{RDFNS}}}about").removeprefix(RH)
+                d = desc[about]
+                for c in el:
+                    res = c.get(f"{{{RDFNS}}}resource")
+                    d.append((c.tag, res.removeprefix(RH) if res is not None
+                              else c.text))
+                el.clear()
+    return desc
+
+def values(d, tag):
+    return [v for t, v in d if t == tag]
+
+def value(d, tag, default=""):
+    vs = values(d, tag)
+    return vs[0] if vs else default
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+    name = __name__.split(".")[-1]
+    desc = read_rdf(name)
+
+    # coefficients of the "contains<n>" predicates
+    coef = {}
+    for about, d in desc.items():
+        if about.startswith("contains") and about != "contains":
+            c = value(d, f"{{{RH}}}coefficient", None)
+            if c is not None:
+                coef[f"{{{RH}}}{about}"] = c
+    classes = {"SmallMolecule", "GenericPolypeptide", "GenericPolynucleotide",
+               "GenericHeteropolysaccharide", "GenericSmallMolecule",
+               "GenericCompound", "Polymer"}
+
+    # master reactions: those with sides
+    masters = sorted((a for a, d in desc.items()
+                      if a.isdigit() and values(d, f"{{{RH}}}side")),
+                     key=int)
+    master_set = set(masters)
+
+    vidx = {}
+    vprops = defaultdict(list)
+    def add_vertex(key, **props):
+        v = vidx.get(key)
+        if v is None:
+            v = vidx[key] = len(vidx)
+            for k, x in props.items():
+                vprops[k].append(x)
+        return v
+
+    def add_reaction(a):
+        d = desc[a]
+        dirs = values(d, f"{{{RH}}}directionalReaction") + \
+            values(d, f"{{{RH}}}bidirectionalReaction")
+        return add_vertex(
+            a, rhea_id=value(d, f"{{{RH}}}accession"), is_reaction=True,
+            name=value(d, f"{{{RH}}}equation"),
+            status=value(d, f"{{{RH}}}status"),
+            is_transport=value(d, f"{{{RH}}}isTransport") == "true",
+            is_balanced=value(d, f"{{{RH}}}isChemicallyBalanced") == "true",
+            ec=[e.split("/")[-1] for e in values(d, f"{{{RH}}}ec")],
+            directional_ids=[f"RHEA:{x}" for x in dirs],
+            citations=[c.split("/")[-1] for c in values(d, f"{{{RH}}}citation")],
+            compound_class="", formula="", charge="", chebi_ids=[])
+
+    def chebi(x):
+        return x.split("/")[-1].replace("_", ":")
+
+    def add_compound(c):
+        d = desc[c]
+        sup = [s for s in values(d, f"{{{RDFS}}}subClassOf") if s in classes]
+        assert len(sup) == 1, (c, sup)
+        if sup[0] == "SmallMolecule":
+            ids = [chebi(x) for x in values(d, f"{{{RH}}}chebi")]
+        elif sup[0] == "Polymer":
+            ids = [chebi(x) for x in values(d, f"{{{RH}}}underlyingChebi")]
+        else:
+            ids = [chebi(value(desc[rp], f"{{{RH}}}chebi"))
+                   for rp in values(d, f"{{{RH}}}reactivePart")]
+        return add_vertex(
+            c, rhea_id=value(d, f"{{{RH}}}accession"), is_reaction=False,
+            name=value(d, f"{{{RH}}}name"), status="", is_transport=False,
+            is_balanced=False, ec=[], directional_ids=[], citations=[],
+            compound_class=sup[0], formula=value(d, f"{{{RH}}}formula"),
+            charge=value(d, f"{{{RH}}}charge"), chebi_ids=ids)
+
+    for alt in ["reactions", "hierarchy"]:
+        if alts is not None and alt not in alts:
+            continue
+        vidx.clear()
+        vprops.clear()
+        edges, ecoef, eloc = [], [], []
+        if alt == "reactions":
+            for a in masters:
+                r = add_reaction(a)
+                for s in values(desc[a], f"{{{RH}}}side"):
+                    left = s.endswith("_L")
+                    assert left or s.endswith("_R"), s
+                    for t, p in desc[s]:
+                        if t not in coef:
+                            continue
+                        pd = desc[p]
+                        c = add_compound(value(pd, f"{{{RH}}}compound"))
+                        edges.append((c, r) if left else (r, c))
+                        ecoef.append(coef[t])
+                        eloc.append(value(pd, f"{{{RH}}}location").lower())
+        else:
+            with open_upstream_file(name, RELATIONSHIPS, "r") as f:
+                header = next(f).rstrip("\n").split("\t")
+                assert header == ["FROM_REACTION_ID", "TYPE", "TO_REACTION_ID"], header
+                for l in f:
+                    s, t, u = l.rstrip("\n").split("\t")
+                    assert t == "is_a", l
+                    if s not in master_set or u not in master_set:
+                        continue
+                    edges.append((add_reaction(s), add_reaction(u)))
+
+        g = Graph(directed=True)
+        g.add_vertex(len(vidx))
+        g.add_edge_list(numpy.array(edges, dtype="int64").reshape(-1, 2))
+        ptypes = dict(rhea_id="string", is_reaction="bool", name="string",
+                      status="string", is_transport="bool",
+                      is_balanced="bool", ec="vector<string>",
+                      directional_ids="vector<string>",
+                      citations="vector<string>", compound_class="string",
+                      formula="string", charge="string", chebi_ids="vector<string>")
+        for k, t in ptypes.items():
+            if alt == "hierarchy" and k in ("is_reaction", "compound_class",
+                                            "formula", "charge", "chebi_ids"):
+                continue
+            g.vp[k] = g.new_vp(t, vals=vprops[k])
+        if alt == "reactions":
+            g.ep.coefficient = g.new_ep("string", vals=ecoef)
+            g.ep.location = g.new_ep("string", vals=eloc)
+        yield alt, g