From bd39008716e6a723bbdce66248b9df752a967c2a Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 08:07:26 -0700 Subject: [PATCH 01/10] fix bug in issue #117 --- gemelli/preprocessing.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gemelli/preprocessing.py b/gemelli/preprocessing.py index 5e40888..2c1e89b 100755 --- a/gemelli/preprocessing.py +++ b/gemelli/preprocessing.py @@ -21,7 +21,12 @@ from inspect import getfullargspec from gemelli._defaults import DEFAULT_MTD from skbio.stats.composition import clr -from skbio.diversity._util import _vectorize_counts_and_tree +try: + # scikit-bio newer versions + from skbio.diversity._util import vectorize_counts_and_tree as _vectorize_counts_and_tree +except ImportError: + # scikit-bio older versions + from skbio.diversity._util import _vectorize_counts_and_tree from bp import parse_newick, to_skbio_treenode from scipy.sparse.linalg import svds # import QIIME2 if in a Q2env otherwise set type to str @@ -30,8 +35,6 @@ except ImportError: # python does not check but technically this is the type NewickFormat = str - - VALID_TAXONOMY_COLUMN_NAMES = ('taxon', 'taxonomy') From 41de7ea901a67bb30cff2a12f7d1898991f33751 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 08:17:33 -0700 Subject: [PATCH 02/10] fix second bug in import --- gemelli/q2/_visualizer.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gemelli/q2/_visualizer.py b/gemelli/q2/_visualizer.py index cd5eeea..0af13f2 100644 --- a/gemelli/q2/_visualizer.py +++ b/gemelli/q2/_visualizer.py @@ -9,13 +9,20 @@ from urllib.parse import quote from skbio import DistanceMatrix from gemelli.utils import qc_rarefaction as _qc_rarefaction -import pkg_resources import seaborn as sns import itertools import matplotlib.pyplot as plt - -TEMPLATES = pkg_resources.resource_filename('gemelli', 'q2') - +# fix old and new dependency chnages +try: + from importlib.resources import files + TEMPLATES = files("gemelli").joinpath("q2") +except ImportError: + try: + from importlib_resources import files + TEMPLATES = files("gemelli").joinpath("q2") + except ImportError: + import pkg_resources + TEMPLATES = pkg_resources.resource_filename("gemelli", "q2") def qc_rarefy(output_dir: str, table: biom.Table, From 07b723b14bcb80e92640267e954f8c4e21b99424 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 08:23:39 -0700 Subject: [PATCH 03/10] fix flake8 --- gemelli/preprocessing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gemelli/preprocessing.py b/gemelli/preprocessing.py index 2c1e89b..65438e0 100755 --- a/gemelli/preprocessing.py +++ b/gemelli/preprocessing.py @@ -23,7 +23,9 @@ from skbio.stats.composition import clr try: # scikit-bio newer versions - from skbio.diversity._util import vectorize_counts_and_tree as _vectorize_counts_and_tree + from skbio.diversity._util import ( + vectorize_counts_and_tree as _vectorize_counts_and_tree, + ) except ImportError: # scikit-bio older versions from skbio.diversity._util import _vectorize_counts_and_tree From 18d5e307a9daf4e3ea0e6ecfe0c510cf17271885 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 08:25:02 -0700 Subject: [PATCH 04/10] fix numpy product to prod change --- gemelli/factorization.py | 2 +- gemelli/preprocessing.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gemelli/factorization.py b/gemelli/factorization.py index 7d830e6..fdfedcc 100644 --- a/gemelli/factorization.py +++ b/gemelli/factorization.py @@ -183,7 +183,7 @@ def _fit(self): raise ValueError('Input data is should be type numpy.ndarray') # ensure the data contains missing values. # other methods would be better in the case of fully dense data - n_entries = np.product(tensor.shape) + n_entries = np.prod(tensor.shape) if self.check_dense: if (np.count_nonzero(tensor) == n_entries and np.count_nonzero(~np.isnan(tensor)) == n_entries): diff --git a/gemelli/preprocessing.py b/gemelli/preprocessing.py index 65438e0..f2e86c5 100755 --- a/gemelli/preprocessing.py +++ b/gemelli/preprocessing.py @@ -369,7 +369,7 @@ def tensor_rclr(T, branch_lengths=None): + [1] + conditions_index[:-1]) # transpose to flatten T = T.transpose(forward_T) - M = T.reshape(np.product(T.shape[:len(T.shape) - 1]), + M = T.reshape(np.prod(T.shape[:len(T.shape) - 1]), T.shape[-1]) with np.errstate(divide='ignore', invalid='ignore'): M_tensor_rclr = matrix_rclr(M, branch_lengths=branch_lengths) From 27bfdc7646af7bc35ef54e343420372fbf8246b8 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 08:43:17 -0700 Subject: [PATCH 05/10] updated numpy use, also back compatiable --- gemelli/tempted.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gemelli/tempted.py b/gemelli/tempted.py index e031806..78bde9f 100644 --- a/gemelli/tempted.py +++ b/gemelli/tempted.py @@ -780,8 +780,9 @@ def tempted_helper(individual_id_tables, individual_loadings.iloc[:, s] = a_hat feature_loadings.iloc[:, s] = b_hat state_loadings.iloc[:, s] = phi_hat.flatten() - lambda_coeff[s] = lambda_coeff_ - rsquared[s] = 1 - resid / (y.size * y.var()) + lambda_coeff[s] = np.asarray(lambda_coeff_).squeeze().item() + rsquared_ = 1 - resid / (y.size * y.var()) + rsquared[s] = np.asarray(rsquared_).squeeze() # update data for i, (individual_id, m) in enumerate(tables_update.items()): temp = tipos[i] From a7336bc7a38463a83c096d95a56eb3b9b0d299da Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 10:11:12 -0700 Subject: [PATCH 06/10] updated skbio ordination container fix back-compatible --- gemelli/rpca.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/gemelli/rpca.py b/gemelli/rpca.py index 9ba84cd..94cae80 100644 --- a/gemelli/rpca.py +++ b/gemelli/rpca.py @@ -931,10 +931,18 @@ def transform(ordination: OrdinationResults, ' the features in the ordination.' ' Either set subset_tables to True or' ' match the tables to the ordination.') - ordination.samples = transform_helper(Udf, - Vdf, - s_eig, - rclr_table_df) + projected_samples = transform_helper(Udf, + Vdf, + s_eig, + rclr_table_df) + ordination.samples = projected_samples + # In skbio >= 0.7, sample_ids is stored as a separate attribute at + # construction and is not re-derived when .samples is reassigned, so it + # must be updated explicitly to match the projected samples. Older skbio + # versions derive the ids from the .samples index and have no such + # attribute, so this is skipped there (back-compatible). + if hasattr(ordination, 'sample_ids'): + ordination.sample_ids = list(projected_samples.index) return ordination From 63fcef82a2ff2882565aff4a63e53b4f21194d6b Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 10:55:47 -0700 Subject: [PATCH 07/10] update changelog and version --- CHANGELOG.md | 7 +++++++ gemelli/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3ff3f..43df8e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +v0.0.13 (2026-03-02) + +### Bug fixes + +* Update dependency updates + * See issue #117 + * All back-compatible v0.0.12 (2024-10-01) diff --git a/gemelli/__init__.py b/gemelli/__init__.py index 6ad9f5a..9e0d8f2 100644 --- a/gemelli/__init__.py +++ b/gemelli/__init__.py @@ -6,4 +6,4 @@ # The full license is in the file COPYING.txt, distributed with this software. # ---------------------------------------------------------------------------- -__version__ = "0.0.12" +__version__ = "0.0.13" From 71e8794e73c8aaba1f55264fefdb9945a8aac4c8 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Thu, 2 Jul 2026 11:08:40 -0700 Subject: [PATCH 08/10] fix flaky test --- gemelli/q2/tests/test_rpca_method.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gemelli/q2/tests/test_rpca_method.py b/gemelli/q2/tests/test_rpca_method.py index 0c16664..afee26b 100644 --- a/gemelli/q2/tests/test_rpca_method.py +++ b/gemelli/q2/tests/test_rpca_method.py @@ -83,6 +83,11 @@ def create_pos_cntrl_test_table(feature_prefix='', class Testqc(unittest.TestCase): def setUp(self): + # The positive/negative control tables are built with Subsample(), + # which draws from the global numpy RNG. Seed it so the controls are + # deterministic and the significance checks below are reproducible on + # CI (otherwise a borderline random draw can flip the p-value). + np.random.seed(0) btneg, btpos = create_pos_cntrl_test_table() self.btneg = Artifact.import_data("FeatureTable[Frequency]", btneg) From d37cd8726fe6fa056a2f40e75fd16d482214fdfe Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Mon, 6 Jul 2026 08:57:46 -0700 Subject: [PATCH 09/10] add matplotlib and seaborn to install_requires The q2 visualizer (gemelli/q2/_visualizer.py) imports seaborn and matplotlib at plugin-registration time, but neither was declared in setup.py install_requires (only in ci/conda_requirements.txt). A plain pip install therefore missed them, causing ModuleNotFoundError: No module named 'seaborn' during the QIIME 2 cache refresh. Left unpinned to match existing style and avoid over-constraining the solver. Co-Authored-By: Claude Opus 4.8 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index ffbd921..f7c7c72 100755 --- a/setup.py +++ b/setup.py @@ -110,6 +110,8 @@ def run(self): 'biom-format', 'h5py', 'iow', + 'matplotlib', + 'seaborn', 'tax2tree'], classifiers=classifiers, entry_points={'qiime2.plugins': q2cmds, From c2e4b199b17061e0df242880bf537c9aeec50460 Mon Sep 17 00:00:00 2001 From: cameronmartino Date: Mon, 13 Jul 2026 15:10:48 -0700 Subject: [PATCH 10/10] update readme --- README.md | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 902ae93..042f044 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,6 @@ Martino, C. and Shenhav, L. et al. Context-aware dimensionality reduction deconv } ``` - ## Citation for RPCA ``` @@ -108,7 +107,6 @@ Martino, C. et al. A Novel Sparse Compositional Technique Reveals Microbial Pert } ``` - ## Citation for Phylogenetic RPCA ``` @@ -137,20 +135,40 @@ Martino, C. et al. A Novel Sparse Compositional Technique Reveals Microbial Pert ## Citation for TEMPTED ``` -Shi, p. et al. Time-Informed Dimensionality Reduction for Longitudinal Microbiome Studies. bioRxiv, (2023) +Shi, p. et al. TEMPTED: time-informed dimensionality reduction for longitudinal microbiome studies. Genome Biology, (2024) ``` ``` -@ARTICLE{Shi2023, +@ARTICLE{Shi2024, author = {Shi, Pixu and Martino, Cameron and Han, Rungang and Janssen, Stefan and Buck, Gregory and Serrano, Myrna and Owzar, Kouros and Knight, Rob and Shenhav, Liat and Zhang, Anru R}, - title = {{Time-Informed} Dimensionality Reduction for Longitudinal - Microbiome Studies}, - year = {2023}, - doi = {10.1101/2023.07.26.550749}, - URL = {https://www.biorxiv.org/content/10.1101/2023.07.26.550749v1}, - journal = {bioRxiv}, + title = {TEMPTED: time-informed dimensionality reduction for longitudinal microbiome studies}, + year = {2024}, + doi = {10.1186/s13059-024-03453-x}, + URL = {https://link.springer.com/article/10.1186/s13059-024-03453-x}, + journal = {Genome Biology}, +} +``` + +## Citation for Joint-RPCA + +``` +Cordazzo Vargas, b. et al. Joint-RPCA: Domain-Aware Multi-Omics Integration for Systems Microbiology. Molecular Systems Biology, (2026) +``` + +``` +@ARTICLE{CordazzoVargas2026, + author = {Cordazzo Vargas, Bianca and Martino, Cameron and Dilmore, Amanda Hazel and Metcalf, + Jessica and Burcham, Zachary and Lahti, Leo and Bektanov, Aituar and Borman, Tuomas and + Salomaa, Veikko and Niiranen, Teemu and Havulinna, Aki and Gregor, Rachel and Eyal, Stav + and Meijler, Michael and Mizrahi, Itzhak and Song, Se and Bartko, Andrew and Dorrestein, Pieter + and Morton, James and McDonald, Daniel and Knight, Rob and Shenhav, Liat}, + title = {Joint-RPCA: Domain-Aware Multi-Omics Integration for Systems Microbiology}, + year = {2026}, + doi = {}, + URL = {}, + journal = {Molecular Systems Biology}, } ```