History of human_gut_microbiome_compendium
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/human_gut_microbiome_compendium/__init__.py b/entries/human_gut_microbiome_compendium/__init__.py
index 70a8423..cec7a4a 100644
--- a/entries/human_gut_microbiome_compendium/__init__.py
+++ b/entries/human_gut_microbiome_compendium/__init__.py
@@ -52,7 +52,7 @@ tags = ['Biological', 'Ecological', 'Weighted', 'Bipartite', 'Metadata']
url = ['https://microbiomap.org/', 'https://doi.org/10.5281/zenodo.8186993']
citation = [('R. J. Abdill, S. P. Graham, V. Rubinetti, M. Ahmadian, P. Hicks, A. Chetty, D. McDonald, P. Ferretti, E. Gibbons, M. Rossi, A. Krishnan, F. W. Albert, C. S. Greene, S. Davis, R. Blekhman, "Integration of 168,000 samples reveals global patterns of the human gut microbiome." Cell 188, 1100-1118.e17 (2025)',
'https://doi.org/10.1016/j.cell.2024.12.017')]
-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/')
upstream_prefix = 'https://zenodo.org/records'
[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/human_gut_microbiome_compendium/__init__.py b/entries/human_gut_microbiome_compendium/__init__.py
index 1f232c9..70a8423 100644
--- a/entries/human_gut_microbiome_compendium/__init__.py
+++ b/entries/human_gut_microbiome_compendium/__init__.py
@@ -39,15 +39,15 @@ Nodes are samples and taxa, and an edge connects a sample to each taxon observed
The networks have the following properties:
-- `is_sample`: whether the node is a sample (otherwise it is a taxon).
-- `name`: the identifier of the sample (`<BioProject>_<SRA run>` in the genus tables, the SRA sample accession in `asv` and `gg2`), or the taxon (lineage in the genus tables, ASV identifier in `asv`, feature identifier in `gg2`).
-- `taxonomy` (`asv`, `gg2`): the lineage of the ASV or feature (empty for samples).
-- `srs`, `srr`, `project`: the SRA sample and run accessions and the BioProject of the sample.
-- `pubdate`, `total_bases`, `instrument`: the publication date of the run in the SRA (as Unix time), the number of sequenced bases, and the sequencing instrument.
-- `geo_loc_name`, `iso`, `region`: the location of the sample as given in BioSample, its country (ISO 3166-1 code, or `unknown`), and its world region.
-- `amplicon`, `bead_beating`, `kit`, `sample_type`, `condition`, `subjects`, `publication`: the metadata of the study of the sample (annotated by the authors of the compendium): the amplified region of the 16S gene, whether the DNA extraction used mechanical lysis, the extraction kit, the material, the condition studied, the population, and the link to the publication.
-- `tags`: the attributes of the sample in BioSample, as `tag=value` strings.
-- Edge `count`: the number of reads of the taxon in the sample."""
+- (Node) `is_sample`: whether the node is a sample (otherwise it is a taxon).
+- (Node) `name`: the identifier of the sample (`<BioProject>_<SRA run>` in the genus tables, the SRA sample accession in `asv` and `gg2`), or the taxon (lineage in the genus tables, ASV identifier in `asv`, feature identifier in `gg2`).
+- (Node) `taxonomy` (`asv`, `gg2`): the lineage of the ASV or feature (empty for samples).
+- (Node) `srs`, `srr`, `project`: the SRA sample and run accessions and the BioProject of the sample.
+- (Node) `pubdate`, `total_bases`, `instrument`: the publication date of the run in the SRA (as Unix time), the number of sequenced bases, and the sequencing instrument.
+- (Node) `geo_loc_name`, `iso`, `region`: the location of the sample as given in BioSample, its country (ISO 3166-1 code, or `unknown`), and its world region.
+- (Node) `amplicon`, `bead_beating`, `kit`, `sample_type`, `condition`, `subjects`, `publication`: the metadata of the study of the sample (annotated by the authors of the compendium): the amplified region of the 16S gene, whether the DNA extraction used mechanical lysis, the extraction kit, the material, the condition studied, the population, and the link to the publication.
+- (Node) `tags`: the attributes of the sample in BioSample, as `tag=value` strings.
+- (Edge) `count`: the number of reads of the taxon in the sample."""
tags = ['Biological', 'Ecological', 'Weighted', 'Bipartite', 'Metadata']
url = ['https://microbiomap.org/', 'https://doi.org/10.5281/zenodo.8186993']
citation = [('R. J. Abdill, S. P. Graham, V. Rubinetti, M. Ahmadian, P. Hicks, A. Chetty, D. McDonald, P. Ferretti, E. Gibbons, M. Rossi, A. Krishnan, F. W. Albert, C. S. Greene, S. Davis, R. Blekhman, "Integration of 168,000 samples reveals global patterns of the human gut microbiome." Cell 188, 1100-1118.e17 (2025)',
[entries] New entry: human_gut_microbiome_compendium 77ab8e5
diff --git a/entries/human_gut_microbiome_compendium/__init__.py b/entries/human_gut_microbiome_compendium/__init__.py
new file mode 100644
index 0000000..1f232c9
--- /dev/null
+++ b/entries/human_gut_microbiome_compendium/__init__.py
@@ -0,0 +1,238 @@
+#! /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 csv
+import datetime as dt
+import io
+import tarfile
+import zipfile
+from collections import defaultdict
+
+import h5py
+import pyarrow.csv as pacsv
+
+from .. import *
+
+title = "Human Microbiome Compendium of gut samples (2023-2026)"
+description = r"""Bipartite networks of human gut microbiome samples and the bacterial and archaeal taxa found in them, from the Human Microbiome Compendium of Abdill et al., which gathers 168,464 publicly available 16S rRNA gene amplicon sequencing samples of the human gut (mostly stool) from 482 studies in the Sequence Read Archive, processed with a uniform pipeline (DADA2), and classified with the SILVA reference database.
+
+Nodes are samples and taxa, and an edge connects a sample to each taxon observed in it, with the number of reads of the taxon in the sample as weight.
+
+- `v1.0.0`, `v1.0.1`, `v1.1.2`: the taxonomic tables at the genus level of the releases of the compendium, where the amplicon sequence variants (ASVs) are classified with SILVA 138.0 (`v1.0.0`, also published as versions 0.1.0 and 0.2.0), with SILVA 138.0 and corrections of the names of 2,881 ASVs whose taxonomic levels were inferred incorrectly (`v1.0.1`), and with SILVA 138.2, with all the ASVs of the compendium classified together (`v1.1.2`, the table of the releases 1.1.0 to 1.1.2). Taxa are named by their lineage down to the genus (unclassified levels are `NA`).
+- `asv` (release 1.1.2): the samples and the ASVs (exact sequence variants, shared across studies), from the per-study ASV tables, with the classification of each ASV with SILVA 138.2.
+- `gg2` (release 1.1.2): the samples and the features of the classification with Greengenes2 (2022.10, closed-reference at 99% identity), with their Greengenes2 taxonomy (the 5,018 samples of the table without any classified reads are isolated nodes).
+
+The networks have the following properties:
+
+- `is_sample`: whether the node is a sample (otherwise it is a taxon).
+- `name`: the identifier of the sample (`<BioProject>_<SRA run>` in the genus tables, the SRA sample accession in `asv` and `gg2`), or the taxon (lineage in the genus tables, ASV identifier in `asv`, feature identifier in `gg2`).
+- `taxonomy` (`asv`, `gg2`): the lineage of the ASV or feature (empty for samples).
+- `srs`, `srr`, `project`: the SRA sample and run accessions and the BioProject of the sample.
+- `pubdate`, `total_bases`, `instrument`: the publication date of the run in the SRA (as Unix time), the number of sequenced bases, and the sequencing instrument.
+- `geo_loc_name`, `iso`, `region`: the location of the sample as given in BioSample, its country (ISO 3166-1 code, or `unknown`), and its world region.
+- `amplicon`, `bead_beating`, `kit`, `sample_type`, `condition`, `subjects`, `publication`: the metadata of the study of the sample (annotated by the authors of the compendium): the amplified region of the 16S gene, whether the DNA extraction used mechanical lysis, the extraction kit, the material, the condition studied, the population, and the link to the publication.
+- `tags`: the attributes of the sample in BioSample, as `tag=value` strings.
+- Edge `count`: the number of reads of the taxon in the sample."""
+tags = ['Biological', 'Ecological', 'Weighted', 'Bipartite', 'Metadata']
+url = ['https://microbiomap.org/', 'https://doi.org/10.5281/zenodo.8186993']
+citation = [('R. J. Abdill, S. P. Graham, V. Rubinetti, M. Ahmadian, P. Hicks, A. Chetty, D. McDonald, P. Ferretti, E. Gibbons, M. Rossi, A. Krishnan, F. W. Albert, C. S. Greene, S. Davis, R. Blekhman, "Integration of 168,000 samples reveals global patterns of the human gut microbiome." Cell 188, 1100-1118.e17 (2025)',
+ 'https://doi.org/10.1016/j.cell.2024.12.017')]
+icon_hash = None
+upstream_license = ('Creative Commons Attribution 4.0 International (CC BY 4.0)',
+ 'https://creativecommons.org/licenses/by/4.0/')
+upstream_prefix = 'https://zenodo.org/records'
+REC = "22035984" # release 1.1.2
+META = (f"{REC}/files/sample_metadata.tsv", f"{REC}/files/projects.csv",
+ f"{REC}/files/tags.tsv.gz")
+files = [(("8431937/files/taxonomic_table.csv.gz",) + META, "v1.0.0", None),
+ (("10452633/files/taxonomic_table.csv.gz",) + META, "v1.0.1", None),
+ ((f"{REC}/files/taxonomic_table.csv.gz",) + META, "v1.1.2", None),
+ ((f"{REC}/files/project_asv_tables.tar.gz", f"{REC}/files/classifications.tsv") + META,
+ "asv", None),
+ ((f"{REC}/files/gg2-2022.10-cref99.biom.qza", f"{REC}/files/gg2-2022.10-cref99.tax.tsv.qza") + META,
+ "gg2", None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+_check_rows = None
+
+def to_time(x):
+ try:
+ return int(dt.datetime.strptime(x, "%Y-%m-%d %H:%M:%S").replace(
+ tzinfo=dt.timezone.utc).timestamp())
+ except ValueError:
+ return -1
+
+def read_metadata(name):
+ "Sample metadata, by SRS and by SRR."
+ with open_upstream_file(name, META[0], "r") as f:
+ samples = list(csv.DictReader(f, delimiter="\t"))
+ with open_upstream_file(name, META[1], "r", encoding="utf-8-sig") as f:
+ projects = {r["project"]: r for r in csv.DictReader(f)}
+ tags = defaultdict(list)
+ with open_upstream_file(name, META[2], "r") as f:
+ for r in csv.DictReader(f, delimiter="\t"):
+ tags[r["srs"]].append(f"{r['tag']}={r['value']}")
+ by_srs, by_srr = {}, {}
+ for r in samples:
+ p = projects.get(r["project"], {})
+ r = dict(r, amplicon=p.get("amplicon", ""), bead_beating=p.get("bead_beating", ""),
+ kit=p.get("kit", ""), sample_type=p.get("sample_type", ""),
+ condition=p.get("condition", ""), subjects=p.get("subjects", ""),
+ publication=p.get("link", ""), tags=tags.get(r["srs"], []))
+ by_srs[r["srs"]] = r
+ by_srr[r["srr"]] = r
+ return by_srs, by_srr
+
+SPROPS = ["srs", "srr", "project", "instrument", "geo_loc_name", "iso", "region",
+ "amplicon", "bead_beating", "kit", "sample_type", "condition",
+ "subjects", "publication"]
+
+def build(samples, taxa, edges, counts, meta, taxonomy=None):
+ "samples: list of (name, metadata or None); taxa: list of names."
+ ns = len(samples)
+ g = Graph(directed=False)
+ g.add_vertex(ns + len(taxa))
+ g.add_edge_list(edges)
+ g.vp.is_sample = g.new_vp("bool", vals=numpy.arange(ns + len(taxa)) < ns)
+ g.vp.name = g.new_vp("string", vals=[s for s, m in samples] + list(taxa))
+ if taxonomy is not None:
+ g.vp.taxonomy = g.new_vp("string", vals=[""] * ns + list(taxonomy))
+ nt = [""] * len(taxa)
+ for p in SPROPS:
+ g.vp[p] = g.new_vp("string", vals=[m[p] if m else "" for s, m in samples] + nt)
+ g.vp.pubdate = g.new_vp("int64_t", vals=[to_time(m["pubdate"]) if m else -1
+ for s, m in samples] + [-1] * len(taxa))
+ g.vp.total_bases = g.new_vp("int64_t", vals=[int(m["total_bases"] or -1) if m else -1
+ for s, m in samples] + [-1] * len(taxa))
+ g.vp.tags = g.new_vp("vector<string>", vals=[m["tags"] if m else []
+ for s, m in samples] + [[]] * len(taxa))
+ g.ep.count = g.new_ep("double", vals=counts)
+ return g
+
+def find_member(z, suffix):
+ ms = [n for n in z.namelist() if n.endswith(suffix)]
+ assert len(ms) == 1, (suffix, ms)
+ return ms[0]
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ name = __name__.split(".")[-1]
+ by_srs, by_srr = None, None
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ if by_srs is None:
+ by_srs, by_srr = read_metadata(name)
+ if alt.startswith("v"):
+ # wide table: samples (rows) x genera (columns)
+ with open_upstream_file(name, fnames[0], "rb") as f:
+ reader = pacsv.open_csv(f, read_options=pacsv.ReadOptions(block_size=1 << 25))
+ taxa = reader.schema.names[2:]
+ samples, src, tgt, counts = [], [], [], []
+ for b in reader:
+ names = b.column(1).to_pylist()
+ m = numpy.column_stack([b.column(i).to_numpy(zero_copy_only=False)
+ for i in range(2, b.num_columns)])
+ i, j = numpy.nonzero(m)
+ src.append(i + len(samples))
+ tgt.append(j)
+ counts.append(m[i, j])
+ for s in names:
+ samples.append((s, by_srr.get(s.split("_", 1)[1])))
+ if _check_rows is not None and len(samples) >= _check_rows:
+ break
+ ns = len(samples)
+ edges = numpy.stack([numpy.concatenate(src),
+ numpy.concatenate(tgt) + ns], axis=1)
+ g = build(samples, taxa, edges, numpy.concatenate(counts), by_srs)
+ elif alt == "asv":
+ taxonomy = {}
+ with open_upstream_file(name, fnames[1], "r") as f:
+ r = csv.reader(f, delimiter="\t")
+ next(r)
+ for row in r:
+ taxonomy[row[0]] = ";".join(x if x != "NA" else "" for x in row[1:])
+ sidx, tidx = {}, {}
+ src, tgt, counts = [], [], []
+ with open_upstream_file(name, fnames[0], "rb") as f:
+ with tarfile.open(fileobj=f, mode="r|*") as tar:
+ nproj = 0
+ for ti in tar:
+ if not ti.isfile() or not ti.name.endswith(".txt"):
+ continue
+ # (skip the macOS metadata files "._*")
+ if ti.size == 0 or ti.name.rsplit("/", 1)[-1].startswith("._"):
+ continue
+ fb = tar.extractfile(ti)
+ # dense table (ASVs x samples), read in blocks
+ reader = pacsv.open_csv(
+ fb, read_options=pacsv.ReadOptions(block_size=1 << 24),
+ parse_options=pacsv.ParseOptions(delimiter="\t"))
+ cols = reader.schema.names[1:]
+ si = numpy.array([sidx.setdefault(s, len(sidx)) for s in cols],
+ dtype="int64")
+ for b in reader:
+ asvs = b.column(0).to_pylist()
+ ai = numpy.array([tidx.setdefault(a, len(tidx)) for a in asvs],
+ dtype="int64")
+ for k in range(1, b.num_columns):
+ x = b.column(k).to_numpy(zero_copy_only=False)
+ nz = numpy.nonzero(x)[0]
+ if len(nz) == 0:
+ continue
+ src.append(numpy.full(len(nz), si[k - 1]))
+ tgt.append(ai[nz])
+ counts.append(x[nz])
+ nproj += 1
+ if _check_rows is not None and nproj >= _check_rows:
+ break
+ samples = [(s, by_srs.get(s)) for s in sidx]
+ taxa = list(tidx)
+ ns = len(samples)
+ edges = numpy.stack([numpy.concatenate(src),
+ numpy.concatenate(tgt) + ns], axis=1)
+ g = build(samples, taxa, edges, numpy.concatenate(counts), by_srs,
+ [taxonomy.get(a, "") for a in taxa])
+ else:
+ with open_upstream_file(name, fnames[1], "rb", seekable=True) as f:
+ z = zipfile.ZipFile(f)
+ with z.open(find_member(z, "data/taxonomy.tsv")) as fb:
+ r = csv.reader(io.TextIOWrapper(fb, encoding="utf8"), delimiter="\t")
+ next(r)
+ taxonomy = {row[0]: row[1] for row in r}
+ with open_upstream_file(name, fnames[0], "rb", seekable=True) as f:
+ z = zipfile.ZipFile(f)
+ with z.open(find_member(z, "data/feature-table.biom")) as fb:
+ hf = h5py.File(io.BytesIO(fb.read()), "r")
+ obs = [x.decode() for x in hf["observation/ids"][:]]
+ sids = [x.decode() for x in hf["sample/ids"][:]]
+ indptr = hf["observation/matrix/indptr"][:]
+ indices = hf["observation/matrix/indices"][:]
+ data = hf["observation/matrix/data"][:]
+ rows = numpy.repeat(numpy.arange(len(obs)), numpy.diff(indptr))
+ ns = len(sids)
+ edges = numpy.stack([indices.astype("int64"), rows + ns], axis=1)
+ samples = [(s, by_srs.get(s, by_srr.get(s))) for s in sids]
+ g = build(samples, obs, edges, data, by_srs,
+ [taxonomy.get(o, "") for o in obs])
+ yield alt, g