From c4671c9a490b56f4e90b4bdee3daa2842d878ce9 Mon Sep 17 00:00:00 2001 From: Jayaram Kancherla Date: Mon, 5 Jan 2026 10:18:21 -0800 Subject: [PATCH 1/3] coerce rse/se to sce --- CHANGELOG.md | 3 +- .../SingleCellExperiment.py | 81 +++++++++++++++++++ tests/test_sce_methods.py | 44 +++++++++- 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee56ac6..edb1c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Changelog -## Version 0.6.0 +## Version 0.6.0 - 0.6.1 - Changed related to SummarizedExperiment and implementation of `CompressedGenomicRangesList` in the genomic ranges package. - Update versions of relevant dependency packages. +- Implement coercions to/from RSE/SE. ## Version 0.5.8 - 0.5.9 diff --git a/src/singlecellexperiment/SingleCellExperiment.py b/src/singlecellexperiment/SingleCellExperiment.py index 7beac65..e35330a 100644 --- a/src/singlecellexperiment/SingleCellExperiment.py +++ b/src/singlecellexperiment/SingleCellExperiment.py @@ -6,6 +6,7 @@ import biocframe import biocutils as ut +from summarizedexperiment import SummarizedExperiment from summarizedexperiment._combineutils import ( check_assays_are_equal, merge_assays, @@ -1277,6 +1278,86 @@ def combine_columns(self, *other) -> SingleCellExperiment: """Wrapper around :py:func:`~combine_columns`.""" return combine_columns(self, *other) + ####################### + ######>> to rse <<##### + ####################### + + def to_rangedsummarizedexperiment(self) -> RangedSummarizedExperiment: + """Coerce to :py:class:`~summarizedexperiment.RangedSummarizedExperiment.RangedSummarizedExperiment`. + + Returns: + A ``RangedSummarizedExperiment`` object. + """ + return RangedSummarizedExperiment( + assays=self._assays, + row_ranges=self._row_ranges, + row_data=self._rows, + column_data=self._cols, + row_names=self._row_names, + column_names=self._column_names, + metadata=self._metadata, + _validate=False, + ) + + def to_rse(self) -> RangedSummarizedExperiment: + """Alias for :py:meth:`~to_rangedsummarizedexperiment`.""" + return self.to_rangedsummarizedexperiment() + + @classmethod + def from_rangedsummarizedexperiment(cls, rse: RangedSummarizedExperiment) -> SingleCellExperiment: + """Coerce from :py:class:`~summarizedexperiment.RangedSummarizedExperiment.RangedSummarizedExperiment`. + + Args: + rse: + A ``RangedSummarizedExperiment`` object. + + Returns: + A ``SingleCellExperiment`` object. + """ + return cls( + assays=rse.assays, + row_ranges=rse.row_ranges, + row_data=rse.row_data, + column_data=rse.col_data, + row_names=rse.row_names, + column_names=rse.column_names, + metadata=rse.metadata, + ) + + @classmethod + def from_rse(cls, rse: RangedSummarizedExperiment) -> SingleCellExperiment: + """Alias for :py:meth:`~from_rangedsummarizedexperiment`.""" + return cls.from_rangedsummarizedexperiment(rse) + + ######################## + ######>> from se <<##### + ######################## + + @classmethod + def from_summarizedexperiment(cls, se: SummarizedExperiment) -> SingleCellExperiment: + """Coerce from :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment`. + + Args: + se: + A ``SummarizedExperiment`` object. + + Returns: + A ``SingleCellExperiment`` object. + """ + return cls( + assays=se.assays, + row_data=se.row_data, + column_data=se.col_data, + row_names=se.row_names, + column_names=se.column_names, + metadata=se.metadata, + ) + + @classmethod + def from_se(cls, se: SummarizedExperiment) -> SingleCellExperiment: + """Alias for :py:meth:`~from_summarizedexperiment`.""" + return cls.from_summarizedexperiment(se) + ############################ ######>> combine ops <<##### diff --git a/tests/test_sce_methods.py b/tests/test_sce_methods.py index 71384d8..e6385f2 100644 --- a/tests/test_sce_methods.py +++ b/tests/test_sce_methods.py @@ -5,7 +5,7 @@ import numpy as np import pandas as pd import pytest -from summarizedexperiment import SummarizedExperiment +from summarizedexperiment import SummarizedExperiment, RangedSummarizedExperiment from singlecellexperiment import SingleCellExperiment from singlecellexperiment.SingleCellExperiment import SingleCellExperiment as sce @@ -90,3 +90,45 @@ def test_SCE_props(): assert tse.reduced_dim_names is not None assert len(tse.reduced_dim_names) == 1 + +def test_SCE_to_RSE(): + tse = SingleCellExperiment( + assays={"counts": counts}, row_data=row_data, column_data=col_data, row_ranges=gr + ) + + rse = tse.to_rangedsummarizedexperiment() + assert isinstance(rse, RangedSummarizedExperiment) + assert not isinstance(rse, SingleCellExperiment) + assert rse.shape == tse.shape + assert rse.row_ranges is not None + +def test_RSE_to_SCE(): + rse = RangedSummarizedExperiment( + assays={"counts": counts}, row_data=row_data, column_data=col_data, row_ranges=gr + ) + + tse = SingleCellExperiment.from_rangedsummarizedexperiment(rse) + assert isinstance(tse, SingleCellExperiment) + assert tse.shape == rse.shape + assert tse.row_ranges is not None + +def test_SCE_to_SE(): + tse = SingleCellExperiment( + assays={"counts": counts}, row_data=row_data, column_data=col_data, row_ranges=gr + ) + + se = tse.to_summarizedexperiment() + assert isinstance(se, SummarizedExperiment) + assert not isinstance(se, SingleCellExperiment) + assert se.shape == tse.shape + assert se.row_data is not None + assert "seqnames" in se.row_data.column_names + +def test_SE_to_SCE(): + se = SummarizedExperiment( + assays={"counts": counts}, row_data=row_data, column_data=col_data + ) + + tse = SingleCellExperiment.from_summarizedexperiment(se) + assert isinstance(tse, SingleCellExperiment) + assert tse.shape == se.shape \ No newline at end of file From 619384e6ae8012a20332f9df250a01d9b15a0979 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:18:55 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_sce_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_sce_methods.py b/tests/test_sce_methods.py index e6385f2..2581742 100644 --- a/tests/test_sce_methods.py +++ b/tests/test_sce_methods.py @@ -131,4 +131,4 @@ def test_SE_to_SCE(): tse = SingleCellExperiment.from_summarizedexperiment(se) assert isinstance(tse, SingleCellExperiment) - assert tse.shape == se.shape \ No newline at end of file + assert tse.shape == se.shape From 12a515356dd663461d79c15b52269ebb946e3b12 Mon Sep 17 00:00:00 2001 From: Jayaram Kancherla Date: Mon, 5 Jan 2026 10:25:41 -0800 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edb1c37..73b6fb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Changelog -## Version 0.6.0 - 0.6.1 +## Version 0.6.0 - 0.6.2 - Changed related to SummarizedExperiment and implementation of `CompressedGenomicRangesList` in the genomic ranges package. - Update versions of relevant dependency packages. +- Rename `reduced_dims` to `reduced_dimensions`. - Implement coercions to/from RSE/SE. ## Version 0.5.8 - 0.5.9